Aware接口
它们为Bean提供了自我感知Spring容器内环境和资源的能力,比如提供容器信息,获取容器里的其他bean等,常用的它的子接口有:
- ApplicationContextAware:
- 允许Bean获取到ApplicationContext对象,从而可以与Spring容器进行交互。
- 常见应用场景包括获取ServletContext、国际化信息、Scheduler等定时任务等。
- BeanFactoryAware:
- 允许Bean获取到BeanFactory对象,从而可以获取Spring容器中的Bean实例或一些组件。
- 常见应用场景包括获取Spring容器中的Bean实例、手动注册BeanDefinition等。
@Component
public class TestApplicationContextAware implements ApplicationContextAware {@Overridepublic 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 {@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("BeanFactoryAware...");}
}
BeanFactoryPostProcessor接口
它的用途有以下方面:
- 自定义修改和扩展BeanFactory:
BeanFactoryPostProcessor
允许开发人员在Spring容器加载配置文件并创建Bean实例之前,对BeanFactory进行自定义修改和扩展。- 这包括修改Bean定义(如修改属性值、更改Bean的作用域等)、注册新的Bean定义(动态地向Spring容器中添加新的Bean定义)以及添加自定义元数据等。
- 操作BeanDefinition:
- 由于
BeanFactoryPostProcessor
在所有的BeanDefinition被扫描完成之后执行,因此它允许开发人员在这个时间点对Bean定义进行操作。 - 通过实现
postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
方法,开发人员可以访问并修改beanFactory
中的BeanDefinition。
- 由于
- 支持多个实现和顺序控制:
- 可以定义多个
BeanFactoryPostProcessor
实例,并通过设置order
属性来确定它们的执行顺序。 - 这在需要按照特定顺序对Bean定义进行处理时非常有用,例如某些Bean定义可能依赖于其他Bean定义的先行处理。
- 可以定义多个
- 扩展点设计:
BeanFactoryPostProcessor
是Spring框架中优秀的设计之一,作为一个扩展点,它允许开发人员通过实现接口和注册Bean的方式轻松地对Spring容器进行扩展。- 这种设计使得Spring框架具有高度的灵活性和可扩展性。
- 具体实现:
- 要注册一个
BeanFactoryPostProcessor
实例,需要定义一个Java类来实现BeanFactoryPostProcessor
接口,并重写postProcessBeanFactory
方法。 - 然后,通过配置(如XML配置或Java配置)将这个类注册为一个Bean,Spring容器在启动时会自动调用其
postProcessBeanFactory
方法。
- 要注册一个
- 与BeanPostProcessor的区别:
BeanFactoryPostProcessor
与BeanPostProcessor
在Spring容器中的作用阶段是不同的。BeanFactoryPostProcessor
在Bean实例化之前操作BeanDefinition,而BeanPostProcessor
则在Bean实例化之后、初始化之前或之后进行操作。
@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {System.out.println("走到了 BeanFactoryPostProcessor....");}
}
BeanPostProcessor接口
它的用途如下:
- 简化依赖注入:
- 通过BeanPostProcessor,开发者可以轻松实现依赖注入,减少了手动管理对象之间依赖关系的复杂性。
- 开发者可以在Bean的实例化、属性注入、初始化等阶段插入自定义逻辑,从而实现对Bean的定制化和增强。
- 支持面向切面编程(AOP):
- BeanPostProcessor提供了AOP的支持,使得开发者可以更加灵活地实现横切关注点,如日志记录、事务管理等。
- 这些横切关注点可以被与核心业务逻辑分离开来,提高了代码的模块化程度。
- 优化配置管理:
- 通过BeanPostProcessor,开发者可以将配置信息与代码分离,实现配置的集中管理和动态加载。
- 这降低了系统的耦合度,使得系统更易于维护和扩展。
- 自定义Bean处理:
- BeanPostProcessor接口定义了两个关键方法:
postProcessBeforeInitialization
和postProcessAfterInitialization
。 postProcessBeforeInitialization
方法在Bean对象初始化之前被调用,开发者可以利用此方法执行一些初始化前的逻辑,如验证、属性设置、数据加载等。postProcessAfterInitialization
方法在Bean对象初始化之后被调用,开发者可以在此阶段对Bean进行进一步的定制化处理,如添加额外的功能或修改Bean的行为。
- BeanPostProcessor接口定义了两个关键方法:
- 提供强大的扩展能力:
- BeanPostProcessor是Spring框架中的一个扩展点,通过实现这个接口,开发者可以扩展Spring容器的功能,增加自定义的逻辑。
- 这使得开发者能够灵活地应对各种复杂的业务场景,提高系统的灵活性和可扩展性。
- 应用场景广泛:
- BeanPostProcessor的应用场景非常广泛,包括但不限于:
- 在系统启动时,自动扫描并注册指定的Bean,实现自动化配置。
- 在Bean初始化之后,通过AOP对Bean进行增强,扩展Bean的功能。
- 在Bean的生命周期中插入自定义的逻辑,实现安全控制、事务处理等。
@Component
public class TestBeanPostProcessor implements BeanPostProcessor {@Overridepublic 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;}@Overridepublic 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 注解所注方法功能类似,它的用途如下:
- 定义初始化逻辑:
- InitializingBean接口允许开发者在Bean的所有属性设置完毕后,执行特定的初始化逻辑。
- 通过实现该接口并重写
afterPropertiesSet()
方法,可以在Bean实例化、依赖注入完成之后执行自定义的初始化操作。
- 资源的初始化和数据加载:
- 在某些场景下,Bean在启动时需要加载一些资源或数据,如连接外部服务、加载缓存数据等。
- 实现InitializingBean接口可以在所有依赖都注入完成后开始加载资源,从而确保资源加载的准确性和完整性。
- 设置动态属性:
- 当Bean中的一些字段需要根据其他属性进行计算或拼接后再进行设置时,可以利用InitializingBean的特性。
- 在所有属性设置完成后,
afterPropertiesSet()
方法将被调用,此时可以对动态属性进行设置。
- 集成外部系统:
- 对于需要与外部系统(如数据库、消息队列等)进行集成的Bean,可以在
afterPropertiesSet()
方法中建立连接、验证配置等。 - 这样做可以确保在Bean真正使用之前,所有必要的外部系统连接和配置都已正确建立。
- 对于需要与外部系统(如数据库、消息队列等)进行集成的Bean,可以在
- 与其他生命周期方法配合:
- 虽然InitializingBean提供了
afterPropertiesSet()
方法用于初始化,但Spring还提供了其他生命周期方法,如@PostConstruct
注解和@PreDestroy
注解。 - 这些方法可以与InitializingBean的
afterPropertiesSet()
方法配合使用,以实现更复杂的生命周期管理逻辑。
- 虽然InitializingBean提供了
- 避免直接调用方法:
- 传统的做法可能是在Bean的某个方法中直接调用初始化逻辑,但这可能导致代码难以维护和理解。
- 通过实现InitializingBean接口,可以将初始化逻辑与业务逻辑分离,提高代码的可读性和可维护性。
@Component
@DependsOn("testPostConstructTwo")
public class TestPostConstructOne implements InitializingBean, ApplicationListener<MyEvent> {@PostConstructpublic void testPostConstruct(){System.out.println("TestPostConstructOne....(@PostConstruct)");}@PreDestroypublic void testPreDestroy(){System.out.println("TestPostConstructOne.testPreDestroy....(@PreDestroy)");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("TestPostConstructOne.afterPropertiesSet....(InitializingBean)");}@Overridepublic void onApplicationEvent(MyEvent myEvent) {System.out.println("TestPostConstructOne 接到事件 Event:"+myEvent.getMessage());}
}@Component
public class TestPostConstructTwo implements InitializingBean , ApplicationListener<MyEvent> {@PostConstructpublic void TestPostConstruct(){System.out.println("TestPostConstructTwo....(@PostConstruct)");}@PreDestroypublic void testPreDestroy(){System.out.println("TestPostConstructTwo.testPreDestroy....(@PreDestroy)");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("TestPostConstructTwo.afterPropertiesSet....(InitializingBean)");}@Overridepublic void onApplicationEvent(MyEvent myEvent) {System.out.println("TestPostConstructTwo 接到事件 Event:"+myEvent.getMessage());}
}
ApplicationListener接口
它的作用如下:
- 事件监听:
- ApplicationListener是一个接口,它定义了一个处理应用程序事件的方法。当一个事件被发布时,所有注册了对应事件的ApplicationListener都会被通知,并调用其
onApplicationEvent
方法来处理这个事件。
- ApplicationListener是一个接口,它定义了一个处理应用程序事件的方法。当一个事件被发布时,所有注册了对应事件的ApplicationListener都会被通知,并调用其
- 松耦合通信:
- Spring的事件处理机制提供了一种观察者模式的实现,允许应用程序组件之间进行松耦合的通信。这意味着事件发布者和监听器之间不需要有直接的依赖关系,降低了系统的耦合度。
- 自定义事件处理:
- 通过实现ApplicationListener接口,开发者可以创建自定义的事件监听器,以便在特定事件发生时执行相应的操作。例如,可以监听
ContextRefreshedEvent
事件,在Spring应用上下文刷新完成时执行一些初始化操作。
- 通过实现ApplicationListener接口,开发者可以创建自定义的事件监听器,以便在特定事件发生时执行相应的操作。例如,可以监听
- 支持多种事件:
- 在Spring Boot中,有许多常见的事件可以被监听,如
ApplicationStartedEvent
(应用程序启动开始时触发)、ApplicationReadyEvent
(应用程序启动完成后触发)、ApplicationFailedEvent
(应用程序启动失败时触发)等。开发者可以根据需要选择监听的事件。
- 在Spring Boot中,有许多常见的事件可以被监听,如
- 注册方式多样:
- ApplicationListener的注册方式多样,可以通过在监听器类上添加
@Component
注解,将其注册为Spring容器中的Bean,也可以通过XML配置进行注册。这使得开发者可以灵活地选择注册方式,满足不同的需求。
- ApplicationListener的注册方式多样,可以通过在监听器类上添加
- 优势:
- 使用ApplicationListener的优势在于其松耦合性、灵活性和可扩展性。通过事件处理机制,开发者可以在不修改事件发布者代码的情况下添加新的监听器,实现了松耦合的通信。同时,通过定义不同的事件和监听器,可以灵活地处理应用程序中的各种情况,满足复杂的业务需求。此外,Spring的事件处理机制是可扩展的,开发者可以轻松地创建自定义的事件和监听器,并将其集成到Spring容器中。
@Component
public class TestApplicationListener implements ApplicationListener<MyEvent> {@Overridepublic void onApplicationEvent(MyEvent myEvent) {System.out.println("myEvent:"+myEvent.getMessage());}
}@Component
public class TestMyEvent {@Autowiredprivate ApplicationContext applicationContext;@PostConstructpublic 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