ioc高级特性——延迟加载、FactoryBean、后置处理器

Lazy-Init延迟加载

Bean的延迟加载,通常bean会在ApplicationContext容器启动时,默认将bean进行实例化,并加载到SingletonObjects单例池中,但是如果我们为bean配置了Lazy-init以后,就不会再容器启动时创建并配置bean,而是会在我们第一次getbean的时候进行加载。

下面我们用一个例子来进行演示

lazy-init demo

首先我们新建两个类,一个叫Common,一个叫LazyInit
在这里插入图片描述
然后,我们对ApplicationContext.xml进行配置,一个使用延迟加载,一个为普通加载

<?xml version="1.0" encoding="UTF-8" ?>
<beans  xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
">
    <!--使用懒加载-->
    <bean id="lazyInit" class="LazyInit"  lazy-init="true"></bean>
    <!--不使用懒加载-->
    <bean id="common" class="Common"></bean>
</beans>

接着我们用测试方法去debug一下,看看使用懒加载的bean什么时候会加载到singletonObjects里面
在这里插入图片描述
在这里插入图片描述

方法执行到断点处,这个时候还没有调用getbean方法,我们看一下singletonobjects里面现在都有哪些bean
在这里插入图片描述
我们这个时候可以看出,没有使用lazy-init的bean,在applicationContext容器初始化的时候就已经将bean加载到singletonobjects单例池里面了,而使用lazy-init的bean还没有被加载,那么我们接着往下走一步
在这里插入图片描述
在这里插入图片描述
这个时候我们发现singletonobjects单例池中加载了lazy这个bean,所以使用lazy-init延迟加载的bean会在第一次被getBean的时候进行实例化

那么这种bean适合什么样的使用场景呢?
1、开启延迟加载能在一定程度上提高容器的启动和运转效率
2、对于一些不常用的类,我们可以开启延迟加载,这样就不用从一开始就占用资源

FactoryBean

说起FactoryBean我们很容易想起另一个BeanFactory,但是我们要清楚,他们并不是一个东西。

FactoryBean和BeanFactory

首先我们从命名上就可以看出他们的区别,FactoryBean是一个Bean,而BeanFactory明显是一个工厂。
熟悉Spring的同学知道BeanFactory是spring的顶级接口,他用来生产和管理bean,我们一般使用的是他的子接口,比如我们最常用的ApplicationContext等。

在spring中Bean有两种,一种是普通Bean,而另一种是工厂bean,也就是我们现在所说的FactoryBean,它的作用是能够生成某个类型的实例并返给我们,这也就是说我们可以去自定义实例对象

使用FactoryBean

首先我们看一下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;
 }
}

然后我们写一个关于FactoryBean的小demo

Demo

mode

public class User {
    private String name;
    private String sex;
    private int age;
    }

UserFactoryBean

public class UserFactoruyBean implements FactoryBean<User> {
    // 通过set方法注入user用户信息
    private String userIfo;
    public void setUserIfo(String userIfo){
        this.userIfo=userIfo;
    }
    @Override
    public User getObject() throws Exception {
        User user = new User();
        String[] split = userIfo.split(",");
        user.setName(split[0]);
        user.setSex(split[1]);
        user.setAge(Integer.parseInt(split[2]));
        return user;
    }

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

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

Beans.xml

   <bean id="userFactoryBean" class="Factory.UserFactoruyBean">
   <!--为属性赋值-->
       <property name="userIfo" value="yhy,男,26"></property>
   </bean>

接着我们来测试一下

    @Test
    public void factoryBeanTest(){
        ApplicationContext applicationContext= new ClassPathXmlApplicationContext("classpath:Beans.xml");
        User userFactoryBean = (User) applicationContext.getBean("userFactoryBean");
        System.out.println(userFactoryBean);
    }

测试结果
在这里插入图片描述
我们所实现的FactoryBean为我们产出了对应的bean对象,但是如果我们想要获取的是FactoryBean本身的实例对象呢?
那我们就需要在获取bean对象的时候,在对象名称前面加一个"&"符号,这样就获取的是FactoryBean本身
我们修改一下测试方法,再进行一下验证

