bean 实例化原理解析

Posted walkingcamel

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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);
    }
}

 

以上是关于bean 实例化原理解析的主要内容,如果未能解决你的问题,请参考以下文章

这一次搞懂 Spring 的 Bean 实例化原理

Spring框架系列 - Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等)

Spring源码解析Bean的实例化和依赖注入

Spring IOC 容器源码分析 - getBean调用方法解析 -- 实例化 Bean 对象

Java 中解析 XML 生成 Bean 实例,用啥方式效率最高?

Spring加载Bean流程解析