前言
最近在springboot的项目中,看到大佬用@PostConstruct注解方法来实现项目启动时去执行该方法,由于之前自己做项目都是通过写一个Servlet监听类然后在web.xml中配置一下来达到这个效果,所以特地去研究了一下Spring是如何处理@PostConstruct的。
PostConstruct简介
javaEE5引入了@PostConstruct和@PreDestroy两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作。
特点:
- 只有一个非静态方法能使用此注解
- 被注解的方法不得有任何参数
- 被注解的方法返回值必须为void
- 被注解方法不得抛出已检查异常
- 此方法只会被执行一次
大体流程:
服务器加载Servlet -> servlet 构造函数的加载 -> postConstruct ->init(init是在service 中的初始化方法,创建service 时发生的事件) -> Service -> destory -> predestory -> 服务器卸载serlvet
Spring实现@PostConstruct的原理
首先看一下BeanPostProcessor这个接口
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
然后在AbstractAutowireCapableBeanFactory类中的initializeBean方法里面会回调这些方法,bean对象在进入到initializeBean方法的时候已经完成了属性填充
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 回调postProcessBeforeInitialization方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 回调postProcessAfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
然后有个继承了BeanPostProcessor接口的CommonAnnotationBeanPostProcessor类,它的父类InitDestroyAnnotationBeanPostProcessor实现了postProcessBeforeInitialization()方法,判断方法上是否有注解PostConstruct,然后通过反射去调用该方法。
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
//......
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
//构造方法里面给initAnnotationType属性赋值PostConstruct.class
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
if (jndiPresent) {
this.jndiFactory = new SimpleJndiBeanFactory();
}
}
//......
}
postProcessBeforeInitialization -> findLifecycleMetadata -> buildLifecycleMetadata
public class InitDestroyAnnotationBeanPostProcessor
implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
//......
//实现了postProcessBeforeInitialization方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//看下面的findLifecycleMetadata方法
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
//反射调用方法
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
//......
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
//看下面lifecycleMetadataCache的构建
return buildLifecycleMetadata(clazz);
}
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
synchronized (this.lifecycleMetadataCache) {
metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
metadata = buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);
}
return metadata;
}
}
return metadata;
}
//......
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
return this.emptyLifecycleMetadata;
}
List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//initAnnotationType在CommonAnnotationBeanPostProcessor的构造方法被初始化了PostConstruct
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
});
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}
//......
}
代码示例
用两个类简单测试一下@PostConstruct在Bean对象创建中的执行顺序
@Component
@Slf4j
public class DemoA {
@Autowired
private DemoB demoB;
public DemoA() {
log.info("这是DemoA的构造方法");
}
@PostConstruct
private void init() {
log.info("这是DemoA的init方法");
demoB.test();
}
}
@Component
@Slf4j
public class DemoB {
@PostConstruct
private void init() {
log.info("这是DemoB的init方法");
}
public DemoB() {
log.info("这是DemoB的构造方法");
}
void test() {
log.info("这是DemoB的test方法");
}
}
最后启动项目控制台输出
这是DemoA的构造方法
这是DemoB的构造方法
这是DemoB的init方法
这是DemoA的init方法
这是DemoB的test方法
可以得出:构造方法 -> @Autowired自动注入 -> @PostConstruct