Spring生命周期回调与容器扩展详解

Spring生命周期回调与容器扩展详解

在Spring框架中,Bean的生命周期回调与容器扩展是非常重要的一部分。Spring框架有一个完整的标准初始化和销毁Bean的流程, 我们可以根据自己的业务需求去扩展这个流程,实现一些自定义的处理。

Bean的生命周期回调

在Spring中,一个Bean的创建与销毁都是由容器来管理的, 容器会自动的调用Bean的一些方法来完成Bean的初始化和销毁。我们可以在Bean的生命周期的多个阶段插入我们自己的处理逻辑。这些阶段包括:Bean实例化、Bean属性设置、Bean初始化前、Bean初始化后、容器销毁前和容器销毁后等。

Bean实例化

在Bean实例化阶段,Spring会通过调用Bean的构造方法来实例化一个对象。如果Bean类的构造方法中存在参数,则Spring会先通过它们来实例化出所需的参数,并进行递归实例化。接着Spring会调用Bean实例化回调接口:InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation方法,以便让用户在Bean实例化之前进行一些处理。如果该方法返回了非 null 的 Bean,则 Spring 容器将不再调用它后面的 Bean 构造方法,直接使用返回的 Bean 对象。如果该方法返回了 null,则 Spring 容器仍会继续进行 Bean 的构造方法调用,直到构造出实例为止。

public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("InstantiationAwareBeanPostProcessor postProcessBeforeInstantiation");
        }
        return null;
    }
}

@Configuration
@ComponentScan("com.example.demo")
public class AppConfig {
    @Bean
    public MyInstantiationAwareBeanPostProcessor myInstantiationAwareBeanPostProcessor() {
        return new MyInstantiationAwareBeanPostProcessor();
    }
}

Bean属性设置

在Bean属性设置阶段,Spring会调用Bean的setter方法来完成依赖注入。Spring通过反射机制查找 Bean 中特定的 set 方法,并将配置文件或者注释配置中所定义的属性值通过这些set方法进行注入。如果Bean实现了BeanNameAware接口或BeanFactoryAware接口,则在属性注入完成后,Spring容器会调用相应的回调方法:BeanNameAware#setBeanName()或BeanFactoryAware#setBeanFactory()。

public class User implements BeanNameAware, BeanFactoryAware {
    private String name;
    private int age;

    public void setBeanName(String name) {
        System.out.println(this.getClass().getSimpleName() + " setBeanName");
    }

    public void setBeanFactory(BeanFactory beanFactory) {
        System.out.println(this.getClass().getSimpleName() + " setBeanFactory");
    }

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

    public void setAge(int age) {
        this.age = age;
    }
}

@Configuration
@ComponentScan("com.example.demo")
public class AppConfig {
    @Bean
    public User user() {
        User user = new User();
        user.setName("Nate");
        user.setAge(30);
        return user;
    }
}

Bean初始化前

在Bean初始化前阶段,Spring容器会调用BeanPostProcessor#postProcessBeforeInitialization()该回调方法,让用户可以在Bean初始化的前面添加自己的逻辑。 Spring容器必须在Bean属性注入完成后,Bean实现了Aware的回调方法后,才会回调这个 BeanPostProcessor 的回调方法。这可以保证调用之前的 Bean 所有属性都被正确的设置了。

public class MyBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("BeanPostProcessor postProcessBeforeInitialization");
        }
        return bean;
    }
}

@Configuration
@ComponentScan("com.example.demo")
public class AppConfig {
    @Bean
    public MyBeanPostProcessor myBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }
}

Bean初始化后

在Bean初始化后阶段,Spring容器会调用BeanPostProcessor#postProcessAfterInitialization()该回调方法,让用户可以在Bean初始化的后面添加自己的逻辑。 Spring容器必须在调用BeanPostProcessor#postProcessBeforeInitialization()之后,才会回调这个 BeanPostProcessor 的回调方法。

public class MyBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("BeanPostProcessor postProcessAfterInitialization");
        }
        return bean;
    }
}

@Configuration
@ComponentScan("com.example.demo")
public class AppConfig {
    @Bean
    public MyBeanPostProcessor myBeanPostProcessor() {
        return new MyBeanPostProcessor();
    }
}

容器销毁前

