美文网首页Spring IOC源码解读
spring源码日记17: 初始化

spring源码日记17: 初始化

作者: BugPool | 来源:发表于2020-02-23 11:37 被阅读0次

所有文章已迁移至csdn,csdn个人主页https://blog.csdn.net/chaitoudaren
在此篇文章开始之前,如果读者对BeanAware、BeanPostProcessors还不够熟悉熟悉,强烈建议先阅读一下这篇文章:spring BeanPostProcessor 生命周期

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {
        ...
        try {
            //
            /**
             * 4. 填充属性
             * 如果@Autowired注解属性,则在上方完成解析后,在这里完成注入
             *
             * @Autowired
             * private Inner inner;
             */
            populateBean(beanName, mbd, instanceWrapper);
            // 5. 初始化
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        ...
}

初始化bean

    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                // 1. 回调各类Aware的set方法,实现注入
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            // 回调各类Aware的set方法,实现注入
            invokeAwareMethods(beanName, bean);
        }

        Object wrappedBean = bean;
        if (mbd == null || !mbd.isSynthetic()) {
            // 2. 应用初始化前置处理
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

        try {
            // 3. 触发自定义初始化方法
            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()) {
            // 4. 应用初始化后置处理
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

        return wrappedBean;
    }
  1. spring可以通过继承各种BeanAware,从写set方法获取对应信息。
    以BeanNameAware为例:
    private void invokeAwareMethods(final String beanName, final Object bean) {
        if (bean instanceof Aware) {
            // bean 实现了BeanNameAware,回调子类setBeanName方法,将beanName传回给bean做赋值
            if (bean instanceof BeanNameAware) {
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            // bean 实现了BeanClassLoaderAware,回调子类setBeanClassLoader方法,将bean类加载器传回给bean做赋值
            if (bean instanceof BeanClassLoaderAware) {
                ClassLoader bcl = getBeanClassLoader();
                if (bcl != null) {
                    ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
                }
            }
            // bean 实现了BeanFactoryAware,回调子类setBeanFactory方法,将当前BeanFactory传回给bean做赋值
            if (bean instanceof BeanFactoryAware) {
                ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
            }
        }
    }

spring检测到当前bean继承了BeanNameAware,便调用((BeanNameAware) bean).setBeanName(beanName);将beanName传入,而调用的这个方法由子类实现,实际则是调用以下代码将beanName赋值到子类中,BeanFactoryAware也同理

public class A implements BeanNameAware {
    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("BeanNameAware被调用, 获取到的beanName:" + name);
    }
}
  1. 实例化前置处理
    后置处理已经介绍很多了,就是调用对应子类的postProcessBeforeInitialization方法对bean进行修改,这里不再多说。需要注意的是这里的后置处理器有一点不一样的,也就是多了一个 Object current对象,意思是在经过实例化前置处理以后,传入的bean有可能被修改为其他bean。这里不单单值的是内容上的修改,而是指物理地址上的修改,这将会导致提前曝光对象的失效,继而引发被依赖对象的问题。
    这点我们在spring源码日记12: spring创建Bean的第6点曾经介绍过,当时让大家了解即可,现在可以回翻重新深究一下
    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;
    }
  1. 触发自定义初始化方法
    spring启动阶段已经解析过init-method属性并保存到BeanDefinition中,现在需要做的就是取出BeanDefiniton中对于的方法名,通过反射的方式触发初始化方法
    protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
            throws Throwable {

        // 如果bean实现了InitializingBean
        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>) () -> {
                        // 回调bean自定义的afterPropertiesSet方法
                        ((InitializingBean) bean).afterPropertiesSet();
                        return null;
                    }, getAccessControlContext());
                }
                catch (PrivilegedActionException pae) {
                    throw pae.getException();
                }
            }
            else {
                // 回调bean自定义的afterPropertiesSet方法
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        // 初始化 当前bean不为空
        if (mbd != null && bean.getClass() != NullBean.class) {
            // spring启动时解析的init-method方法
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.isExternallyManagedInitMethod(initMethodName)) {
                // 通过反射触发初始化方法
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }
  1. 初始化后置处理
    关于后置处理器就不再多做介绍,可以参考一下初始化前置处理,需要注意的点一样

如果看到这里,恭喜你spring Ioc容器的源码已经读完,spring的源码需要反复读才能真正都理解,每读一遍源码都会有新的收获新的见解,鼓励大家往回看,多被锤几遍。毕竟这可是JAVA最牛逼的架构,说是码农的智慧结晶也一点不过分!

相关文章

网友评论

    本文标题:spring源码日记17: 初始化

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