zoukankan      html  css  js  c++  java
  • 初始化bean和销毁bean的扩展

    前言

    前两篇文章创建bean属性注入已经讲述了创建bean的前三个步骤,这篇文章讲述的是创建bean的最后一个步骤------初始化bean。

    初始化bean

     在bean的配置中有一个init-method的属性,这个属性的作用是在bean实例化前调用init-method指定的方法来根据用户业务进行相应的实例化。Spring中程序已经执行过bean的实例化,并且进行了属性的填充,而就在这时将会调用用户设定的初始化方法:

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
            if (System.getSecurityManager() != null) {
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                    invokeAwareMethods(beanName, bean);
                    return null;
                }, getAccessControlContext());
            }
            else {
                //对特殊的bean处理:Aware、BeanClassLoaderAware、BeanFactoryAware
                invokeAwareMethods(beanName, bean);
            }
    
            Object wrappedBean = bean;
            if (mbd == null || !mbd.isSynthetic()) {
                //应用后处理器
                wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
            }
    
            try {
                //激活用户自定义的init方法
                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;
        }

    虽然说此函数的主要目的是进行按用户设定的初始化方法调用,但是除此之外还有些其他必要的工作。

    1.激活Aware方法

    在分析其原理之前,我们先来了解一下Aware的使用。Spring中提供一些Aware相关接口,比如BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等,实现这些Aware接口的bean被初始化之后,可以获取一些相对应的资源,例如实现BeanFactoryAware的bean在初始化后,Spring容器将会注入BeanFactory的实例,而实现ApplicationContextAware的bean,在bean被初始化后,将会被注入ApplicationContext的实例等。我们先通过实例方法来了解一下Aware的使用。

     定义普通的bean:

    public class Hello {
        public void say(){
            System.out.println("hello!");
        }
    }

    定义BeanFactoryAware类型的bean:

    public class AwareTest implements BeanFactoryAware {
        private BeanFactory beanFactory;
        //声明bean的时候Spring会自动注入BeanFactory
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            this.beanFactory = beanFactory;
        }
    
        public void test(){
            Hello hello = (Hello) beanFactory.getBean("hello");
            hello.say();
        }
    
        //测试
        public static void main(String[] args){
            ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
            AwareTest awareTest = (AwareTest) ctx.getBean("test");
            awareTest.test();
        }
    
    }

    配置文件:

        <bean id="test" class="com.joe.aware.AwareTest"/>
        <bean id="hello" class="com.joe.aware.Hello"/>

    运行上述测试类,运行结果:

    hello!

    按照上面的方法我们可以获取到Spring中BeanFactory,并且可以根据BeanFactory获取所有的bean,以及进行相关设置。当然还有其他的Aware的使用方法都大同小异,来看下Spring的实现方式:

    private void invokeAwareMethods(final String beanName, final Object bean) {
            if (bean instanceof Aware) {
                if (bean instanceof BeanNameAware) {
                    ((BeanNameAware) bean).setBeanName(beanName);
                }
                if (bean instanceof BeanClassLoaderAware) {
                    ClassLoader bcl = getBeanClassLoader();
                    if (bcl != null) {
                        ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                    }
                }
                if (bean instanceof BeanFactoryAware) {
                    ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
                }
            }
        }

    上述代码比较简单,所以逻辑就不说了。

    2.处理器的应用

    BeanPostProcessor在前面的文章中已经出现了不少次,是Spring中开放式架构中一个必不可少的亮点,给了用户充足的权限去更改或者扩展Spring,而除了BeanPostProcessor外还有其他很多的PostProcessor,当然大部分都是以此为基础,继承自BeanPostProcessor。BeanPostProcessor的使用位置在:当调用客户自定义初始化方法前以及调用自定义初始化方法后分别会调用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,使用户可以根据自己的业务需求进行相应的处理。

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

    3.激活自定义的init方法

    定制的初始化方法除了熟知的使用配置init-method外,还有使自定义的bean实现InitializingBean接口,并在afterPropertiesSet中实现自己的初始化业务逻辑。

    init-method与afterPropertiesSet都是在初始化bean时执行,执行顺序是afterPropertiesSet先执行,而init-method后执行。

    在invokeInitMethods方法中就实现了这两个步骤的初始化方法调用:

    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
                throws Throwable {
            //首先檢查是否是InitializingBean,如果是的话需要调用afterPropertiesSet方法
            boolean isInitializingBean = (bean instanceof InitializingBean);
            if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
                if (logger.isTraceEnabled()) {
                    logger.trace("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);
                }
            }
        }

    注册DisposableBean

    Spring中不仅提供了对于初始化方法的扩展入口,同样也提供了销毁方法的扩展入口,对于销毁方法的扩展,除了熟知的destroy-method方法外,用户还可以注册后处理器DestructionAwareBeanPostProcessor来统一处理bean的销毁方法,源代码如下:

    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
            AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
            if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
                if (mbd.isSingleton()) {
                    // 单例模式下注册需要销毁的bean,此方法中会处理实现DisposableBean的bean,
                    //并且对所有bean使用DestructionAwareBeanPostProcessors处理
                    registerDisposableBean(beanName,
                            new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
                }
                else {
                    // 自定义scope处理
                    Scope scope = this.scopes.get(mbd.getScope());
                    if (scope == null) {
                        throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
                    }
                    scope.registerDestructionCallback(beanName,
                            new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
                }
            }
        }

    参考:《Spring源码深度解析》 郝佳 编著:

    作者:Joe
    努力了的才叫梦想,不努力的就是空想,努力并且坚持下去,毕竟这是我相信的力量
  • 相关阅读:
    4月21日Java作业
    5.14 Java作业
    第十周java作业
    4月30号作业
    第七周上机
    4.9Java
    通宵看剧有感
    error: pathspec 'xxxxxxxxx' did not match any file(s) known to git
    markdown格式测试
    博客申请通过啦
  • 原文地址:https://www.cnblogs.com/Joe-Go/p/10181965.html
Copyright © 2011-2022 走看看