在容器销毁前阶段,Spring容器会调用DisposableBean#destroy()方法和DestroyBean接口的destroy()方法,以便进行Bean销毁前的一些逻辑处理。

public class Dog implements DisposableBean {
    public void destroy() throws Exception {
        System.out.println("DisposableBean destroy");
    }
}

@Configuration
@ComponentScan("com.example.demo")
public class AppConfig {
    @Bean(destroyMethod = "destroy")
    public Dog dog() {
        return new Dog();
    }
}

容器销毁后

在容器销毁后阶段,Spring容器会调用BeanPostProcessor#postProcessBeforeDestruction()方法和DestroyBean接口的destroy()方法,以便进行销毁Bean后的一些逻辑处理。

public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor {
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("DestructionAwareBeanPostProcessor postProcessBeforeDestruction");
        }
    }

    public boolean requiresDestruction(Object bean) {
        return true;
    }
}

@Configuration
@ComponentScan("com.example.demo")
public class AppConfig {
    @Bean
    public MyDestructionAwareBeanPostProcessor myDestructionAwareBeanPostProcessor() {
        return new MyDestructionAwareBeanPostProcessor();
    }
}

容器扩展

在Spring中,我们还可以通过继承一些扩展点的抽象类来实现我们自己的扩展。这些扩展点包括:BeanFactoryPostProcessor、BeanPostProcessor、ApplicationListener和ResourceLoaderAware等。

BeanFactoryPostProcessor

BeanFactoryPostProcessor用于对BeanFactory进行处理。在Spring容器初始化完成之后,BeanFactory 调用BeanFactoryPostProcessor回调函数对BeanFactory进行外部扩展。我们可以通过实现这个接口实现对Bean的修改,比如替换Bean的内容,增加Bean的内容等等。注意:这个扩展只是针对BeanFactory的扩展,而不是Bean的扩展。

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        BeanDefinition bd = beanFactory.getBeanDefinition("dog");
        MutablePropertyValues pvs = bd.getPropertyValues();
        if (pvs.contains("name")) {
            PropertyValue pv = pvs.getPropertyValue("name");
            pv.setConvertedValue("Tommy");
        }
    }
}

@Configuration
@ComponentScan("com.example.demo")
public class AppConfig {
    @Bean
    public MyBeanFactoryPostProcessor myBeanFactoryPostProcessor() {
        return new MyBeanFactoryPostProcessor();
    }
}

BeanPostProcessor

前面已经讲解了BeanPostProcessor,它主要用于在Bean的初始化前后添加自己的处理逻辑。

ApplicationListener

ApplicationListener用于监听ApplicationEvent类型的事件。当相关事件发生时,Spring容器就会调用该接口的回调函数。我们可以利用这个机制自定义自己需要的事件,并在事件发生时实现自己的业务逻辑。

public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {
    public void onApplicationEvent(MyApplicationEvent event) {
        System.out.println("MyApplicationListener onApplicationEvent");
    }
}

@Configuration
@ComponentScan("com.example.demo")
public class AppConfig {
    @Bean
    public MyApplicationListener myApplicationListener() {
        return new MyApplicationListener();
    }
}

public class MyApplicationEvent extends ApplicationEvent {
    public MyApplicationEvent(Object source) {
        super(source);
    }
}

@Component
public class User {
    @Autowired
    private ApplicationContext applicationContext;

    public void print() {
        MyApplicationEvent event = new MyApplicationEvent(this);
        applicationContext.publishEvent(event);
    }
}

ResourceLoaderAware

ResourceLoaderAware用于在加载Bean时获取ResourceLoader(资源加载器)来加载文件或URL等资源。

public class MyResourceLoaderAware implements ResourceLoaderAware {
    private ResourceLoader resourceLoader;

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public void print() throws IOException {
        Resource resource = resourceLoader.getResource("classpath:test.txt");
        InputStream inputStream = resource.getInputStream();
        System.out.println(inputStream);
    }
}

@Configuration
@ComponentScan("com.example.demo")
public class AppConfig {
    @Bean
    public MyResourceLoaderAware myResourceLoaderAware() {
        return new MyResourceLoaderAware();
    }
}

总结

