《Spring 揭秘》读书笔记
豆瓣评分:9.1 分。书是 2009 年出版的,使用的 Spring 版本应该是 2.5,比较老了,不过思想一流。
IoC 章节
装修新房,需要用家具,我们要么 new
,多数情况下还是我们自己去家具厂将家具买回来,有一个共同点就是我们都是自己主动去获取依赖的对象!IoC 的理念,让别人为你服务!
如何暗示对方你需要什么样的适当的服务?构造方法注入:构造方法中声明依赖对象的参数列表;Setter
注入:更为宽松随意;接口注入:自己需要实现某个接口来进行暗示,已经不流行了。
IoC Service Provider 的职责:业务对象的构建管理、业务对象间的依赖绑定。如何管理对象间的依赖关系:直接编码、XML 配置文件等方式来记录对象间的关系。
Spring 的 Ioc 容器类型:BeanFactory
和 ApplicationContext
,其中 ApplicationContext
更为高级,比如事件发布、国际化信息支持等。BeanFactory
像是一个汽车生产厂,其他零件厂商送入零件放入这个汽车工厂,只需要从终点获得成品汽车 Object getBean(String name)
就可以了,我们需要交给它一份生产图纸 (XML 配置文件)。
BeanFactory
只是一个接口,好比我们跟图书馆打交道,书本实际上是放置在书架 BeanDefinitionRegistry
上的,每一本书都有一个 BeanDefinition
与之相对应。
虽然 lazy-init-bean
是延迟初始化的,但是因为依赖它的 not-lazy-init-bean
并不是延迟初始化的,所以还是会被提前初始化。所以需要保证依赖于该 bean 定义的其他 bean 定义也同样设置为延迟初始化:<beans default-lazy-init="true">
。
prototype
生命周期,当对象实例返回给请求方之后,就任由这个对象自生自灭了,需要请求方自己负责这个对象的后续生命周期的管理工作。
FactoryBean
是 Spring 容器提供的一种可以扩展容器对象实例化逻辑的接口,其主语是 Bean
,它是生产对象 getObject()
的工厂。某些对象的实例化逻辑过于繁琐,或者第三方库不能直接注册到 Spring 容器的时候,就可以实现 FactoryBean
接口,给出自己的对象实例化逻辑代码。
Spring 的 Ioc 容器启动的流程分为:容器启动阶段(装配生产线:依赖 BeanDefinitionReader
解析,编组为 BeanDefinition
,最后将其注册到 BeanDefinitionRegistry
中)和 Bean
实例化阶段(getBean
方法:装配好的生产线生产具体的产品)。
Bean
的实例化过程:
ApplicationContext
间接继承了 ResourceLoader
,提供统一的资源加载策略。继承了 MessageSource
统一了国际化信息的访问方式。Spring 的 ApplicationContext
容器内部允许以 ApplicationEvent
的形式发布事件,容器内注册的 ApplicationListener
类型的 bean 定义会被 ApplicationContext
容器自动识别,它们负责监听容器内发布的所有
ApplicationEvent
类型的事件。也就是说,一旦容器内发布 ApplicationEvent
及其子类型的事件,注册到容器的 ApplicationListener
就会对这些事件进行处理。
AOP 章节
AOP 世界的公民:Joinpoint
表示程序执行的时机。Pointcut
表示 Joinpot
的表述方式。Advise
是单一横切关注点逻辑的载体。各种 Advise
执行时机:
Java 动态代理实现 InvocationHandler
的 invoke
方法即可,不过其只能对实现了相应接口的类使用。如果某个类没有实现任何接口,那么其会使用 CGLIB 开源动态字节码类库,为目标对象生成动态的代理对象实例。其原理是对目标对象进行继承扩展,生成子类,通过覆写来扩展父类的行为。其唯一限制就是无法对 final
方法进行覆写。
同一 Joinpot
的多个 Advisor
,按照顺序号来依次执行,顺序号越小,优先级越高。小于 0
的原则上是 Spring AOP 内部使用。
execution
的格式如下:
execution(修饰符? 返回类型 declaring-type-pattern? 方法名(方法参数) 抛出异常的模式?)
方法的返回类型、方法名以及参数部分的匹配模式必须指定。
*
可以用于任何部分的匹配模式,..
可以在declaring-type-pattern
和参数匹配模式的位置使用。
// 只能指定 cn.spring21 这一层下的所有类型
execution(void cn.spring21.*.doSomething(*))
// .. 指定多个层次
// 匹配 cn.spring21 包下的所有类型
// 以及 cn.spring21 下层包下声明的所有类型
execution(void cn.spring21..*.doSomething(*))
// 0 到多个参数
execution(void *.doSomething(..))
// 第一个参数String,第二个参数类型不限
execution(void doSomething(String,*))
// 前面几个参数类型不限制,但是最后一个必须是String
execution(void doSomething(..,String))
within
只接受类型声明:
// 匹配 MockTarget 类的所有方法声明
within(cn.spring21.aop.target.MockTarget)
// 匹配 cn.spring21.aop.target 包下所有类型的内部的方法级别的 Joinpoint
within(cn.spring21.aop.target.*)
// 匹配 cn.spring21.aop.target 包下以及子包所有类型的内部的方法级别的 Joinpoint
within(cn.spring21.aop..*)
args
捕捉拥有指定参数类型、参数数量的方法级 Joinpot:
// 匹配 Foo 类的 login(User user) {} 方法
// 也匹配 Bar 类的 isLogin(User user) {} 方法
args(cn.spring21.abc.domain.User)
args
方法是在运行期间动态检查参数的类型,即时目标方法是 login(Object user)
,只要传入的是 User
类型,那么依然可以捕捉到。
@annotation
检测所有含有某个注解的方法。
AOP 应用案例:异常处理、安全检查、缓存。