目录
一、lazy-init 延迟加载
1、定义
1)原本默认的配置
<bean id="testBean" class="cn.lagou.LazyBean"/>
<!-- 该 bean 默认的设置为: -->
<bean id="testBean" class="cn.lagou.LazyBean" lazy-init="false"/>
lazy-init = “false”,立即加载,表示在 Spring 启动时,立刻进行实例化。
2)延迟加载的配置
如果不想让一个 singleton bean 在 ApplicationContext 实现初始化时被提前实例化,那么可以将 bean 设置为延迟实例化。
<bean id="testBean" class="cn.lagou.LazyBean" lazy-init="true"/>
设置 lazy-init 为 true 的 bean 将不会在 ApplicationContext 启动时提前被实例化,而是第一次向容器通过 getBean 索取 bean 时实例化的。
如果一个设置了立即加载的 bean1,引用了一个延迟加载的 bean2,那么 bean1 在容器启动时被实例化,而 bean2 由于被 bean1 引用,所以也被实例化,这种情况也符合延迟加载的 bean 在第一次调用时才被实例化的规则。
3)全局配置
也可以在容器层次中通过在元素上使用 “default-lazy-init” 属性来控制延迟初始化,如下配置:
<beans default-lazy-init="true">
<!-- no beans will be eagerly pre-instantiated... -->
</beans>
4)注意事项
如果一个 bean 的 scope 属性为 scope=“pototype” 时,即使设置了 lazy-init=“false”,容器启动时也不会实例化 bean,而是调用 getBean 方法实例化。
2、应用场景
- 开启延迟加载一定程度提高容器启动和运转性能;
- 对于不常使用的 Bean 设置延迟加载,这样偶尔使用的时候再加载,不必要从一开始该 Bean 就占用资源。
二、FactoryBean 和 BeanFactory
1、BeanFactory
BeanFactory 接口是容器的顶级接口,定义了容器的一些基础行为,负责生活和管理 Bean 的一个工厂,具体使用它下面的子接口类型,比如 ApplicationContext。
2、FactoryBean
Spring 中 Bean 有两种,一种是普通 Bean,一种是工厂 Bean(FactoryBean),FactoryBean 可以生成某一个类型的 Bean 实例(返回给我们),也就是说我们可以借助于它自定义 Bean 的创建过程。
Bean 创建的三种方式中的静态方法和实例化方法和 FactoryBean 作用类似,FactoryBean 使用较多,尤其在 Spring 框架一些组件中会使用,还有其他框架和 Spring 框架整合时使用。
例子:
想看一下 FactoryBean 源码。
// 可以让我们自定义 Bean 的创建过程(完成复杂 Bean 的定义)
public interface FactoryBean<T> {
@Nullable
// 返回 FactoryBean 创建的 Bean 实例,
// 如果 isSingleton 返回 true,则该实例会放到 Spring 容器的单例对象缓存池中 Map
T getObject() throws Exception;
@Nullable
// 返回 FactoryBean 创建的 Bean 类型
Class<?> getObjectType();
// 返回作用域是否单例
default boolean isSingleton() {
return true;
}
}
Company 类。
public class Company {
private String name;
private String address;
private int scale;
// get、set 方法略
@Override
public String toString() {
return "Company{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", scale=" + scale +
'}';
}
}
CompanyFactoryBean 类。
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.demo.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);
// 结果如下
bean:com.demo.edu.factory.CompanyFactoryBean@53f6fd09
三、后置处理器
Spring 提供了两种后处理 bean 的扩展接口,分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使用上是有所区别的。
1、两者区别
- 工厂初始化(BeanFactory)—> Bean 对象;
- 在 BeanFactory 初始化之后可以使用 BeanFactoryPostProcessor 进行后置处理做一些事情;
- 在 Bean 对象实例化(并不是 Bean 的整个生命周期完成)之后可以使用 BeanPostProcessor 进行后置处理做一些事情;
注意:对象不一定是 springbean,而 springbean 一定是个对象。
2、BeanPostProcessor
BeanPostProcessor 是针对 Bean 级别的处理,可以针对某个具体的 Bean。
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、BeanFactoryPostProcessor
BeanFactory 级别的处理,是针对整个 Bean 的工厂进行处理,典型应用:PropertyPlaceholderConfigurer。
@FunctionalInterface
public interface BeanFactoryPostProcessor {
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
throws BeansException;
}
此接口只提供了一个方法,方法参数为 ConfigurableListableBeanFactory,该参数类型定义了一些方法:
public interface ConfigurableListableBeanFactory
extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
void ignoreDependencyType(Class<?> type);
void ignoreDependencyInterface(Class<?> ifc);
void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue);
boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
throws NoSuchBeanDefinitionException;
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
Iterator<String> getBeanNamesIterator();
void clearMetadataCache();
void freezeConfiguration();
boolean isConfigurationFrozen();
void preInstantiateSingletons() throws BeansException;
}
其中有个方法名为 getBeanDefinition 的方法,我们可以根据此方法,找到我们定义 bean 的 BeanDefinition 对象。
然后我们可以对定义的属性进行修改,以下是 BeanDefinition 中的部分源码。
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
void setParentName(@Nullable String parentName);
@Nullable
String getParentName();
void setBeanClassName(@Nullable String beanClassName);
@Nullable
String getBeanClassName();
void setScope(@Nullable String scope);
@Nullable
String getScope();
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
void setDependsOn(@Nullable String... dependsOn);
@Nullable
String[] getDependsOn();
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
void setPrimary(boolean primary);
boolean isPrimary();
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
ConstructorArgumentValues getConstructorArgumentValues();
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
void setRole(int role);
int getRole();
void setDescription(@Nullable String description);
@Nullable
String getDescription();
ResolvableType getResolvableType();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
- 方法名字类似我们 bean 标签的属性,setBeanClassName 对应 bean 标签中的 class 属性,所以当我们拿到 BeanDefinition 对象时,我们可以手动修改 bean 标签中所定义的属性值。
- BeanDefinition 对象:我们在 XML 中定义的 bean 标签,Spring 解析 bean 标签成为一个 JavaBean, 这个 JavaBean 就是 BeanDefinition。
- 注意:调用 BeanFactoryPostProcessor 方法时,这时候 bean 还没有实例化,此时 bean 刚被解析成 BeanDefinition 对象。
文章内容输出来源:拉勾教育Java高薪训练营;