Spring常用拓展点(随记)

Aware接口

它们为Bean提供了自我感知Spring容器内环境和资源的能力,比如提供容器信息,获取容器里的其他bean等,常用的它的子接口有:

  • ApplicationContextAware
    • 允许Bean获取到ApplicationContext对象,从而可以与Spring容器进行交互。
    • 常见应用场景包括获取ServletContext、国际化信息、Scheduler等定时任务等。
  • BeanFactoryAware
    • 允许Bean获取到BeanFactory对象,从而可以获取Spring容器中的Bean实例或一些组件。
    • 常见应用场景包括获取Spring容器中的Bean实例、手动注册BeanDefinition等。
@Component
public class TestApplicationContextAware implements ApplicationContextAware {
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        /*for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
            System.out.println(beanDefinitionName);
        }*/
        System.out.println("ApplicationContextAware...");
    }
}


@Component
public class TestBeanFactoryAware implements BeanFactoryAware {

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware...");
    }
}

BeanFactoryPostProcessor接口

它的用途有以下方面:

  1. 自定义修改和扩展BeanFactory
    • BeanFactoryPostProcessor允许开发人员在Spring容器加载配置文件并创建Bean实例之前,对BeanFactory进行自定义修改和扩展。
    • 这包括修改Bean定义(如修改属性值、更改Bean的作用域等)、注册新的Bean定义(动态地向Spring容器中添加新的Bean定义)以及添加自定义元数据等。
  2. 操作BeanDefinition
    • 由于BeanFactoryPostProcessor在所有的BeanDefinition被扫描完成之后执行,因此它允许开发人员在这个时间点对Bean定义进行操作。
    • 通过实现postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法,开发人员可以访问并修改beanFactory中的BeanDefinition。
  3. 支持多个实现和顺序控制
    • 可以定义多个BeanFactoryPostProcessor实例,并通过设置order属性来确定它们的执行顺序。
    • 这在需要按照特定顺序对Bean定义进行处理时非常有用,例如某些Bean定义可能依赖于其他Bean定义的先行处理。
  4. 扩展点设计
    • BeanFactoryPostProcessor是Spring框架中优秀的设计之一,作为一个扩展点,它允许开发人员通过实现接口和注册Bean的方式轻松地对Spring容器进行扩展。
    • 这种设计使得Spring框架具有高度的灵活性和可扩展性。
  5. 具体实现
    • 要注册一个BeanFactoryPostProcessor实例,需要定义一个Java类来实现BeanFactoryPostProcessor接口,并重写postProcessBeanFactory方法。
    • 然后,通过配置(如XML配置或Java配置)将这个类注册为一个Bean,Spring容器在启动时会自动调用其postProcessBeanFactory方法。
  6. 与BeanPostProcessor的区别
    • BeanFactoryPostProcessorBeanPostProcessor在Spring容器中的作用阶段是不同的。
    • BeanFactoryPostProcessor在Bean实例化之前操作BeanDefinition,而BeanPostProcessor则在Bean实例化之后、初始化之前或之后进行操作。
@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("走到了 BeanFactoryPostProcessor....");
    }
}

 

BeanPostProcessor接口

它的用途如下:

  1. 简化依赖注入
    • 通过BeanPostProcessor,开发者可以轻松实现依赖注入,减少了手动管理对象之间依赖关系的复杂性。
    • 开发者可以在Bean的实例化、属性注入、初始化等阶段插入自定义逻辑,从而实现对Bean的定制化和增强。
  2. 支持面向切面编程(AOP)
    • BeanPostProcessor提供了AOP的支持,使得开发者可以更加灵活地实现横切关注点,如日志记录、事务管理等。
    • 这些横切关注点可以被与核心业务逻辑分离开来,提高了代码的模块化程度。
  3. 优化配置管理
    • 通过BeanPostProcessor,开发者可以将配置信息与代码分离,实现配置的集中管理和动态加载。
    • 这降低了系统的耦合度,使得系统更易于维护和扩展。
  4. 自定义Bean处理
    • BeanPostProcessor接口定义了两个关键方法:postProcessBeforeInitializationpostProcessAfterInitialization
    • postProcessBeforeInitialization方法在Bean对象初始化之前被调用,开发者可以利用此方法执行一些初始化前的逻辑,如验证、属性设置、数据加载等。
    • postProcessAfterInitialization方法在Bean对象初始化之后被调用,开发者可以在此阶段对Bean进行进一步的定制化处理,如添加额外的功能或修改Bean的行为。
  5. 提供强大的扩展能力
    • BeanPostProcessor是Spring框架中的一个扩展点,通过实现这个接口,开发者可以扩展Spring容器的功能,增加自定义的逻辑。
    • 这使得开发者能够灵活地应对各种复杂的业务场景,提高系统的灵活性和可扩展性。
  6. 应用场景广泛
    • BeanPostProcessor的应用场景非常广泛,包括但不限于:
    • 在系统启动时,自动扫描并注册指定的Bean,实现自动化配置。
    • 在Bean初始化之后,通过AOP对Bean进行增强,扩展Bean的功能。
    • 在Bean的生命周期中插入自定义的逻辑,实现安全控制、事务处理等。
