zoukankan      html  css  js  c++  java
  • bean 实例化原理解析

    bean的生命周期主要有如下几个歩奏

    • 创建bean实例
    • 给实例化的bean填充属性
    • 初始化bean
    • 通过IOC容器使用bean
    • 容器关闭时候销毁bean

    在实例化bean之前在BeanDefinition里头已经有了所有需要实例化时用到的元数据,接下来spring 只需要选择合适的实例化方法以及策略即可。实例化方法有两大类分别是工厂方法构造方法实例化,后者是最常见的。

    两种实例化方法

    • 工厂方法
    • 构造方法

    启动容器时会实例化所有注册的bean,对于所有单例非懒加载的bean来说当从容器里获取bean(getBean(String name))的时候不会触发,实例化阶段,而是直接从缓存获取已准备好的bean,而生成bean的时机则是下面这行代码运行时触发的

    @Test
    public void testBeanInstance(){        
        // 启动容器
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
    }

    一 使用工厂方法实例化(很少用)

    1.静态工厂方法
    public class FactoryInstance {    
        public FactoryInstance() {
            System.out.println("instance by FactoryInstance");
        }
    }
    
    public class MyBeanFactory {   
    public static FactoryInstance getInstanceStatic(){
    return new FactoryInstance(); } }
    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="factoryInstance" class="spring.service.instance.MyBeanFactory" factory-method="getInstanceStatic"/> </beans>

      

    输出结果为:

    instance by FactoryInstance
    

      

    2.实例工厂方法

    public class MyBeanFactory {    
    
        /**
         * 实例工厂创建bean实例
         *
         * @return
         */
        public FactoryInstance getInstance() {       
         return new FactoryInstance(); } }

      

     
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
           
        <!-- 工厂实例 -- >   
        <bean id="myBeanFactory" class="MyBeanFactory"/>
        <bean id="factoryInstance" factory-bean="myBeanFactory" factory-method="getInstance"/>
        
    </beans>
     

    输出结果为:

    instance by FactoryInstance
    

      

    二 使用构造函数实例化(无参构造函数 & 有参构造函数)

    1.无参构造函数实例化(默认的)
    public class ConstructorInstance {    
        public ConstructorInstance() {
            System.out.println("ConstructorInstance none args");
        } 
    }
    

      

     
    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
        
        <bean id="constructorInstance" class="spring.service.instance.ConstructorInstance"/>
        
    </beans>
     

    输出结果为:

    ConstructorInstance none args

    1.有参构造函数实例化
    public class ConstructorInstance {    
        private String name;    
        public ConstructorInstance(String name) {
            System.out.println("ConstructorInstance with args");        
            this.name = name;
        }    
        
        public String getName() {        
            return name;
        }    
        
        public void setName(String name) {        
            this.name = name;
        }
     
    }
     
    <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
           
       <bean id="constructorInstance" class="spring.service.instance.ConstructorInstance">
            <constructor-arg index="0" name="name" value="test constructor with args"/>
       </bean>
        
    </beans>
     

    输出结果为:

    ConstructorInstance with args

    源码阅读

    下面这段是 有关spring bean生命周期的代码,也是我们本次要讨论的bean 实例化的入口。

    doCreateBean方法具体实现在doCreateBeanAbstractAutowireCapableBeanFactory类,感兴趣的朋友可以进去看看调用链。

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
      //第一步 创建bean实例 还未进行属性填充和各种特性的初始化
      BeanWrapper instanceWrapper = null;
      if (instanceWrapper == null) {
       instanceWrapper = createBeanInstance(beanName, mbd, args);
      }
      final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
      Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
    
      Object exposedObject = bean;
      try {
          // 第二步 进行属性填充
       populateBean(beanName, mbd, instanceWrapper);
       if (exposedObject != null) {
           // 第三步 初始化bean 执行初始化方法
        exposedObject = initializeBean(beanName, exposedObject, mbd);
       }
      }catch (Throwable ex) {
          //  抛相应的异常
      }
    
      // Register bean as disposable.
      try {
       registerDisposableBeanIfNecessary(beanName, bean, mbd);
      }catch (BeanDefinitionValidationException ex) {
       throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
      }
      return exposedObject;
    }
     

    我们这里只需关注第一步创建bean实例的流程即可

    instanceWrapper = createBeanInstance(beanName, mbd, args);
    
    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
      // Make sure bean class is actually resolved at this point.
      Class<?> beanClass = resolveBeanClass(mbd, beanName);
            // 使用工厂方法进行实例化
      if (mbd.getFactoryMethodName() != null)  {
       return instantiateUsingFactoryMethod(beanName, mbd, args);
      }
      // Need to determine the constructor...
      Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
      // 使用带参构造函数初始化
      if (ctors != null ||
        mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
        mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
           
       return autowireConstructor(beanName, mbd, ctors, args);
      }
    
      // 默认实例化方式 无参构造实例化
      return instantiateBean(beanName, mbd);
    }

    上面代码就是spring 实现bean实例创建的核心代码。这一步主要根据BeanDefinition里的元数据定义决定使用哪种实例化方法,主要有下面三种:

    • instantiateUsingFactoryMethod 工厂方法实例化的具体实现

    • autowireConstructor 有参构造函数实例化的具体实现

    • instantiateBean 默认实例化具体实现(无参构造函数)

    实例化策略(cglib or 反射)

    工厂方法的实例化手段没有选择策略直接用了发射实现的
    实例化策略都是对于构造函数实例化而言的

    上面说到的两构造函数实例化方法不管是哪一种都会选一个实例化策略进行,到底选哪一种策略也是根据BeanDefinition里的定义决定的。

    beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

    上面这一行代码就是选择实例化策略的代码,进入到上面两种方法的实现之后发现都有这段代码。

    下面选一个instantiateBean的实现来介绍

    protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
      try {
       Object beanInstance;
       final BeanFactory parent = this;
       if (System.getSecurityManager() != null) {
        beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
         @Override
         public Object run() {
          return getInstantiationStrategy().instantiate(mbd, beanName, parent);
         }
        }, getAccessControlContext());
       }
       else {
           // 在这里选择一种策略进行实例化
        beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
       }
       BeanWrapper bw = new BeanWrapperImpl(beanInstance);
       initBeanWrapper(bw);
       return bw;
      }
      catch (Throwable ex) {
       throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
      }
    }
     

    选择使用反射还是cglib

    先判断如果beanDefinition.getMethodOverrides()为空也就是用户没有使用replace或者lookup的配置方法,那么直接使用反射的方式,简单快捷,但是如果使用了这两个特性,在直接使用反射的方式创建实例就不妥了,因为需要将这两个配置提供的功能切入进去,所以就必须要使用动态代理的方式将包含两个特性所对应的逻辑的拦截增强器设置进去,这样才可以保证在调用方法的时候会被相应的拦截器增强,返回值为包含拦截器的代理实例。---引用自《spring 源码深度剖析》这本书

    <bean id="constructorInstance" class="spring.service.instance.ConstructorInstance" >        <lookup-method name="getName" bean="xxx"/>
        <replaced-method name="getName" replacer="yyy"/>
    </bean>
     

    如果使用了lookup或者replaced的配置的话会使用cglib,否则直接使用反射。
    具体lookup-methodreplaced-method的用法可以查阅相关资料。

    public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
        // Don't override the class with CGLIB if no overrides.
        if (bd.getMethodOverrides().isEmpty()) {
          constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
          return BeanUtils.instantiateClass(constructorToUse);
        }else {
          // Must generate CGLIB subclass.
          return instantiateWithMethodInjection(bd, beanName, owner);
        }
    }
    【做一朵向日葵,面朝太阳,心纳阳光。心,只要有了充盈的阳光,就不再那么的冰;人,也就不再那么的冷;拥有了热度,心也跟着有了温度。】
  • 相关阅读:
    hadoop:WordCount问题总结
    .mata. _root_ (转)
    Hbase笔记:批量导入
    Hbase笔记4 java操作Hbase
    wget
    中国大陆开源镜像站汇总
    全键盘操作Windows
    linux下实用命令
    /dev/null和/dev/zero的区别
    Windows xp下安装sql server2005所碰到的一些问题及解决方法
  • 原文地址:https://www.cnblogs.com/walkingcamel/p/13384665.html
Copyright © 2011-2022 走看看