Spring IOC源码解析-余下的初始化工作

一.简介

大家应该还记得在bean配置时有一个init-method的属性,这个属性的作用是在bean实例化之前调用init-method指定的方法来根据用户进行相应的实例化。我们现在就已经进入了这个方法,首先看一下这个方法的执行位置,Spring中的程序已经执行过了bean的实例化,并且进行了属性的填充,而就在这个时候将会调用用户设定的初始化方法。initializeBean 就是这个方法,我们将对这个方法进行解析。

二.源码解析

2.1 initializeBean 

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    if (System.getSecurityManager() != null) {
        AccessController.doPrivileged(new PrivilegedAction<Object>() {
            @Override
            public Object run() {
                invokeAwareMethods(beanName, bean);
                return null;
            }
        }, getAccessControlContext());
    }
    else {
        // 若 bean 实现了 BeanNameAware、BeanFactoryAware、BeanClassLoaderAware 等接口,则向 bean 中注入相关对象
        invokeAwareMethods(beanName, bean);
    }

    Object wrappedBean = bean;
    if (mbd == null || !mbd.isSynthetic()) {
        // 执行 bean 初始化前置操作
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    try {
        /*
         * 调用初始化方法:
         * 1. 若 bean 实现了 InitializingBean 接口,则调用 afterPropertiesSet 方法
         * 2. 若用户配置了 bean 的 init-method 属性,则调用用户在配置中指定的方法
         */
        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()) {
        // 执行 bean 初始化后置操作,AOP 会在此处向目标对象中织入切面逻辑
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}

这个方法的做了下面几件事:

  1. 检测bean是否实现了*Aware类型接口,若实现,则向bean中注入相应对象

  2. 执行bean初始化前置操作

  3. 执行初始化操作

  4. 执行bean初始化后置操作

2.2 激活Aware方法

2.2.1 Aware的使用

Spring中提供了一些Aware相关接口,比如BeanFactoryAware,ApplicationContextAware,ServletContextAware等,实现这些接口的bean在被初始化之后,可以获得一些相应的资源,例如实现BeanFactoryAware的bean在初始化后,Spring容器将会注入BeanFactory的实例,而实现ApplicationContextAware的bean,在bean被初始化后,就会被注入ApplicationContext的实例等。可以 通过下面的例子来了解一下Aware的使用。

1.定义普通的bean

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

2.定义BeanFactoryAware类型的bean,使用main方法进行测试

public class Test implements BeanFactoryAware{
      
     private BeanFactory beanFactory;
     @Override
     public void setBeanFactory(BeanFactory beanFactory) throws BeansException{
       this.beanFactory=beanFactroy;
     }

    public void testAware(){
       Hello hello=(Hello)beanFactory.getBean("hello");
       hello.say();
    }

    public static void main(String[] args){
       ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
       Test test=(Test)ioc.getBean("test");
        test.testAware();
    }
}

3.运行测试类,在控制台输出:hello

按照上面的方法可以获得Spring的BeanFactory,并可以根据BeanFactory获取所有的bean,以及进行相关设置。

2.2.2 invokeAwareMethods 

private void invokeAwareMethods(final String beanName, final Object bean) {
    if (bean instanceof Aware) {
        if (bean instanceof BeanNameAware) {
            // 注入 beanName 字符串
            ((BeanNameAware) bean).setBeanName(beanName);
        }
        if (bean instanceof BeanClassLoaderAware) {
            // 注入 ClassLoader 对象
            ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
        }
        if (bean instanceof BeanFactoryAware) {
            // 注入 BeanFactory 对象
            ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
        }
    }
}

invokeAwareMethods 方法的逻辑很简单,一句话总结:根据 bean 所实现的 Aware 的类型,向 bean 中注入不同类型的对象。

2.3 处理器的应用

BeanPostProcessor相信大家并不陌生,它给予用户充足的权限去更改或者扩展Spring,而除了BeanPostProcessor还有很多PostProcessor,大部分都是以此为基础,继承自BeanPostProcessor。BeanPostProcessor的使用位置就在这里,在调用用户自定义初始化方法前以及调用自定义初始化方法后分别会调用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法,使用户可以自己根据自己业务需求进行响应处理。

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




@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;

		// 同样获取createBean 过程中所有 BeanPostProcessors(bean后置处理器)
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			
			// 重点 :如果bean被子类标识为代理,则使用配置的拦截器创建一个代理。
			Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

2.4 激活自定义的init方法

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

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

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

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
        throws Throwable {

    // 检测 bean 是否是 InitializingBean 类型的
    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(new PrivilegedExceptionAction<Object>() {
                    @Override
                    public Object run() throws Exception {
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }
                }, getAccessControlContext());
            }
            catch (PrivilegedActionException pae) {
                throw pae.getException();
            }
        }
        else {
            // 如果 bean 实现了 InitializingBean,则调用 afterPropertiesSet 方法执行初始化逻辑
            ((InitializingBean) bean).afterPropertiesSet();
        }
    }

    if (mbd != null) {
        String initMethodName = mbd.getInitMethodName();
        if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                !mbd.isExternallyManagedInitMethod(initMethodName)) {
            // 调用用户自定义的初始化方法
            invokeCustomInitMethod(beanName, bean, mbd);
        }
    }
}

在源代码中,就可以看到上面所说两个方法的执行顺序。

参考:Spring IOC 容器源码分析 - 余下的初始化工作

         《Spring源码深度即系》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值