@Component
public class TestBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if("testPostConstructOne".equals(beanName)){
            System.out.println("BeanPostProcessor.postProcessBeforeInitialization... TestPostConstructOne");
        }
        if("testPostConstructTwo".equals(beanName)){
            System.out.println("BeanPostProcessor.postProcessBeforeInitialization... TestPostConstructTwo");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if("testPostConstructOne".equals(beanName)){
            System.out.println("BeanPostProcessor.postProcessAfterInitialization.... TestPostConstructOne");
        }
        if("testPostConstructTwo".equals(beanName)){
            System.out.println("BeanPostProcessor.postProcessAfterInitialization.... testPostConstructTwo");
        }
        return bean;
    }
}

 如上:它可以具体的去AOP切某个类。

InitializingBean接口

它和@PostConstruct 注解所注方法功能类似,它的用途如下:

  1. 定义初始化逻辑
    • InitializingBean接口允许开发者在Bean的所有属性设置完毕后,执行特定的初始化逻辑。
    • 通过实现该接口并重写afterPropertiesSet()方法,可以在Bean实例化、依赖注入完成之后执行自定义的初始化操作。
  2. 资源的初始化和数据加载
    • 在某些场景下,Bean在启动时需要加载一些资源或数据,如连接外部服务、加载缓存数据等。
    • 实现InitializingBean接口可以在所有依赖都注入完成后开始加载资源,从而确保资源加载的准确性和完整性。
  3. 设置动态属性
    • 当Bean中的一些字段需要根据其他属性进行计算或拼接后再进行设置时,可以利用InitializingBean的特性。
    • 在所有属性设置完成后,afterPropertiesSet()方法将被调用,此时可以对动态属性进行设置。
  4. 集成外部系统
    • 对于需要与外部系统(如数据库、消息队列等)进行集成的Bean,可以在afterPropertiesSet()方法中建立连接、验证配置等。
    • 这样做可以确保在Bean真正使用之前,所有必要的外部系统连接和配置都已正确建立。
  5. 与其他生命周期方法配合
    • 虽然InitializingBean提供了afterPropertiesSet()方法用于初始化,但Spring还提供了其他生命周期方法,如@PostConstruct注解和@PreDestroy注解。
    • 这些方法可以与InitializingBean的afterPropertiesSet()方法配合使用,以实现更复杂的生命周期管理逻辑。
  6. 避免直接调用方法
    • 传统的做法可能是在Bean的某个方法中直接调用初始化逻辑,但这可能导致代码难以维护和理解。
    • 通过实现InitializingBean接口,可以将初始化逻辑与业务逻辑分离,提高代码的可读性和可维护性。
@Component
@DependsOn("testPostConstructTwo")
public class TestPostConstructOne implements InitializingBean, ApplicationListener<MyEvent> {

    @PostConstruct
    public void testPostConstruct(){
        System.out.println("TestPostConstructOne....(@PostConstruct)");
    }

    @PreDestroy
    public void testPreDestroy(){
        System.out.println("TestPostConstructOne.testPreDestroy....(@PreDestroy)");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("TestPostConstructOne.afterPropertiesSet....(InitializingBean)");
    }

    @Override
    public void onApplicationEvent(MyEvent myEvent) {
        System.out.println("TestPostConstructOne 接到事件 Event:"+myEvent.getMessage());
    }
}


@Component
public class TestPostConstructTwo implements InitializingBean , ApplicationListener<MyEvent> {

    @PostConstruct
    public void TestPostConstruct(){
        System.out.println("TestPostConstructTwo....(@PostConstruct)");
    }

    @PreDestroy
    public void testPreDestroy(){
        System.out.println("TestPostConstructTwo.testPreDestroy....(@PreDestroy)");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("TestPostConstructTwo.afterPropertiesSet....(InitializingBean)");
    }

    @Override
    public void onApplicationEvent(MyEvent myEvent) {
        System.out.println("TestPostConstructTwo 接到事件 Event:"+myEvent.getMessage());
    }
}

ApplicationListener接口

