1. lazy-init 延迟加载
Bean的延迟加载
Application容器默认行为是在启动服务器的时候将所有的单例bean提前实例化,提前实例化意味着初始化过程中ApplicationContext实例会创建并配置所有的singleton。
<bean id="testBean" calss="cn.lagou.LazyBean" lazy-init="true" />
- 设置了lazy-init为true的bean将不会再启动时提前被实例化,而是第一次向容器通过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="prototype"时,那么即使设置了lazy-init="false",容器启动也不会初始化bean,而是getBean方法实例化的。
应用场景
- 开启延迟加载一定程度提高容器启动和运转性能。
- 对于不常使用的Bean设置延迟加载,这样偶尔使用的时候再加载,不必要从一开始该bean就占用资源。
2. FactoryBean和BeanFactory
BeanFactory接口是容器的顶级接口,定义了容器的一些基础行为,负责生产和管理Bean的一个工厂,具体使用它下面的子接口的类型,比如ApplicationContext;
此处我们重点分析FactoryBean。
Spring中Bean有两种,一种是普通Bean,一种是工厂Bean(FactroyBean),FactoryBean可以生成某一个类型的Bean实例(返回给我们),也就是说我们可以借助于它自定义Bean的创建流程。
Bean创建的三种方式中的静态方法和实例化方法和FactoryBean作用类似,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;
}
}
Company类
package com.lagou.edu.pojo;
public class Company {
private String name;
private String address;
private int scale;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getScale() {
return scale;
}
public void setScale(int scale) {
this.scale = scale;
}
@Override
public String toString() {
return "Company{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", scale=" + scale +
'}';
}
}
CompanyFactory类
package com.lagou.edu.factory;
import com.lagou.edu.pojo.Company;
import org.springframework.beans.factory.FactoryBean;
public class CompanyFactoryBean implements FactoryBean<Company> {
private String companyInfo; // 公司名称,地址,规模
public void setCompanyInfo(String companyInfo) {
this.companyInfo = companyInfo;
}
@Override
public Company getObject() throws Exception {
// 模拟创建复杂对象Company
Company company = new Company();
String[] strings = companyInfo.split(",");
company.setName(strings[0]);
company.setAddress(strings[1]);
company.setScale(Integer.parseInt(strings[2]));
return company;
}
@Override
public Class<?> getObjectType() {
return Company.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
xml配置
<bean id="companyBean" class="com.lagou.edu.factory.CompanyFactoryBean">
<property name="companyInfo" value="拉勾,中关村,500"/>
</bean>
测试,获取FactoryBean产生的对象
Object companyBean = applicationContext.getBean("companyBean");
System.out.println("bean:" + companyBean);
// 结果如下
bean:Company{name='拉勾', address='中关村', scale=500}
测试,获取FactoryBean,需要在id之前添加“&”
Object companyBean = applicationContext.getBean("&companyBean");
System.out.println("bean:" + companyBean);
// 结果如下, 可以通过包名看到就是刚才新建的factoryBean
bean:com.lagou.edu.factory.CompanyFactoryBean@53f6fd09
3. 后置处理器
Spring提供了两种后处理bean的扩展接口,分别是BeanPostProcessor和BeanFactoryPostProcessor。两者使用上是有所区别的。
工厂初始化(BeanFactory)- -> Bean对象
在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进行后置处理做一些事情。
在Bean对象实例化(并不是Bean的整个生命周期完成)之后可以使用BeanPostProcessor进行后置处理做一些事情。
3.1 BeanPostProcessor
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
该接口提供两个方法,分别在bean的初始化方法前和初始化方法后执行(这个初始化方法值得是类似我们定义bean的时候定义了init-method所指定的方法)。
定义了一个类是实现了BeanPostProcessor,默认会对整个Spring容器中所有的bean进行处理,如果要对某个bean处理,可以通过方法参数判断,两个类型参数分别为Object和String,第一个参数是每一个bean的实例,第二个参数就是每个bean的name或者id属性的值。苏益我们可以通过第二个参数来判断我们将要处理的具体bean。
注意:处理是发生在Spring容器的实例化和依赖注入之后。
3.2 BeanFactoryPostProcessor
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
该接口只提供了一个方法postProcessBeanFactory,接口参数为ConfigurableListableBeanFactory,该接口参数定义了一些方法。
根据其中一个方法getBeanDefinition可以找到定义的bean的BeanDefinition对象,然后我们可以对定义的属性进行修改,以下是BeanDefinition中的方法。
方法名字类似我们bean标签的属性,setBeanClassName对应bean标签的class属性,所以当我们拿到BeanDefinition对象时,我们可以手动修改bean标签中所定义的属性值。
BeanDefinition对象:我们在XML中定义的bean标签。Spring解析bean标签成为一个JavaBean,这个JavaBean就是BeanDefinition 。
注意:调用BeanFactoryPostProcessor方法时,这时候bean还没有实例化,此时bean刚被解析为BeanDefinition对象。