文章
问答
冒泡
Spring如何处理@PostConstruct注解

前言

最近在springboot的项目中,看到大佬用@PostConstruct注解方法来实现项目启动时去执行该方法,由于之前自己做项目都是通过写一个Servlet监听类然后在web.xml中配置一下来达到这个效果,所以特地去研究了一下Spring是如何处理@PostConstruct的。

PostConstruct简介

javaEE5引入了@PostConstruct和@PreDestroy两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作。

特点:

  1. 只有一个非静态方法能使用此注解
  2. 被注解的方法不得有任何参数
  3. 被注解的方法返回值必须为void
  4. 被注解方法不得抛出已检查异常
  5. 此方法只会被执行一次

大体流程:

服务器加载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

参考文章

spring

关于作者

TimothyC
天不造人上之人,亦不造人下之人
获得点赞
文章被阅读