Spring Bean生命周期与常用接口

2023年 7月 25日 87.7k 0

Spring Bean生命周期

image.png

①BeanFactoryPostProcessor

介绍

实现该接口可以在 Spring 容器加载 Bean 定义之后、实例化 Bean 之前修改 Bean 的定义信息。通过重写 postProcessBeanFactory() 方法,可以对 Bean 的定义进行修改,例如修改属性值、添加额外的 Bean 定义等。

BeanFactoryPostProcessor接口与bean定义进行交互和修改,但是不会与bean实例进行交互。这样做可能导致过早的bean实例化,违反容器规则并导致意外的副作用。如果需要与bean实例进行交互,则应该实现BeanPostProcessor接口。

关于执行顺序?

  • ApplicationContext会根据PriorityOrdered和Ordered语义对自动检测到的BeanFactoryPostProcessor进行排序。
  • 而通过ConfigurableApplicationContext以编程方式注册的BeanFactoryPostProcessor将按照注册的顺序应用;通过实现PriorityOrdered或Ordered接口来表达的任何排序语义将被忽略。
  • 此外,@Order注解对BeanFactoryPostProcessor不起作用。

应用场景

  • 修改属性值。如加解密。
  • 注册额外的Bean定义。注册新的Bean定义到Bean工厂中,这样,后续的Bean实例化过程就可以使用这些新定义的Bean。
  • Bean名称的重命名,实现自定义命名策略。
  • 条件化Bean注册:根据条件判断是否注册这个Bean。
  • 对Bean的注解进行处理:读取Bean的特殊注解,对Bean定义进行二次处理。
  • 动态加载配置文件
  • 实现国际化
  • ...

案例

动态修改配置类属性

配置类

@Component
@ConfigurationProperties(prefix = "my")
public class MyConfig {

    private String myProperty;

    public String getMyProperty() {
        return myProperty;
    }

    public void setMyProperty(String myProperty) {
        this.myProperty = myProperty;
    }
}

修改属性


import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 获取MyConfig bean
        MyConfig myConfig = beanFactory.getBean(MyConfig.class);
        
        // 修改属性值
        myConfig.setMyProperty("Updated Value from BeanFactoryPostProcessor");
    }
}

修改Bean的初始化方法

@Component
public class MyBean  {

    
    @PostConstruct
    public void init() {
        System.out.println("Initializing MyBean...");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Destroying MyBean...");
    }

    public void customInit() {
        System.out.println("Custom Initialization ");
    }

    public void customDestroy() {
        System.out.println("Custom Destruction " );
    }
}
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 获取名为 "myBean" 的 Bean 的定义
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myBean");

        // 修改 Bean 的初始化方法为 "customInit"
        beanDefinition.setInitMethodName("customInit");
        
        // 修改 Bean 的销毁方法为 "customDestroy"
        beanDefinition.setDestroyMethodName("customDestroy");
    }


}

重命名Bean

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 获取名为 "myBean" 的 Bean 的定义
        BeanDefinition beanDefinition = beanFactory.getBeanDefinition("myBean");
        
        // 修改 Bean 的名称为 "renamedMyBean"
        beanFactory.registerSingleton("renamedMyBean", beanFactory.getBean("myBean"));
    }
}

②Aware系列接口

介绍

通过实现Aware接口,Bean可以获取到Spring容器的一些关键资源或设置相关信息,从而能够在运行时更灵活地与容器进行交互和定制。

常用的接口

  • ApplicationContextAware:实现该接口的Bean可以获取到ApplicationContext,它是Spring容器的顶层接口,包含了所有容器的功能。通过ApplicationContext,Bean可以在运行时获取其他Bean、资源、国际化消息等。
  • BeanNameAware:实现该接口的Bean可以获取自己在Spring容器中的Bean名称。这在需要在Bean中获取自己的名称时非常有用,例如在日志记录、动态注册Bean等场景中。
  • BeanFactoryAware:实现该接口的Bean可以获取到Bean所属的BeanFactory,也就是Spring容器本身。这可以让Bean在运行时获取其他Bean或进行Bean的动态注册。
  • EnvironmentAware:实现该接口的Bean可以获取Spring的Environment对象,它表示了Spring的环境信息,包含了配置文件中的属性、系统属性等。这在需要根据不同的环境进行动态配置时非常有用。
  • ResourceLoaderAware:实现该接口的Bean可以获取ResourceLoader,用于加载外部资源。通过ResourceLoader,Bean可以加载classpath中的文件、URL资源等。
  • MessageSourceAware:实现该接口的Bean可以获取MessageSource,用于获取国际化消息。这在需要根据不同的语言或地区返回不同的消息时非常有用。

案例

获取ApplicationContext

@RestController
public class ProxyTestController implements ApplicationContextAware{

