• 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");
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    查找初始化方法,根据配置的@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);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    在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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    InitializingBean#afterPropertiesSet

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

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

    invokeCustomInitMethod(beanName, bean, mbd);
    
    • 1

    BeanPostProcessor#postProcessAfterInitialization

    见下

    总结

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

    扩展

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

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

    @Documented
    @Retention(RUNTIME)
    @Target(METHOD)
    public @interface LastInit {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    深度学习模型部署 C++学习经历
    Python实现面向对象版学员管理系统
    自定义 C++ 和 CUDA 扩展
    使用 mediaDevices.getUserMedia 在浏览器录制视频
    向日葵x华测导航:远程控制如何助力导航测绘设备运维
    vs+opencv+QT调试程序
    【小笔记】复杂模型小数据可能会造成过拟合还是欠拟合?
    GD32F103 硬件 IIC
    低耦合的理解
    Lucene数据写入流程
  • 原文地址:https://blog.csdn.net/sunquan291/article/details/126547405