延迟加载

Lazy-init 延迟加载,Bean 的延迟加载。 ApplicationContext 容器的默认行为是在启动服务器时所有 Singleton Bean 提前进行实例化。

配置方式

<!-- bean 的默认配置 -->
<bean id="wzkTestBean" class="wzk.WzkTestBean" lazy-init="false" />
  • false 表示立即加载,在 Spring 启动时立刻进行实例初始化
  • true 表示延迟加载,第一次调用时才初始化

如果设置了一个立即加载的 bean1,引用了一个延迟加载的 bean2,那么 bean1 在容器启动时会初始化,此时 bean2 也会被实例化出来。

也可以使用 default-lazy-init 属性控制全局延时初始化:

<beans default-lazy-init="true">
    <!-- no beans will be eagerly pre-instantiated... -->
</beans>

当 bean 的 scope 为 prototype 时,即使设置 lazy-init=false,容器启动时也不会立刻初始化,而是调用 getBean 方法时才实例化。

应用场景

  • 开启延迟加载可以提高容器启动时的性能和运转性能
  • 对于不经常使用的 Bean,偶尔加载时再实例化,节约资源

FactoryBean 和 BeanFactory

基础介绍

BeanFactory 接口是容器的顶级接口,定义了容器的基础行为,负责生产和管理 Bean 的工厂。具体使用它的子接口类型,如 ApplicationContext。

FactoryBean 是 Spring 中一种特殊的 Bean,可以生成某一个类型的对象实例,借助它可以自定义 Bean 的创建过程。Spring 中有两种 Bean:

  • 普通 Bean
  • 工厂 Bean(FactoryBean)

FactoryBean 与静态工厂方法和实例化工厂方法的作用类似,但在 Spring 框架和一些第三方框架整合时使用较多。

FactoryBean 接口方法

public interface FactoryBean<T> {
    T getObject() throws Exception;          // 获取实例化对象
    Class<?> getObjectType();                // 返回对象类型
    boolean isSingleton();                   // 是否单例
}

代码示例

WzkCompany 实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class WzkCompany {
    private String name;
    private String address;
    private String money;
}

WzkCompanyFactoryBean 实现类

public class WzkCompanyFactoryBean implements FactoryBean<WzkCompany> {
    private String wzkCompanyInfo;

    public void setWzkCompanyInfo(String wzkCompanyInfo) {
        this.wzkCompanyInfo = wzkCompanyInfo;
    }

    @Override
    public WzkCompany getObject() throws Exception {
        WzkCompany wzkCompany = new WzkCompany();
        String[] strs = wzkCompanyInfo.split(",");
        wzkCompany.setName(strs[0]);
        wzkCompany.setAddress(strs[1]);
        wzkCompany.setMoney(strs[2]);
        return wzkCompany;
    }

    @Override
    public Class<?> getObjectType() {
        return WzkCompany.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}

XML 配置

<bean id="wzkCompanyBean" class="wzk.factory.WzkCompanyFactoryBean">
    <property name="companyInfo" value="公司名字,公司地址,1000"></property>
</bean>

测试运行

// 获取 FactoryBean 创建的对象
Object wzkCompany = applicationContext.getBean("wzkCompanyBean");
// 输出:WzkCompany(name=公司名字, address=公司地址, money=1000)

// 获取 FactoryBean 本身,需要加 & 前缀
Object factoryBean = applicationContext.getBean("&wzkCompanyBean");
// 输出:wzk.factory.WzkCompanyFactoryBean@xxxx

后置处理器

Spring 提供了两种后处理 Bean 的扩展接口:

  • BeanPostProcessor
  • BeanFactoryPostProcessor

执行顺序:工厂初始化 BeanFactory → Bean 对象 → 在 BeanFactory 初始化之后使用 BeanFactoryPostProcessor → 在 Bean 实例化后使用 BeanPostProcessor

注意:对象不一定是 SpringBean,而 SpringBean 一定是个对象。

BeanPostProcessor

BeanPostProcessor 是针对 Bean 级别的处理,可以针对具体的某个 Bean 进行处理。

public interface BeanPostProcessor {
    // 初始化方法前执行
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
    // 初始化方法后执行
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

说明:

  • 初始化方法指的是 init-method 所指定的方法
  • 默认会对整个 Spring 容器中所有的 Bean 进行处理
  • 可以通过参数 beanName 判断具体要处理的 Bean
  • 处理发生在 Spring 容器的实例化和依赖注入之后

BeanFactoryPostProcessor

BeanFactoryPostProcessor 是 BeanFactory 级别的处理,针对整个 Bean 工厂进行处理。典型应用如 PropertyPlaceholderConfigurer

public interface BeanFactoryPostProcessor {
   Factory(ConfigurableListableBeanFactory bean void postProcessBeanFactory) throws BeansException;
}

可以通过 getBeanDefinition 方法获取 BeanDefinition 对象,修改 Bean 标签中定义的属性值。

注意: 调用 BeanFactoryPostProcessor 方法时,Bean 还没有被实例化,此时 Bean 刚被解析为 BeanDefinition 对象。


总结

概念说明
BeanFactoryIOC 容器顶级接口,负责生产和管理 Bean
FactoryBean特殊 Bean,用于自定义 Bean 创建过程
BeanPostProcessorBean 级别后处理,在初始化前后执行
BeanFactoryPostProcessor工厂级别后处理,在 Bean 实例化前执行