首页 > 编程语言 >【Spring IOC】【六】容器源码解析- initializeBean剩下的初始化工作

【Spring IOC】【六】容器源码解析- initializeBean剩下的初始化工作

时间:2023-02-18 22:44:07浏览次数:39  
标签:mbd Spring beanName bean 源码 null IOC afterPropertiesSet wrappedBean

1  前言

我们的bean经过的应该就剩下initializeBean这个方法,这个方法对上一步的populateBean属性填充完,做最后的剩余工作,这个里边的东西相比之前几个那可真是让人看着开心加愉快了,我们来看。

2  源码分析

2.1  方法通读

看一下 initializeBean 方法的源码:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
        if (System.getSecurityManager() != null) {
            AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
                invokeAwareMethods(beanName, bean);
                return null;
            }, getAccessControlContext());
        }
        else {
            // aware后缀结尾的类大家应该很熟悉吧
            // 若 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;
    }

以上就是 initializeBean 方法的逻辑。该方法做了如下几件事情:

  1. 检测 bean 是否实现了 *Aware 类型接口,若实现,则向 bean 中注入相应的对象
  2. 执行 bean 初始化前置操作
  3. 执行初始化操作
  4. 执行 bean 初始化后置操作

2.2  invokeAwareMethods

根据 bean 所实现的 Aware 的类型,向 bean 中注入不同类型的对象。

private void invokeAwareMethods(String beanName, 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.3  invokeInitMethods

做了两件事,1、就是你的bean如果实现了InitializingBean,会调用你的afterPropertiesSet方法做你的东西。 2、执行你bean的init-method方法。

init-method可以配在xml也可以用注解像这样:@Bean(initMethod = "init", destroyMethod = "destroy")

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

        boolean isInitializingBean = (bean instanceof InitializingBean);
        if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("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 {
                // 调用afterPropertiesSet
                ((InitializingBean) bean).afterPropertiesSet();
            }
        }

        if (mbd != null && bean.getClass() != NullBean.class) {
            String initMethodName = mbd.getInitMethodName();
            if (StringUtils.hasLength(initMethodName) &&
                    !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
                    !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
                // 调用用户自定义的方法
                invokeCustomInitMethod(beanName, bean, mbd);
            }
        }
    }

3  小结

这个方法还是比较舒服的,不会拖家带口的带出来一堆东西,Spring很多地方都给我们留了扩展,Spring就是给我们管理bean、增强bean的,管理也就是管理bean的生命周期,增强就是在创建的过程中,创建对应的代理对象出来。我们看完IOC 对于bean的几个创建过程中的方法也是有了大概的认识 比如getBean、doGetBean、createBean、doCreateBean、createBeanInstance、populateBean、intializeBean,中间涉及的缓存、代理、依赖解析、属性解析等等,好多细节也是还没太明白,还是要多看,多运用到自己的业务代码中去,哪里有理解不对的还望指正,今天就到这里了。

标签:mbd,Spring,beanName,bean,源码,null,IOC,afterPropertiesSet,wrappedBean
From: https://www.cnblogs.com/kukuxjx/p/17133820.html

相关文章

  • Swift源码转PlantUML
    brewinstallswiftplantuml https://github.com/MarcoEidinger/SwiftPlantUML  在文件目录下执行swiftplantuml./*.swift 然后就会打开 https:......
  • SSM整合02 - Spring整合SpringMVC
    Spring与SpringMVC分别各自管理Service层和Controller层spring.xml<?xmlversion="1.0"encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/be......
  • SSM整合03 - Spring整合MyBatis
    MyBatis核心配置文件mybatis-config.xmlSpring整合MyBatis的核心点:将MyBatis核心配置文件中的配置尽可能写入Spring的配置文件中原MyBatis核心配置文件mybatis-config.......
  • Spring事务(Transaction)管理高级篇一栈式解决开发中遇到的事务问题
    Spring是目前Java开发中最流行的框架了,它的事务管理我们在开发中常常的用到,但是很多人不理解它事务的原理,导致开发中遇到事务方面的问题往往都要用很长的时间才能解决,下面......
  • 2.ioc注入
    setter注入需要无参构造创建对象然后通过set方法赋值 required=true就是说这个bean必须在xml里配置了,不然就抛出异常thebeanpropertymustbepopulatedatconfig......
  • springcloud day01
    单体架构:业务所有功能都在一个项目中开发,打成一个包部署优点是架构简单部署成本低缺点是耦合度高分布式架构:根据业务功能对系统做拆分,每个业务功能模块作为一个独立的......
  • Spring boot Gateway 使用Nacos注册中心No servers available for service
    主要原因是Gateway没有发现合适的服务ReactiveCompositeDiscoveryClient.discoveryClients中如果只有一个或只有SimpleReactiveDiscoveryClient(没有合适服务就会使用这......
  • 参考iictools源码实现HP203b气压温度传感器读取
    参考i2ctools源码实现HP203B气压温度传感器读取由于开发的设备中要用到HP203B气压温度传感器,此设备要用到i2c协议进行数据的读取,我将以韦东山老师课程为指引,参考经典的i2c......
  • SpringMVC源码(九):无异常View视图解析
    在MVC请求流程中,处理Controller控制器逻辑后获取到的ModelAndView对象并不能直接返回到浏览器,需要通过对ModelAndView中的View属性做解析获取视图,并用Model属性中的数......
  • Error:(3, 32) java: 无法访问org.springframework.boot.SpringApplication,错误的类文
    启动Springboot项目报错 这是Springboot的版本和Java的版本不对应导致的。 Springboot2.0以上版本最低需要java8支持;Springboot3.0以上的版本最低需要java17支持!参......