它的作用如下:

  1. 事件监听
    • ApplicationListener是一个接口,它定义了一个处理应用程序事件的方法。当一个事件被发布时,所有注册了对应事件的ApplicationListener都会被通知,并调用其onApplicationEvent方法来处理这个事件。
  2. 松耦合通信
    • Spring的事件处理机制提供了一种观察者模式的实现,允许应用程序组件之间进行松耦合的通信。这意味着事件发布者和监听器之间不需要有直接的依赖关系,降低了系统的耦合度。
  3. 自定义事件处理
    • 通过实现ApplicationListener接口,开发者可以创建自定义的事件监听器,以便在特定事件发生时执行相应的操作。例如,可以监听ContextRefreshedEvent事件,在Spring应用上下文刷新完成时执行一些初始化操作。
  4. 支持多种事件
    • 在Spring Boot中,有许多常见的事件可以被监听,如ApplicationStartedEvent(应用程序启动开始时触发)、ApplicationReadyEvent(应用程序启动完成后触发)、ApplicationFailedEvent(应用程序启动失败时触发)等。开发者可以根据需要选择监听的事件。
  5. 注册方式多样
    • ApplicationListener的注册方式多样,可以通过在监听器类上添加@Component注解,将其注册为Spring容器中的Bean,也可以通过XML配置进行注册。这使得开发者可以灵活地选择注册方式,满足不同的需求。
  6. 优势
    • 使用ApplicationListener的优势在于其松耦合性、灵活性和可扩展性。通过事件处理机制,开发者可以在不修改事件发布者代码的情况下添加新的监听器,实现了松耦合的通信。同时,通过定义不同的事件和监听器,可以灵活地处理应用程序中的各种情况,满足复杂的业务需求。此外,Spring的事件处理机制是可扩展的,开发者可以轻松地创建自定义的事件和监听器,并将其集成到Spring容器中。
@Component
public class TestApplicationListener implements ApplicationListener<MyEvent> {
    @Override
    public void onApplicationEvent(MyEvent myEvent) {
        System.out.println("myEvent:"+myEvent.getMessage());

    }
}


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

    @PostConstruct
    public void myEvent(){
        System.out.println("TestMyEvent.myEvent @PostConstruct进入了");
        MyEvent myEvent = new MyEvent(this,"MyEvent....");
        applicationContext.publishEvent(myEvent);
        System.out.println("TestMyEvent.myEvent @PostConstruct事件发布了");
    }
}

最终的执行结果如下:

Connected to the target VM, address: '127.0.0.1:55538', transport: 'socket'

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.2.7.RELEASE)

2024-06-03 15:37:46.999  INFO 21164 --- [           main] com.study.TestSping                      : Starting TestSping on LAPTOP-BIU6HEDB with PID 21164 (E:\spring-cloud-study\spring-cloud-learning\study-spring\target\classes started by admin in E:\spring-cloud-study\spring-cloud-learning)
2024-06-03 15:37:47.003  INFO 21164 --- [           main] com.study.TestSping                      : No active profile set, falling back to default profiles: default
走到了 BeanFactoryPostProcessor
2024-06-03 15:37:47.756  INFO 21164 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2024-06-03 15:37:47.763  INFO 21164 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-06-03 15:37:47.763  INFO 21164 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.34]
2024-06-03 15:37:47.835  INFO 21164 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-06-03 15:37:47.835  INFO 21164 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 787 ms
TestMyEvent.myEvent @PostConstruct进入了
BeanPostProcessor.postProcessBeforeInitialization... TestPostConstructTwo
TestPostConstructTwo....(@PostConstruct)
TestPostConstructTwo.afterPropertiesSet....(InitializingBean)
BeanPostProcessor.postProcessAfterInitialization.... testPostConstructTwo
BeanPostProcessor.postProcessBeforeInitialization... TestPostConstructOne
TestPostConstructOne....(@PostConstruct)
TestPostConstructOne.afterPropertiesSet....(InitializingBean)
BeanPostProcessor.postProcessAfterInitialization.... TestPostConstructOne
TestPostConstructOne 接到事件 Event:MyEvent....
TestPostConstructTwo 接到事件 Event:MyEvent....
TestMyEvent.myEvent @PostConstruct事件发布了
ApplicationContextAware...
BeanFactoryAware...
InitializingBean.afterPropertiesSet ....
2024-06-03 15:37:47.961  INFO 21164 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2024-06-03 15:37:48.058  INFO 21164 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8081 (http) with context path ''
2024-06-03 15:37:48.060  INFO 21164 --- [           main] com.study.TestSping                      : Started TestSping in 1.495 seconds (JVM running for 3.015)
CommandLineRunner.....
Disconnected from the target VM, address: '127.0.0.1:55538', transport: 'socket'
2024-06-03 15:37:51.369  INFO 21164 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
DisposableBean....
TestPostConstructOne.testPreDestroy....(@PreDestroy)
TestPostConstructTwo.testPreDestroy....(@PreDestroy)

Process finished with exit code 130

  • 29
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值