??简介
??JSR-250
规范为Bean
初始化之后/销毁之前方法指定了两个注解:@PostConstruct
和@PreDestroy
,这两个注解可以应用在方法级别上,@PostConstruct
注释方法在Bean
实例化之后、应用注入之前调用,@PreDestroy
注释方法在Bean
实例销毁之前调用。
??@PostConstruct
和@PreDestroy
规范中要去较为严格,但Spring在实现时,并未完全按照其规范实现,在Spring中应用@PostConstruct
和@PreDestroy
这两个注解,以实现约束为准即可。
??注意事项
??InitializingBean
注意事项:
??① Bean
必须实现InitializingBean
接口。
??② Bean
的afterPropertiesSet
不能使用@PostConstruct
注释。
??init-method
注意事项:
??① init-method
指定属性不能为空。
??② Bean
不可以实现InitializingBean
接口或Bean
的init-method
方法名不可以为afterPropertiesSet
。
??③ Bean
的init-method
方法不能使用@PostConstruct
注释。
??@PostConstruct
注意事项:
??① 可以应用于任何可见性的方法:public
、package-protected
、protected
或private
。
??② 不能注释在InitializingBean.afterPropertiesSet()
和init-method
方法上,可能导致后两者失效。
??演示示例
??@PostConstruct
、InitializingBean
和init-method
都可以用作Bean
初始化相关操作,示例将一起演示这三种方式。
??1) 建InitTestBean
,用于进行初始化相关的测试。
??① 实现InitializingBean
接口,重写afterPropertiesSet()
方法。
??② 添加initMethod()
方法,用于进行init-method
的配置。
??③ 添加postConstructor()
方法,用于@PostConstruct
注解注释。
package com.arhorchin.securitit.initbean;import javax.annotation.PostConstruct;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;/*** @author Securitit.* @note Bean初始化测试.*/
public class InitTestBean implements InitializingBean {
/*** logger.*/private Logger logger = LoggerFactory.getLogger(InitTestBean.class);@Overridepublic void afterPropertiesSet() throws Exception {
logger.info("调用InitializingBean的afterPropertiesSet方法.");}public void initMethod() throws Exception {
logger.info("调用init-method的initMethod方法.");}@PostConstructpublic void postConstructor() throws Exception {
logger.info("调用@PostConstruct注释的方法.");}}
??2) 在Spring的配置文件中增加Bean
声明,并指定init-method
属性。
<bean class="com.arhorchin.securitit.initbean.InitTestBean" init-method="initMethod"></bean>
??3) 运行程序查看效果,可以看到如下的输出。
2020-12-17 14:42:12 INFO [c.a.s.i.InitTestBean] 调用@PostConstruct注释的方法.
2020-12-17 14:42:12 INFO [c.a.s.i.InitTestBean] 调用InitializingBean的afterPropertiesSet方法.
2020-12-17 14:42:12 INFO [c.a.s.i.InitTestBean] 调用init-method的initMethod方法.
??从运行结果可以看出:
??① @PostConstruct
先于InitializingBean.afterPropertiesSet()
。
??② InitializingBean.afterPropertiesSet()
先于init-method
的initMethod()
。
??自定义注解示例
??@PostConstruct
和@PreDestroy
实现关键在于org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor
,而InitDestroyAnnotationBeanPostProcessor
允许通过setInitAnnotationType(...)
和setDestroyAnnotationType(...)
来自定义初始化和销毁注解类型。
??1) 自定义注解@DefPostConstruct
,用于进行演示。
package com.arhorchin.securitit.initbean;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author Securitit.* @note 自定义初始化注解.*/
@Documented
@Retention (RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DefPostConstruct {
}
??2) 建DefApplicationContextAware
,实现ApplicationContextAware
,用于通过InitDestroyAnnotationBeanPostProcessor
的setInitAnnotationType(...)
和setDestroyAnnotationType(...)
设置初始化和销毁注解类型。
package com.arhorchin.securitit.initbean;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;/*** @author Securitit.* @note 用于测试自定义注解的ApplicationContextAware.*/
public class DefApplicationContextAware implements ApplicationContextAware {
/*** logger.*/private Logger logger = LoggerFactory.getLogger(DefApplicationContextAware.class);@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
InitDestroyAnnotationBeanPostProcessor initDestroy = null;initDestroy = applicationContext.getBean(InitDestroyAnnotationBeanPostProcessor.class);logger.info("BeanPostProcessor.postProcessBeforeInitialization调用.Bean名称:" + initDestroy);initDestroy.setInitAnnotationType(DefPostConstruct.class);initDestroy.setDestroyAnnotationType(DefPreDestroy.class);}}
??3) 修改InitTestBean
,用于进行初始化相关的测试。
package com.arhorchin.securitit.initbean;import javax.annotation.PostConstruct;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;/*** @author Securitit.* @note Bean初始化测试.*/
public class InitTestBean implements InitializingBean {
/*** logger.*/private Logger logger = LoggerFactory.getLogger(InitTestBean.class);@Overridepublic void afterPropertiesSet() throws Exception {
logger.info("调用InitializingBean的afterPropertiesSet方法.");}public void initMethod() throws Exception {
logger.info("调用init-method的initMethod方法.");}@DefPostConstructpublic void postConstructor() throws Exception {
logger.info("调用@PostConstruct注释的方法.");}}
??4) 在Spring的配置文件中增加Bean
声明,并指定init-method
属性,同时配置DefApplicationContextAware
。
<!-- 配置 ApplicationContextAware -->
<beanclass="com.arhorchin.securitit.initbean.DefApplicationContextAware"></bean>
<!-- 配置 InitTestBean -->
<bean class="com.arhorchin.securitit.initbean.InitTestBean"init-method="initMethod"></bean>
??5) 运行程序查看效果,可以看到如下的输出。
2020-12-17 17:01:08 INFO [c.a.s.i.DefApplicationContextAware] ApplicationContextAware.setApplicationContext调用.Bean:org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@3027f7ce
2020-12-17 17:01:08 INFO [c.a.s.i.InitTestBean] 调用@DefPostConstruct注释的方法.
2020-12-17 17:01:08 INFO [c.a.s.i.InitTestBean] 调用InitializingBean的afterPropertiesSet方法.
2020-12-17 17:01:08 INFO [c.a.s.i.InitTestBean] 调用init-method的initMethod方法.
??可以看到,自定义注解同样达到了与@PostConstruct
注解相同的效果。
??总结
??本文对@PostConstruct
的应用进行了演示,同时一并演示了InitializingBean
和init-method
,并通过示例验证了三者之间的调用顺序,充分了解这点,还是十分有用的。
??源码解析基于spring-framework-5.0.5.RELEASE
版本源码。
??若文中存在错误和不足,欢迎指正!