Spring中的Bean生命周期回调和容器扩展提供了很好的扩展机制, 通过实现一些扩展点的接口,我们可以在Bean的实例化,初始化,销毁的不同阶段插入我们自己的处理逻辑,实现一些自定义的处理。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Spring生命周期回调与容器扩展详解 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Python实现ORM

    下面是关于Python实现ORM的完整攻略,包括介绍、使用和两个示例说明。 介绍 ORM(Object-Relational Mapping)是一种将对象模型和关系数据库模型进行映射的技术。ORM可以将数据库中的表、字段等映射为Python中的类、属性等,从而实现对数据库的操作。Python中有多个ORM框架可供选择,如Django ORM、SQLAlche…

    other 2023年5月6日
    00
  • xp/win7/win8系统连接投影设备后没有声音怎么办?电脑连接投影设备无声音的解决方法

    针对“xp/win7/win8系统连接投影设备后没有声音”的问题,我们可以按照以下步骤进行操作: 1. 检查投影设备是否支持音频传输 首先需要检查投影设备是否支持音频传输功能,如果不支持,则无法在投影设备上播放电脑中的音频。如果设备支持,需要确认投影设备是否正确连接电脑的音频输出端口。 2. 检查电脑音频设置 其次,需要检查电脑音频设置是否正确。在Windo…

    other 2023年6月27日
    00
  • 2018年3大UI设计趋势,你知道吗?

    2018年3大UI设计趋势,你知道吗? UI设计是一个不断变化的领域,每年都会有新的趋势和流行。作为网站的站长,我们需要紧跟时代,掌握最新的UI设计趋势,来提高用户体验,增强网站的竞争力。在2018年,以下三个UI设计趋势将会成为主流。 1. 扁平化设计进一步发展 扁平化设计是近年来最为流行的UI设计潮流之一,它强调简洁的界面设计,去除了过多的装饰和效果,使…

    其他 2023年3月28日
    00
  • bvt&bat(版本验证测试和版本验收测试)

    BVT & BAT(版本验证测试和版本验收测试) 什么是BVT和BAT? BVT指的是版本验证测试,也称为构建验证测试,是一个自动化测试过程,旨在检查构建过程中产生了什么问题。BVT测试确保系统是否处于可以进一步测试的状态。BAT指的是版本验收测试,主要用于确认将构建的软件交付给QA团队之前是否可以通过测试,以便将其发布到客户。 BVT和BAT的重要…

    其他 2023年3月29日
    00
  • ASP.NET中Form表单不可以嵌套使用

    在ASP.NET中,Form表单不可以嵌套使用。这是因为ASP.NET Web Forms模型是基于单一表单的,它使用了一个HTML <form> 元素来包裹整个页面的内容。当页面被提交时,整个表单的数据将被发送到服务器进行处理。 如果在ASP.NET中嵌套使用多个Form表单,会导致以下问题: 无法正确提交数据:当嵌套的Form表单被提交时,只…

    other 2023年7月28日
    00
  • tibcojaspersoftstudio报表软件使用教程

    Tibco Jaspersoft Studio报表软件使用教程 Tibco Jaspersoft Studio是一款开源的报表设计工具,可以用于创建各种类型的报表,包括表格、图表、交叉表等。本文将详细讲解Tibco Jaspersoft Studio使用教程,包括两个示例说明。 1. 下载和安装Tibco Jaspersoft Studio Tibco Ja…

    other 2023年5月7日
    00
  • Javascript中字符串相关常用的使用方法总结

    Javascript中字符串相关常用的使用方法总结 在Javascript中,字符串是一种常见的数据类型。在日常的开发过程中,对于字符串的处理十分重要。本篇文章将对Javascript中字符串相关常用的使用方法进行总结,旨在帮助读者更加深入地理解和运用字符串类型的相关知识。 1. 创建字符串 使用单引号创建一个字符串: var str1 = ‘hello w…

    other 2023年6月20日
    00
  • python去除字符串中的换行符

    在Python中,可以使用多种方法去除字符串中的换行符。下面是一些常用的方法: 方法一:使用replace()函数 可以使用Python内置的replace()函数来换字符串中的换行符。示例代码如下: str_with_newline = "Hello,\nWorld!" str_without_newline = str_with_ne…

    other 2023年5月8日
    00
合作推广
合作推广
分享本页
返回顶部