Java-33 深入浅出 Spring - FactoryBean 和 BeanFactory BeanPostProcessor

点一下关注吧!!!非常感谢!!持续更新!!!

大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html

目前已经更新到了:

  • MyBatis(已更完)
  • Spring(正在更新...)

延迟加载

Lazy-init 延迟加载,Bean 的延迟加载。

ApplicationContext 容器的默认行为是在启动服务器时所有 Singleton Bean 提前进行。

复制代码
<!-- bean 的默认配置 -->
<bean id="wzkTestBean" class="wzk.WzkTestBean" lazy-init="false"

false 表示立即加载,表示在 Spring 启动的时候,立刻进行实例初始化。

如果不想让一个 Singleton Bean 在 ApplicationContext 实现初始化的时候被提前实例化,那可以配置其对应的值为 true。

如果设置了一个立即加载的 bean1,引用了一个延迟加载的 bean2,那么 bean1 在容器启动的时候会初始化,此时由于 bean2 是被 bean1 引用的,所以也会被实例化出来(当然,此时也符合第一次调用才初始化的原则)。

当然,也可以在配置上用 default-lazy-init 属性来控制延时初始化,比如下面的配置:

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

如果一个 bean 的 scope 属性为 scope = "pototype" 时,即使设置了 lazy-init=false,容器在启动的时候也不会立刻初始化,而是调用 getBean 方法实例化。

应用场景

  • 开启延迟加载可以在一定程度上提高容器启动的时候的性能、运转的性能。
  • 对于不会经常使用的 Bean,偶尔加载的时候再加载,节约资源。

FactoryBean 和 BeanFactory

基础介绍

BeanFactory 接口是容器的顶级接口,定义了容器的一些基础行为,负责生产和管理 Bean 的一个工厂,具体使用它下面的子接口类型,比如 ApplicationContext,此处我们重点分析:FactoryBean

Spring 中 Bean 有两种,一种普通 Bean,一种是工厂 Bean(FactoryBean),FactoryBean 可以生成某一个类型的对象实例,也就是我们可以借助它来自定义 Bean 的创建过程。

Bean 创建的三种方式中的静态方法和实例化方法和 FactoryBean 作用类似,FactoryBean 使用较多,尤其是 Spring 框架一些组件中会使用,还有其他框架 和 Spring框架整合时使用。

其中的方法有:

  • getObject
  • getObjectType
  • 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;
    }
}

编写配置

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

测试运行

此时我们执行代码的时候:

复制代码
Object wzkCompany = applicationContext.getBean("wzkCompanyBean");

输出的结果是构建出来的对象:

复制代码
name="公司名字" address="公司地址" money="1000"

那我们如果需要获取到 FactoryBean 的时候,我们需要这么写:

复制代码
Object wzkCompany = applicationContext.getBean("&wzkCompanyBean");

此时运行输出的结果就是:

复制代码
wzk.factory.WzkCompanyFactoryBean@xxxx

后置处理器

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

  • BeanPostProcessor
  • BeanFactoryPostProcess

工厂初始化 BeanFactory -> Bean 对象,在 BeanFactory 初始化之后可以使用 BeanFactoryPostProcessor 进行后置处理做一些事情,在 Bean 的对象实例化(并不是 Bean 的整个生命周期完成)之后可以使用 BeanPostcessor 进行后置处理做一些事情。

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

BeanPostProcessor

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

其中对应的方法有:

  • postProcessBeforeInitialization
  • postProcessAfterInitialization

该接口提供了两个方法,分别在 Bean 的初始化方法前和初始化方法之后执行,具体这个初始化方法指的是什么方法,类似我们在定义 Bean 的时候,定义了 init-method 所指定的方法。

定义一个类实现了 BeanPostProcessor,默认是会对整个 Spring 容器中所有的 Bean 进行处理,如果针对具体的某个 Bean 处理,可以通过方法参数判断,两个类型参数分别为 Object 和 String,第一个参数是每个 Bean 的实例,第二个参数是每个 Bean 的 name 或者 id 属性的值。

所以我们通过第二个参数,来判断将要处理的具体的 Bean。

注意:处理是发生在 Spring 容器的实例化和依赖注入之后。

BeanFactoryPostProcessor

BeanFactory 级别的处理,是针对整个 Bean 的工厂进行处理,典型:

  • PropertyPlaceholderConfigure

其中的方法如下:

  • postProcessBeanFactory

此接口只有一个方法,该参数定义了一些方法:

其中有个 getBeanDefinition 方法,我们可以根据此方法,找到我们定义 Bean 的 BeanDefinition 对象,然后我们可以对定义的属性进行修改,以下 BeanDefinition 中的方法:

方法名字类似我们的标签属性,setBeanClassName 对应 bean 标签中的 class 的属性,所以当我们拿到 BeanDefinition 对象时,我们可以手动修改 Bean 标签中所定义的属性值。

BeanDefinition对象:在 XML 定义中的 Bean 标签,Spring 解析 Bean 标签称为一个JavaBean,这个 JavaBean 就是 BeanDefinition。

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

相关推荐
能工智人小辰3 分钟前
二刷 苍穹外卖day10(含bug修改)
java·开发语言
DKPT4 分钟前
Java设计模式之结构型模式(外观模式)介绍与说明
java·开发语言·笔记·学习·设计模式
缘来是庄6 分钟前
设计模式之外观模式
java·设计模式·外观模式
编程小白gogogo25 分钟前
Spring学习笔记
笔记·学习·spring
LL.。27 分钟前
同步回调和异步回调
开发语言·前端·javascript
0wioiw039 分钟前
Python基础(吃洋葱小游戏)
开发语言·python·pygame
知其然亦知其所以然44 分钟前
JVM社招面试题:队列和栈是什么?有什么区别?我在面试现场讲了个故事…
java·后端·面试
栗子~~1 小时前
Python实战- Milvus 向量库 使用相关方法demo
开发语言·python·milvus
狐凄1 小时前
Python实例题:基于 Flask 的在线聊天系统
开发语言·python
狐凄1 小时前
Python实例题:基于 Flask 的任务管理系统
开发语言·python