天天用 Spring,bean 实例化原理你懂吗?
发布日期:2021-06-30 12:50:33 浏览次数:2 分类:技术文章

本文共 5965 字,大约阅读时间需要 19 分钟。

Java技术栈

www.javastack.cn

关注阅读更多优质文章

来源:小小木的博客

www.cnblogs.com/wyc1994666/p/10650480.html

本次主要想写spring bean的实例化相关的内容。创建spring bean 实例是spring bean 生命周期的第一阶段。

  • 初始化bean

如我们在xml里定义的 <bean id="xxx" class="yyy"/> 以及用注解标识的bean都是通过默认实例化方法实例化的。

  • 两种实例化方法(构造函数 和 工厂方法)

  • 源码阅读

  • 实例化策略(cglib or 反射)

两种实例化方

使用适当的实例化方法为指定的bean创建新实例:工厂方法,构造函数实例化。

代码演示

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

@Testpublic 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();    }}
     

输出结果为:

instance by FactoryInstance

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

输出结果为:

instance by FactoryInstance

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

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

输出结果为:

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

输出结果为:

ConstructorInstance with args

源码阅读

下面这段是 有关spring bean生命周期的代码,也是我们本次要讨论的bean 实例化的入口。推荐看下。关注Java技术栈公众号在后台回复Spring阅读更多Spring系列教程。

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() {     @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

        
    

如果使用了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);    }}

由于篇幅省略了部分代码。

最近热文:

1、

2、

3、

4、

5、

6、

7、

8、

9、

10、

扫码关注Java技术栈公众号阅读更多干货。

点击「」获取面试题大全~

转载地址:https://javastack.blog.csdn.net/article/details/107602743 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:从 Java 9 开始,Java 就华丽的转身为微服务了…
下一篇:Spring Boot 太狠了,一次性发布了 3 个版本!

发表评论

最新留言

能坚持,总会有不一样的收获!
[***.219.124.196]2024年04月20日 13时24分04秒