简介
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);
@Override
public void afterPropertiesSet() throws Exception {
logger.info("调用InitializingBean的afterPropertiesSet方法.");
}
public void initMethod() throws Exception {
logger.info("调用init-method的initMethod方法.");
}
@PostConstruct
public 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);
@Override
public 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);
@Override
public void afterPropertiesSet() throws Exception {
logger.info("调用InitializingBean的afterPropertiesSet方法.");
}
public void initMethod() throws Exception {
logger.info("调用init-method的initMethod方法.");
}
@DefPostConstruct
public void postConstructor() throws Exception {
logger.info("调用@PostConstruct注释的方法.");
}
}
4) 在Spring的配置文件中增加Bean
声明,并指定init-method
属性,同时配置DefApplicationContextAware
。
<!-- 配置 ApplicationContextAware -->
<bean
class="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
版本源码。
若文中存在错误和不足,欢迎指正!