一、lazy-Init 延迟加载(懒加载)
- ApplicationContext 容器的默认行为是在启动服务器时将所有 singleton bean 提前进行实例化,提前实例化意味着作为初始化过程的⼀部分,ApplicationContext 实例会创建并配置所有的 singleton bean,比如:
<!--lazy-init="false",立即加载,表示在 Spring 启动时,立刻进行实例化--> <bean id="testBean" class="com.wujun.LazyBean" /> <!-- 该bean默认的设置为: --> <bean id="testBean" calss="com.wujun.LazyBean" lazy-init="false" />
- 如果不想让⼀个 singleton bean 在 ApplicationContext 实现初始化时被提前实例化,那么可以将bean 设置为延迟实例化
<bean id="testBean" calss="com.wujun.LazyBean" lazy-init="true" />
设置 lazy-init 为 true 的 bean 将不会在 ApplicationContext 启动时提前被实例化,而是第⼀次向容器通过 getBean 索取 bean 时实例化 - 如果⼀个设置了立即加载的 bean1,引用了⼀个延迟加载的 bean2 ,那么 bean1 在容器启动时被实例化,而 bean2 由于被 bean1 引用,所以也被实例化,这种情况也符合延时加载的 bean 在第⼀次调用时才被实例化的规则
- 也可以在容器层次中通过在 元素上使用 "default-lazy-init" 属性来控制延时初始化,如下面配置:
<beans default-lazy-init="true"> <!-- no beans will be eagerly pre-instantiated... --> </beans>
- 如果⼀个 bean 的 scope 属性为
scope="pototype"
时,即使设置了lazy-init="false"
,容器启动时也不会实例化 bean,而是调用 getBean 方法实例化的 - 在类上使用注解
@Lazy
也可以开启延迟加载,默认值为 true,也就是说加了注解的类默认就是要开启延迟加载的类 - 应用场景:
- 开启延迟加载⼀定程度提高容器启动和运转性能(当服务器内存差点意思的时候,可以使用延迟加载来优化,因为不是所有对象都要立即使用的)
- 对于不常使用的 Bean 设置延迟加载,这样偶尔使用的时候再加载,不必要从⼀开始该 Bean 就占用资源
二、FactoryBean 和 BeanFactory
- BeanFactory 接口是容器的顶级接口,定义了容器的⼀些基础行为,负责生产和管理 Bean 的⼀个工厂,通常使用它下面的子接口类型,比如 ApplicationContext
- Spring 中 Bean 有两种,⼀种是普通Bean,⼀种是工厂Bean(FactoryBean),FactoryBean 可以生成某⼀个类型的 Bean 实例(返回给我们),也就是说我们可以借助于它自定义 Bean 的创建过程
- FactoryBean 使用较多,尤其在 Spring 框架⼀些组件中会使用,还有其他框架和Spring 框架整合时使用
// 可以让我们⾃定义Bean的创建过程(完成复杂 Bean 的定义) public interface FactoryBean<T> { // 返回 FactoryBean 创建的Bean实例, // 如果 isSingleton 返回 true,则该实例会放到Spring容器的单例对象缓存池中Map @Nullable T getObject() throws Exception; // 返回 FactoryBean 创建的 Bean 类型 @Nullable Class<?> getObjectType(); // 返回作用域是否单例 default boolean isSingleton() { return true; } }
三、后置处理器
-
概念
Spring 提供了两种后处理 bean 的扩展接口,分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使用上是有所区别的- 在 BeanFactory 初始化之后可以使用 BeanFactoryPostProcessor 进行后置处理做⼀些事情
- 在 Bean 对象实例化(并不是 Bean 的整个生命周期完成)之后可以使用 BeanPostProcessor 进行后置处理做⼀些事情,注意:对象不⼀定是 SpringBean,而 SpringBean ⼀定是个对象
-
SpringBean 的生命周期
- 根据配置情况调用 Bean 构造方法或工厂方法实例化 Bean
- 利用依赖注入完成 Bean 中所有属性值的配置注入
- 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的
setBeanName()
方法传入当前 Bean 的 id 值 - 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用
setBeanFactory()
方法传入当前工厂实例的引用 - 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用
setApplicationContext()
方法传入当前 ApplicationContext 实例的引用 - 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的预初始化方法
postProcessBeforeInitialzation()
对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的 - 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用
afterPropertiesSet()
方法 - 如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法(如果使用 @PostConstruct 代替的话,@PostConstruct 所标注的方法执行顺序是在第6条之后,第7条之前的)
- 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法
postProcessAfterInitialization()
,此时,Bean 已经可以被应用系统使用了 - 如果在 <bean> 中指定了该 Bean 的作用范围为 scope="singleton",则将该 Bean 放入 Spring IOC 的缓存池中,将触发 Spring 对该 Bean 的生命周期管理;如果在 <bean> 中指定了该 Bean 的作用范围为 scope="prototype",则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean
- 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用
destory()
方法将 Spring 中的 Bean 销毁,如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁 -
注意:Spring 为 Bean 提供了细致全面的生命周期过程,通过实现特定的接口或 <bean> 的属性设置,都可以对 Bean 的生命周期过程产生影响,虽然可以随意配置 <bean> 的属性,但是建议不要过多地使用 Bean 实现接口,因为这样会导致代码和 Spring 的聚合过于紧密
网友评论