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

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

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

目前已经更新到了:

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

延迟加载

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

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

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

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

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

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

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

xml 复制代码
<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

java 复制代码
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WzkCompany {

    private String name;

    private String address;

    private String money;

}

WzkCompanyFactoryBean

java 复制代码
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>

测试运行

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

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

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

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

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

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

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

shell 复制代码
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 对象。

相关推荐
Swift社区1 分钟前
Excel 列名称转换问题 Swift 解答
开发语言·excel·swift
一道微光5 分钟前
Mac的M2芯片运行lightgbm报错,其他python包可用,x86_x64架构运行
开发语言·python·macos
矛取矛求9 分钟前
QT的前景与互联网岗位发展
开发语言·qt
Leventure_轩先生9 分钟前
[WASAPI]从Qt MultipleMedia来看WASAPI
开发语言·qt
向宇it23 分钟前
【从零开始入门unity游戏开发之——unity篇01】unity6基础入门开篇——游戏引擎是什么、主流的游戏引擎、为什么选择Unity
开发语言·unity·c#·游戏引擎
wm104325 分钟前
java web springboot
java·spring boot·后端
smile-yan27 分钟前
Provides transitive vulnerable dependency maven 提示依赖存在漏洞问题的解决方法
java·maven
老马啸西风28 分钟前
NLP 中文拼写检测纠正论文-01-介绍了SIGHAN 2015 包括任务描述,数据准备, 绩效指标和评估结果
java
Earnest~31 分钟前
Maven极简安装&配置-241223
java·maven
皮蛋很白34 分钟前
Maven 环境变量 MAVEN_HOME 和 M2_HOME 区别以及 IDEA 修改 Maven repository 路径全局
java·maven·intellij-idea