Bean初始化扩展点

Bean初始化扩展点

在Spring的应用中,较多常见的会使用注解@PostConstruct用于对于进行一些Bean的初始化操作。但Spring中存在三种方法只可以进行初始化的指定,分别是

  • 使用@PostConstruct
  • 实现InitializingBean
  • 使用@Bean(initMethod = “init”)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7z3GiMF7-1661505455872)(E:\pic\image-20220826165844104.png)]

在populateBean的入口处,依次调下如下方法:

BeanPostProcessor#postProcessBeforeInitialization

首先会获取Bean的后置处理器并执行,其中存在一个CommonAnnotationBeanPostProcessor继承自InitDestroyAnnotationBeanPostProcessor;

从下面代码中看到其设置了初始化的注解参数为@PostConstruct

	public CommonAnnotationBeanPostProcessor() {
		setOrder(Ordered.LOWEST_PRECEDENCE - 3);
		setInitAnnotationType(PostConstruct.class);
		setDestroyAnnotationType(PreDestroy.class);
		ignoreResourceType("javax.xml.ws.WebServiceContext");
	}

查找初始化方法,根据配置的@PostConstruct注解,反射查找

private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
		final boolean debug = logger.isDebugEnabled();
		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 -> {
				if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
					LifecycleElement element = new LifecycleElement(method);
					currInitMethods.add(element);
					if (debug) {
						logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
					}
				}
				if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
					currDestroyMethods.add(new LifecycleElement(method));
					if (debug) {
						logger.debug("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 new LifecycleMetadata(clazz, initMethods, destroyMethods);
	}

在InitDestroyAnnotationBeanPostProcessor中的执行逻辑:

	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		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;
	}

InitializingBean#afterPropertiesSet

程序继续往下,invokeInitMethods(beanName, wrappedBean, mbd);这里的代码较为直接,boolean isInitializingBean = (bean instanceof InitializingBean);直接通过类型判断,执行回调的afterPropertiesSet方法。

接着查询Bean定义了initMethod配置的初始化方法,并调用执行。

invokeCustomInitMethod(beanName, bean, mbd);

BeanPostProcessor#postProcessAfterInitialization

见下

总结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrIALQWp-1661505455874)(E:\pic\image-20220826170247511.png)]

扩展

知道上述原理后,考虑这样一个场景,设计一个注解用于控制Bean初始化最后一步额外操作。

这里要复用到BeanPostProcessor#postProcessAfterInitialization,可以看到其是初始化方法中最后一行代码,正好满足要求。

@Documented
@Retention(RUNTIME)
@Target(METHOD)
public @interface LastInit {
}

Bean后置处理器,继承InitDestroyAnnotationBeanPostProcessor,设置对应注解类即可,并在postProcessAfterInitialization中调用父类中的postProcessBeforeDestruction方法即可。

@Component
public class LastInitAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor {
    public LastInitAnnotationBeanPostProcessor() {
        super();
        setInitAnnotationType(LastInit.class);
    }

    @Override
    public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException {
        //不处理
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        super.postProcessBeforeInitialization(bean, beanName);
        return bean;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值