    private static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

③⑥BeanPostProcessor

介绍

实现该接口可以在 Bean 实例化后、初始化前、后对 Bean 进行增强。提供了在 Bean 初始化之前、后干预的机会,可以对 Bean 进行定制化处理。

实例化:是指创建一个对象的过程
初始化:初始化包括属性的赋值、调用初始化方法(例如使用 @PostConstruct 标记的方法)、进行依赖注入等。初始化是对象生命周期中的一个关键阶段,它确保对象在使用之前处于合适的状态。

通过重写 postProcessBeforeInitialization() 和 postProcessAfterInitialization() 方法,可以在 Bean 初始化之前和之后进行一些自定义逻辑,返回处理过的Bean实例。

应用场景

  • 修改属性:加解密、校验。
  • 属性扩展附加信息,比如动态生成的一些属性值;
  • AOP相关处理:在方法前后添加自定义逻辑,比如,动态生成代理对象、方法前后拦截等。
  • 处理自定义注解:根据自定义注解,对Bean进行二次处理。
  • 包装对象:对对象进行包装,增强、扩展Bean功能。
  • ...

案例

动态生成代理对象

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return new LoggingProxy().getLoggingProxy(bean);
    }
}


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class LoggingProxy implements InvocationHandler {

    private Object target;

    public Object getLoggingProxy(Object target) {
        if(target instanceof LoggingInterface) {
            this.target = target;
            return Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),
                    target.getClass().getInterfaces(),
                    this
            );
        }
        return target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before executing method: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After executing method: " + method.getName());
        return result;
    }
}

public interface LoggingInterface {
}

public interface ProxyTestService extends LoggingInterface {
    void proxyTest();
}

@Service
public class ProxyTestServiceImpl implements ProxyTestService {
    @Override
    public void proxyTest() {
        System.out.println("被代理方法");
    }
}


@RestController
public class ProxyTestController {

    @Resource
    private ProxyTestService proxyTestService;


    @GetMapping("a")
    public String proxyTest() {
        proxyTestService.proxyTest();
        return "ok";
    }
}

④PostConstruct

依赖注入完成后立即执行,通常用于执行一些初始化操作,比如连接数据库、加载配置文件、缓存预热等。

注解并不是 Spring 特有的,它们是 JSR-250 规范中定义的注解
注意事项:被标记方法不能是静态,也不能传递参数

⑤InitializingBean

实现该接口可以在 Bean 属性设置完成后执行初始化操作。通过重写 afterPropertiesSet() 方法,可以在 Bean 初始化时执行自定义的逻辑。

⑦SmartInitializingSingleton

Spring 提供的一个扩展接口,用于在所有单例 Bean 初始化完成后执行一些特定的逻辑。它提供了一个 afterSingletonsInstantiated() 方法,当所有的单例 Bean 初始化完成后,Spring 容器会自动调用该方法。

⑧PreDestroy

在 Spring 容器销毁该 Bean 前执行。通常用于执行一些清理操作,比如释放资源、关闭连接等。

注解并不是 Spring 特有的,它们是 JSR-250 规范中定义的注解
注意事项:被标记方法不能是静态,也不能传递参数

⑨DisposableBean

实现该接口可以在容器销毁 Bean 实例前执行清理操作。通过重写 destroy() 方法,可以在 Bean 销毁前执行自定义的清理逻辑。

FactoryBean

介绍

实现了FactoryBean了实现类,通过 getObject() 方法,返回一个自定义Bean到容器,提供给其它Bean 实例使用(依赖注入)。

应用场景

  • 对象的缓存:FactoryBean可以实现对象的缓存,例如在每次调用时返回同一个对象实例,提高性能。
  • 动态代理:FactoryBean可以用于创建动态代理对象,实现一些特定的功能,例如权限控制、事务管理等。
  • 对象的延迟加载:FactoryBean可以在需要时才创建实例,实现对象的延迟加载,从而减少系统启动时间和资源占用。
  • 对象的创建和配置:FactoryBean允许开发人员在创建Bean实例时进行更复杂的逻辑处理,例如从外部配置文件中读取参数,进行条件判断,创建不同的实例等。这样可以将对象的创建和配置逻辑从业务代码中分离出来,提高了代码的可维护性和可扩展性。

案例

提供一个Bean

例如,下面FactoryBean的实现类MyBean,就提供了SomeService的实现给OtherBean使用:

public class SomeService {
    // SomeService的具体实现
}

public class MyBean implements FactoryBean {
    @Override
    public SomeService getObject() throws Exception {
        // 在这里创建并返回SomeService的实例
        return new SomeService();
    }

    @Override
    public Class getObjectType() {
        return SomeService.class;
    }

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

@Configuration
public class AppConfig {
    @Bean
    public MyBean myBean() {
        return new MyBean();
    }

    @Bean
    public OtherBean otherBean(SomeService someService) {
        // OtherBean依赖于SomeService实例
        return new OtherBean(someService);
    }
}

public class OtherBean {
    private final SomeService someService;

    public OtherBean(SomeService someService) {
        this.someService = someService;
    }

    // 其他操作...
}

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论