美文网首页
每日一结——Spring初始化Bean几种方式

每日一结——Spring初始化Bean几种方式

作者: 奔向学霸的路上 | 来源:发表于2021-03-03 15:37 被阅读0次

    Spring初始化Bean的几种方式

    1. 实现InitializingBean接口,重写afterPropertiesSet方法
    2. <Bean>元素上添加init-method初始化
    3. 使用@PostConstruct注解
    

    执行顺序:Constructor > @PostConstruct > InitializingBean > init-method

    源码位置

    AbstractAutowireCapableBeanFactory#initializeBean

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        // ...
    
        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 初始化前置处理
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }
    
        try {
            // 调用初始化方法
            invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable ex) {
            // ...
        }
        if (mbd == null || !mbd.isSynthetic()) {
            // 初始化后置处理
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }
    
        return wrappedBean;
    }
    

    这里主要包含了初始化的前置处理、调用初始化方法、初始化后置处理

    @PostConstruct

    @PostConstruct注解将在applyBeanPostProcessorsBeforeInitialization这个前置处理

    @Override
        public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
                throws BeansException {
    
            Object result = existingBean;
            for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
                Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
                if (current == null) {
                    return result;
                }
                result = current;
            }
            return result;
        }
    

    跟进InitDestroyAnnotationBeanPostProcessor#postProcessBeforeInitialization方法

    @Override
        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;
        }
    

    findLifecycleMetadata方法会解析元数据,所以@PostConstruct注解的初始化方法在这里找到了。

    再跟进findLifecycleMetadata方法

    @Override
        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;
        }
    

    再进findLifecycleMetadata

    private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
            if (this.lifecycleMetadataCache == null) {
                // Happens after deserialization, during destruction...
                return buildLifecycleMetadata(clazz);
            }
            // Quick check on the concurrent map first, with minimal locking.
            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;
        }
    

    再进buildLifecycleMetadata

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

    可以看到有个判断是否被initAnnotationType注释注解,然后添加到集合中。

    initAnnotationType位于CommonAnnotationBeanPostProcessor类中

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

    可以看到CommonAnnotationBeanPostProcessor和InitDestroyAnnotationBeanPostProcessor的关系是继承关系

    实现InitializingBean接口afterPropertiesSet方法

    继续initializeBean方法,这次来看invokeInitMethods方法

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
            .....
            Object wrappedBean = bean;
            if (mbd == null || !mbd.isSynthetic()) {
                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()) {
                wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
            }
    
            return wrappedBean;
        }
    

    invokeInitMethods方法

    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
                throws Throwable {
    
            boolean isInitializingBean = (bean instanceof InitializingBean);
            if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
                }
                if (System.getSecurityManager() != null) {
                    try {
                        AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
                            ((InitializingBean) bean).afterPropertiesSet();
                            return null;
                        }, getAccessControlContext());
                    }
                    catch (PrivilegedActionException pae) {
                        throw pae.getException();
                    }
                }
                else {
                    ((InitializingBean) bean).afterPropertiesSet();
                }
            }
    
            if (mbd != null && bean.getClass() != NullBean.class) {
                String initMethodName = mbd.getInitMethodName();
                if (StringUtils.hasLength(initMethodName) &&
                        !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                        !mbd.isExternallyManagedInitMethod(initMethodName)) {
                    invokeCustomInitMethod(beanName, bean, mbd);
                }
            }
        }
    

    可以看出首先会检查是否是InitializingBean,如果是调用afterPropertiesSet()方法

    init-method

    在invokeInitMethods方法中,我们会发现以下这段代码,它是执行init-method配置的内容

    if (mbd != null && bean.getClass() != NullBean.class) {
                String initMethodName = mbd.getInitMethodName();
                if (StringUtils.hasLength(initMethodName) &&
                        !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                        !mbd.isExternallyManagedInitMethod(initMethodName)) {
                    invokeCustomInitMethod(beanName, bean, mbd);
                }
            }
    

    postProcessAfterInitialization方法

    再次回到initializeBean方法,可以看到最后调用了applyBeanPostProcessorsAfterInitialization方法

    @Override
        public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
                throws BeansException {
    
            Object result = existingBean;
            for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
                Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
                if (current == null) {
                    return result;
                }
                result = current;
            }
            return result;
        }
    

    总结

    根据上述源码可以得出以下执行顺序:postProcessBeforeInitialization->InitializingBean(afterPropertiesSet)->init-method->postProcessAfterInitialization

    BeanPostProcessor后置处理器

    如果一个Bean实现了BeanPostProcess接口,将会调用postProcessBeforeInitialization(Object bean, String beanName)方法,
    经常用于对Bean内容的更改,并且由于这个在Bean初始化结束时调用,也常被应用与缓存或者内存技术
    postProcessBeforeInitialization方法在bean初始化之前执行, postProcessAfterInitialization方法在bean初始化之后执行

    相关文章

      网友评论

          本文标题:每日一结——Spring初始化Bean几种方式

          本文链接:https://www.haomeiwen.com/subject/dwvqqltx.html