Spring 框架源码解读4

作者: 想54256 | 来源:发表于2020-04-16 16:38 被阅读0次

    title: Spring 框架源码解读4
    date: 2020/04/16 13:56


    本节内容 & 思考题

    Spring 创建对象的几种方式?

    1、空参构造(@Component)

    <bean id="apple" class="cn.x5456.Apple" />
    

    2、静态工厂方法(了解)

    <bean id="apple" class="cn.x5456.Apple" factory-method="createApple" />
    
    public Apple createApple() {
        return new Apple();
    }
    

    3、实例工厂(@Bean)

    <bean name="appleFactory" class="cn.x5456.AppleFactory" />
    
    <bean id="apple" factory-bean="appleFactory" factory-method="createApple" />
    

    本节将会介绍第一种和第三种配置的实现方式(不会介绍注解实现)

    注:本教程暂不考虑有参构造(包括自动注入的有参构造),因为其实都是差不多的。


    装饰者模式:BeanWrapper

    策略模式:实例化对象的方式

    新增工厂方法创建对象

    1、BD 新增字段

    // 工厂类注册到容器中的 beanName
    private String factoryBean;
    
    // 工厂方法名
    private String factoryMethod;
    

    2、修改 ABF

    /**
     * 根据 bd 创建对象
     * <p>
     * 1)创建bean 日后需要对有参构造进行扩展
     * 2)注入属性  日后新增
     * 3)执行初始化操作
     * 4)注册销毁的处理
     */
    private Object createBean(BeanDefinition beanDefinition) {
    
        // 1、创建 bean
        Object bean = this.createBeanInstance(beanDefinition);
    
        // 2、注入属性 todo
    
        // 3、执行初始化操作(在 Spring 中是直接调用的该类中的 initializeBean 方法,为了让他面向对象一点,我给他抽出一个类)
        InitializeBeanAdapter initializeBeanAdapter = new InitializeBeanAdapter(bean, beanDefinition);
        initializeBeanAdapter.afterPropertiesSet();
    
        // 4、注册销毁的处理
        if (this.check(beanDefinition, bean)) {
            registry.registerDisposableBean(beanDefinition.getName(), new DisposableBeanAdapter(bean, beanDefinition));
        }
    
        return bean;
    }
    
    /**
        * 分两种情况
        * <p>
        * 1. 工厂方法(无参版)
        * 2. 空参构造
        */
    private Object createBeanInstance(BeanDefinition beanDefinition) {
        if (ObjectUtil.isNotNull(beanDefinition.getFactoryBean())) {
            // 从容器中找到工厂对象
            Object bean = this.getBean(beanDefinition.getFactoryBean());
            if (ObjectUtil.isNull(bean)) {
                throw new RuntimeException("工厂 bean 不存在!");
            }
            return ReflectUtil.invoke(bean, beanDefinition.getFactoryMethod());
        }
    
        return ReflectUtil.newInstance(beanDefinition.getClassName());
    }
    

    3、测试

    public class TestJsonBF {
        public static void main(String[] args) {
            ListableBeanFactory bf = new JsonBeanFactoryImpl("/Users/x5456/IdeaProjects/Summer/src/test/resources/apple.json");
            Apple apple = bf.getBean("apple", Apple.class);
            System.out.println(apple);
        }
    }
    
    apple.json
    
    [
      {
        "name": "appleFactory",
        "className": "cn.x5456.summer.AppleFactory"
      },
      {
        "name": "apple",
        "factoryBean": "appleFactory",
        "factoryMethod": "createApple"
      }
    ]
    
    public class AppleFactory {
    
        public Apple createApple() {
            Apple apple = new Apple();
            apple.setName("黄元帅");
            return apple;
        }
    }
    

    思考:配置文件中把 factory 放到 bean 的后面会不会报错吗?

    不会,因为 BF 先把所有的 BD 读到 BDMap 中,然后 AP 再一个一个 get,不管先后顺序,总能获取到对象;这也是 BF 懒加载的好处。

    Spring 0.9

    Spring 0.9 只有根据构造创建的,所以没有参考 0.9 版本

    Spring 5.0

    创建 Bean 部分代码

    // AbstractAutowireCapableBeanFactory.java
    
    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
        // Make sure bean class is actually resolved at this point.
        Class<?> beanClass = resolveBeanClass(mbd, beanName);
    
        // 判断一个类的访问权限, Spring默认情况下对于非public的类是不允许访问的
        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
            throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
        }
    
        // 不重要,跳过
        Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
        if (instanceSupplier != null) {
            return obtainFromSupplier(instanceSupplier, beanName);
        }
    
    
        // 这里是处理工厂方法的,比如你的类里面设置了一个工厂方法返回一个对象,比如:
        //  @Bean
        //  public static Object query() {
        //    return new Ant();
        //  }
        //  xml配置如下:
        //  <bean id="user" class="com.ant.context.service.UserService" factory-method="query">
        //
        //  </bean>
        //  那么这个query方法就会在这里处理,这里spring就会给你构建一个新的对象Ant,然后放到实例容器中去
        if (mbd.getFactoryMethodName() != null)  {
            return instantiateUsingFactoryMethod(beanName, mbd, args);
        }
    
    
        // 重新创建同一个bean时的快捷方式(Shortcut)...
        boolean resolved = false;
        boolean autowireNecessary = false;
        if (args == null) {
            synchronized (mbd.constructorArgumentLock) {
                if (mbd.resolvedConstructorOrFactoryMethod != null) {
                    // 如果已经解析了构造方法的参数,则直接把这个属性设置为true
                    // 则后面的if判断方法则会直接进入,而不会去执行后续的方法
                    resolved = true;
                    // 如果已经解析了构造方法参数, 则必须要通过一个带参构造方法来实例
                    autowireNecessary = mbd.constructorArgumentsResolved;
                }
            }
        }
    
        // 判断是否已经解析过了构造函数
        if (resolved) {
            if (autowireNecessary) {
                // 通过构造方法自动装配的方式构造 bean 对象
                return autowireConstructor(beanName, mbd, null, null);
            }
            else {
                // 通过默认的无参构造方法进行
                return instantiateBean(beanName, mbd);
            }
        }
    
        // 这个方法比较重要,spring通过判断我们的bean对象的构造方法的数量和结构,
        // 来判断我们在实例化对象的时候,到底要使用哪个构造函数去对我们的bean进行实例化
        // 如果我们的bean只有一个默认的无参构造方法,则会返回null
        // Candidate constructors for autowiring?
        Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    
        if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
            // 如果我们的bean自己有一个特殊的构造方法,则会执行这个方法,这个方法比较复杂,也比较重要
            return autowireConstructor(beanName, mbd, ctors, args);
        }
    
        // 如果bean只有一个默认的无参构造方法,则使用下面的方法去实例化我们的bean对象
        // No special handling: simply use no-arg constructor.
        return instantiateBean(beanName, mbd);
    }
    

    1)工厂方法方式

    image image
    1. 从工厂类中找到用户配置的那个方法
    2. 找到那个方法需要依赖注入的参数
    3. 如果没找到工厂方法则抛出异常,检查返回值是不是 void
    4. 和下面一样,选个策略创建对象
    有参版本
    <?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">
    
        <bean name="appleFactory" class="com.dist.ars.aop.AppleFactory" />
    
        <bean id="apple" factory-bean="appleFactory" factory-method="createApple">
            <constructor-arg ref="seed" />
        </bean>
    
        <bean name="seed" class="com.dist.ars.aop.Seed" />
    </beans>
    

    2)空参构造方式

    image image image image

    这就是创建对象的流程,再往下就是 DI 了,也是使用 BeanWrapper 的目的。

    相关文章

      网友评论

        本文标题:Spring 框架源码解读4

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