    @Test
    public void factoryBeanTest(){
        ApplicationContext applicationContext= new ClassPathXmlApplicationContext("classpath:Beans.xml");
        // 获取User对象
        Object userBean = applicationContext.getBean("userFactoruyBean");
        // 获取UserFactoryBean对象
        Object userFactoruyBean = applicationContext.getBean("&userFactoruyBean");
        System.out.println(userBean);
        System.out.println(userFactoruyBean);
    }

结果正确
在这里插入图片描述

后置处理器

spring提供了两种后置处理bean的接口,一个是BeanPostProcessor,另一个是BeanFactoryPostProcessor。
顾名思义,两者之中BeanPostProcessor是对Bean做后置处理,而BeanFactoryPostProcessor是对BeanFactory做后置处理

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;
    }
}

BeanPostProcessor有两个方法,postProcessBeforeInitialization和postProcessAfterInitialization他们分别可以在Bean的初始化之前和初始化之后进行处理。
BeanPostProcessor默认会对容器内的所有Bean执行处理

同样我们写一个小demo
首先我们写两个类,一个是TestModel,另一个是PostProcessorTestModel。这样两个空类,我们不用添加任何方法,只需要建立两个空类就可以,仅测试使用。

然后我们写一个后置处理器

public class PPTPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 打印前置处理bean
        System.out.println("before"+beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 打印后置处理bean
        System.out.println("after"+beanName);
        return bean;
    }
}

BeanPostProcessor后置处理器是对已经注入的Bean进行处理,所以我们要编辑一下beans.xml配置文件

    <bean id="testModel" class="TestModel"></bean>
    <bean id="postProcessorTestModel" class="PostProcessorTestModel"></bean>
    <bean id="pPTPostProcessor" class="PPTPostProcessor"></bean>

然后写一个测试方法打一个断点测试一下
在这里插入图片描述
然后看结果
在这里插入图片描述
我们可以看到,后置处理器在bean注入完成后,对所有的bean进行了处理

BeanFactoryPostProcessor

BeanFactoryPostProcessor是对整个BeanFactory进行处理

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

该接口只提供了一个方法postProcessBeanFactory,这个方法的参数是ConfigurableListableBeanFactory
ConfigurableListableBeanFactory同样是一个接口,我们可以看到这个接口下的所有方法
在这里插入图片描述
其中getBeaneDefinition可以找到我们定义的BeanDefinition对象,那么BeanDefinition对象是什么呢?就是我们在beans.xml中的bean标签,spring解析bean标签内容会存储在BeanDefinition对象中,注意他不是实例化后的bean对象。
在BeanDefinition对象中有以下方法
在这里插入图片描述
我们可以通过调用这些方法修改bean标签中定义的属性

照例,我们通过修改刚才的demo来展示一下

TestModel

public class TestModel {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "TestModel{" +
                "name='" + name + '\'' +
                '}';
    }
}

BeanFactoryPostProcessor

public class PPTBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        // 获取bean
        BeanDefinition testModel = configurableListableBeanFactory.getBeanDefinition("testModel");
        // 获取属性
        MutablePropertyValues propertyValues = testModel.getPropertyValues();
        // 为属性赋值
        propertyValues.add("name","testModelName");
    }
}

Test方法测试

    @Test
    public void postProcessorTest(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:beans.xml");
        Object testModel = applicationContext.getBean("testModel");
        System.out.println(testModel);
    }

结果
在这里插入图片描述
赋值成功

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
实例化后处理器是指在IOC容器中配并实例化后处理器的过程。后处理器可以分为bean的后处理器和容器的后处理器。对于bean的后处理器,它会对容器中的bean进行后处理,对bean进行增强。而对于容器的后处理器,它会对IOC容器的功能进行增强。 常见的配实例化后处理器的方法有两种: 1. 使用@Configuration注解的类中使用@Bean注解来配bean后处理器。这种方式通过在配类中定义一个方法,并使用@Bean注解标记这个方法,使其返回一个后处理器的实例。例如,可以使用@Configuration和@Bean注解来配一个ConfigurationClassPostProcessor的实例,该实例是一个bean工厂后处理器实现类,用于解析@ComponentScan和@Bean注解。 2. 使用特定的后处理器实现类来配bean工厂后处理器。例如,可以使用MapperScannerConfigurer来作为bean工厂后处理器的实现类,用于扫描指定的包,并将符合条件的类注册成bean。 配实例化后处理器的具体步骤和方法可以根据具体的需求和使用场景进行选择和配。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Spring学习理解---后处理器](https://blog.csdn.net/qq_24792035/article/details/127311732)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Spring之BeanFactoryPostProcessor(bean工厂后处理器)](https://blog.csdn.net/qq_35512802/article/details/126167419)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值