一直在使用Spring提供的IoC容器, 但是始终没有系统化的梳理一下. 今天在这里写下, 也是以备以后参考之用.
Ioc container的核心是BeanFactory
接口, 它提供的方法能够管理任何类型的对象. ApplicationContext
是它的子接口, 集成了Spring AOP的特性.
BeanFactory or ApplicationContext?
BeanFactory目前只是Spring为了维持向后兼容性而保留的接口, 任何新开发的框架或者程序应该使用
ApplicationContext
而不是BeanFactory
.
那么ApplicationContext
相比BeanFactory
提供了哪些好处呢? 简单的来说就是很多增强的功能, 更细粒度的干预bean生命周期的定制, AOP, 国际化, 事件支持等, 详见下表:
所有的bean在使用前都需要在ApplicationContext
注册(register), 常用的有以下几种形式:
- xml形式定义的;
- 注解定义;
- Java Config
- 手动注册在Spring容器之外实例化的bean;
Dependency Injection的实现方式
一共有三种方法: 构造器注入, 设值注入和方法注入. 构造器注入在设值注入之前.
- 构造器注入: 注入强制性的依赖.
- 设值注入: 注入可选依赖或配置(例如
@ConfigurationProperties
); 当设置注入加入了@Required
标识, 就会变成一个强制性依赖. - 方法注入: 通常是在bean构造后对bean进行增强设置.
Constructor-based
构造器注入是推荐的方式, 能够实现一个immutable的bean, 确保所有的依赖不是
null
. 并能够保证调用者使用时, 依赖是实例化完成的.
无需提供getter/setter方法.
setter-based
设值注入应被仅用于注入可选依赖, 或者是能够被赋予默认值的依赖.
使用设值注入的好处是, 能够在之后通过setter
方法进行注入的变更, 在JMX MBeans管理上必须使用此种方式.
方法注入
下面是一个例子:
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired // 自动注入--方法注入参数auth, 对已创建的AuthenticationManagerBuilder类型的bean进行增强.
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("admin").roles("USER");
}
}
依赖解析步骤
如果bean是单例的, 并且被标注为pre-instantiated(默认就是这个)会在容器创建的时候被创建. 否则的话会按需创建.
lazy-initialized beans
通常来讲单例bean会在容器创建的时候初始化, 并且会按照依赖关系顺次进行初始化, 但是你也可以通过指定
lazy-init=true
到某个bean
上使其在第一次使用的时候才被初始化.
注意: 即使某个bean开启了lazy-init, 也不一定是延迟初始化的, 因为如果依赖它的bean是单例的, 且没有开启延迟初始化, 那么Spring容器为了保证准确性, 会将这个bean也立即初始化.
Bean作用域(Bean Scopes)
bean一共有七种作用域:
作用域 | 描述 |
---|---|
singleton | 默认, 单例, 通常用于无状态bean, 如dao. service, controller等 |
prototype | 原型, 每次调用产生一个新的实例, 通常用在domain object上. 相当于java的new 关键字, Spring在实例化bean之后, 执行完initialization lifecycle callback, 之后就不在负责这个bean的生命周期了, 完全交给客户端负责 |
request | HTTP 请求范围 |
session | HTTP Session范围 |
application | 和ServletContext 的生命周期一致, 也就是web应用的范围 |
websocket | 和一个WebSocket 的生命周期一致 |
request, session, application, websocket作用域
这些作用域需要线程与Http Request或者Http Sesson对象绑定. 当使用Spring MVC时, 自动绑定.
使用以下注解在bean上显式指定:
- @RequestScope
- @SessionScope
- @ApplicationScope
application scope
是ServletContext
级别的, 作为一个ServletContext
的attribute存取, 这个范围非常像singleton范围, 但是有以下两点主要区别:
- 它是与
ServletContext
绑定, 不是与ApplicatinContext
绑定. 一个ServletContext
可以有多个ApplicationContext
. 也就是说, application scope的bean是与ApplicationContext
平行的, 二者都是ServletContext
的一个属性. - 它是
ServletContext
的一个属性.
代理
一般有两种类型:
- interface-based proxy, 典型的是JDK内置的动态代理
- 一种是inherated-based proxy, 典型的是CGLIB
interface-based proxy
优点是不需要引入额外的库依赖, 缺点是想要代理的方法必须是在被代理类实现的接口中定义的.
inherated-based proxy
缺点是需要引入额外依赖, 优点是可以代理所有的共有类型方法.
Bean生命周期(lifecycle)
- initialization callback 使用
@PostConstruct
- de