精华内容
下载资源
问答
  • 行业分类-化学冶金-一种产品自动装配装置及自动装配生产线.zip
  • 行业分类-作业装置-一种牙刷自动装配系统和牙刷自动装配方法.zip
  • Spring实现自动装配

    2018-03-25 19:17:07
    本项目为Java项目,使用Spring实现自动装配,根据类型方式实现自动装配。适合初学者了解Spring不同装配方式。
  • SpringBoot——自动装配原理(干货)

    万次阅读 多人点赞 2020-10-31 16:26:39
    SpringBoot——自动装配原理(干货) 在编写SpringBoot项目时,@SpringBootApplication是最常见的注解了,我们可以看一下源代码: 这里面包含了@SpringBootConfiguration,@EnableAutoConfiguration,@...

    深入理解SpringBoot——自动装配原理(干货)


    面试官:谈谈你对Springboot自动装配的了解叭

    回答:

    • 在编写SpringBoot项目时,@SpringBootApplication是最常见的注解了,我们可以看一下里面的源代码:

    在这里插入图片描述

    • 这里面包含了:
    1. @SpringBootConfiguration
      • 我们点进去通过源码得知他是一个@Configuration,所以也就是对spring原生注解的封装
    2. @EnableAutoConfiguration
    3. @ComponentScan
      • 默认扫描的是与该类同级的类或者同级包下的所有类,是spring的原生注解之一

    @EnableAutoConfiguration重头戏——自动装配核心

    • 一旦加上此注解,那么将会开启自动装配功能,简单点讲,Spring会试图在自己的classpath(类路径)下找到所有配置的Bean然后进行装配。
    • 装配Bean时,会根据若干个(Conditional)定制规则来进行初始化。我们看一下它的源码:

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    • 该接口主要是为了导入@Configuration的配置项,而DeferredImportSelector是延期导入,当所有的@Configuration都处理过后才会执行。
    • 回过头来我们看一下AutoConfigurationImportSelector的自动配备核心方法 selectImport
    //自动装配的方法
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
       if (!isEnabled(annotationMetadata)) { //判断是否自动装配
          return NO_IMPORTS;
       }
       AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
       return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    }
    
    protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
       if (!isEnabled(annotationMetadata)) {
          return EMPTY_ENTRY;
       }
       //获取所有元数据信息
       AnnotationAttributes attributes = getAttributes(annotationMetadata);
       //获取所有加载bean的条件配置
       List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
       //过滤并删除掉重复的bean
       configurations = removeDuplicates(configurations);
       Set<String> exclusions = getExclusions(annotationMetadata, attributes);
       checkExcludedClasses(configurations, exclusions);
       configurations.removeAll(exclusions);
       configurations = getConfigurationClassFilter().filter(configurations);
       fireAutoConfigurationImportEvents(configurations, exclusions);
       return new AutoConfigurationEntry(configurations, exclusions);
    }
    • 该方法刚开始会先判断是否进行自动装配,而后会从META-INF/spring-autoconfigure-metadata.properties读取元数据与元数据的相关属性,紧接着会调用getCandidateConfigurations方法:
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
       List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
             getBeanClassLoader());
       Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
             + "are using a custom packaging, make sure that file is correct.");
       return configurations;
    }
    • 在这里又遇到我们的老熟人了–SpringFactoryiesLoader, 它会读取META-INF/spring.factories下的EnableAutoConfiguration的配置,紧接着在进行排除与过滤,进而得到需要装配的类。最后让所有配置在META-INF/spring.factories下的AutoConfigurationImportListener执行AutoConfigurationImportEvent事件,代码如下:
    private void fireAutoConfigurationImportEvents(List<String> configurations,
                Set<String> exclusions) {
            List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
            if (!listeners.isEmpty()) {
                AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this,
                        configurations, exclusions);
                for (AutoConfigurationImportListener listener : listeners) {
                    invokeAwareMethods(listener);
                    listener.onAutoConfigurationImportEvent(event);
                }
            }
        }
    
        protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
            return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class,
                    this.beanClassLoader);
        }

    总结:

    自动装配还是利用了SpringFactoriesLoader来加载META-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,它会经过exclude和filter等操作,最终确定要装配的类

    展开全文
  • 什么叫自动装配: Spring提供了XMl配置装配我们的bean属性,但是有时候装配太过繁琐,为了简化装配XML配置的节点提供了autowire 属性配置自动装配,只需要告诉Spring容器你的装配方式,他可以完成属性自动注入。 ...

    什么叫自动装配:

    Spring提供了XMl配置装配我们的bean属性,但是有时候装配太过繁琐,为了简化装配XML配置的节点提供了autowire 属性配置自动装配,只需要告诉Spring容器你的装配方式,他可以完成属性自动注入。

    Spring提供的自动装配的方式:
    1丶no - 不自动装配
    2丶byName - 根据名称进行装配
    3丶byType - 根据类型进行装配,找到两个一样的Type会报错
    4丶constructor - 根据构造函数进行装配

    测试我就不测试了,今天我们来尝试使用注解配置Bean下开启自动装配。

    首先介绍一下注解方式开启装配用到的工具:BeanFactoryPostProcessor

    Spring给我们提供了一个供开发人员扩展Spring的接口---->BeanFactoryPostProcessor
    工程中,我们配置的Bean,他有相应的属性,这些属性被扫描后会有一个BeanDefition对象来描述这个bean定义,Spring也是通过这个BeanDefinition图纸来实例化我们的bean。而我们就可以通过BeanFactoryPostProcessor这个接口来完成对BeanDefinition里bean描述的修改。
    自动装配模型也属于beanDefition中的一个bean描述信息,如下所示:

    public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable {
        public static final int AUTOWIRE_NO = 0;
        public static final int AUTOWIRE_BY_NAME = 1;
        public static final int AUTOWIRE_BY_TYPE = 2;
        public static final int AUTOWIRE_CONSTRUCTOR = 3;
    
    XXXX
    XXXX
    }
    

    实验开始:

    ClassA:

    @Component
    public class A {
    
        B b;
        public A() {
            System.out.println("A构造");
        }
        public void getB(){
            System.out.println(b);
        }
        public void setB(B b) {
            this.b = b;
        }
    }
    

    BeanFactoryPostProcessor:

    public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
            GenericBeanDefinition beanDefinition  = (GenericBeanDefinition) configurableListableBeanFactory.getBeanDefinition("a");
            System.out.println(beanDefinition.getAutowireMode());
    //        beanDefinition.setAutowireMode(2);
        }
    }
    

    把 beanDefinition.setAutowireMode(2);注释掉之后,容器初始化打印:
    第一个为默认自动装配模型为0,第三个为打印的注入A中的B属性对象为null

    0
    A构造
    null
    

    这个时候我们把把 beanDefinition.setAutowireMode(2);注释去掉,重启容器
    启动类:
    ``
    public static void main(String[] args) {
    AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
    annotationConfigApplicationContext.getBean(A.class).getB();
    }
    打印如下

    ``
    0
    A构造
    com.gjs.test.B@2c34f934
    

    B已经成功被注入进来,大功告成

    展开全文
  • 【Spring】Bean的自动装配

    万次阅读 2021-05-12 16:24:26
    自动装配是Spring满足bean依赖的一种方式! Spring会在上下文中自动寻找,并自动给bean装配属性! 在Spring中有三种装配的方式: 在xml中显示的配置 在Java中显示配置 隐式的自动装配bean【重要】 1. 显示...

    自动装配是Spring满足bean依赖的一种方式!

    Spring会在上下文中自动寻找,并自动给bean装配属性!

    在Spring中有三种装配的方式:

    • 在xml中显示的配置
    • 在Java中显示配置
    • 隐式的自动装配bean【重要】

    1. 显示装配。

    前面博客写的显示方法。

    2. 自动装配

    • byName:会自动在容器上下文中查找,和自己对象set方法的值对应的bean-id。

    必须保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法值一致!

        <bean id="people" class="com.company.org.People" autowire="byName">
            <property name="name" value="牧心"/>
        </bean>
    • byType:会自动在容器上下文中查找,和自己对象属性类型相同的的bean。(必须保证该类型的对象只有一个

    必须保证所有bean的class唯一,并且这个bean需要和自动注入的属性一致!

        <bean id="people" class="com.company.org.People" autowire="byType">
            <property name="name" value="牧心"/>
        </bean>
    • 使用注解实现自动装配

    JDK1.5开始支持注解;Spring2.5开始支持注解。

    要使用注解须知:

    1. 导入约束。

    2. 配置注解的支持。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd">
    
        <!-- 配置注解的支持 -->
        <context:annotation-config/>
    
    </beans>

    @Autowired

    直接在属性上使用。(此时可以省略set方法,前提是这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byName)

    默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它required属性为false。

        @Autowired
        private Cat cat;
        @Autowired
        private Dog dog;

    PS:@Nullable:字段标记了这个注解,说明这个字段可以为null。如:

        @Autowired(required = false)
        private Cat cat;

    @Qualifier(value="xxx"):如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解[@Autowired]完成的时候,我们可以使用Qualifier(value="xxx")去配置@Autowired的使用,指定一个唯一的bean对象注入!

        @Autowired
        @Qualifier(value = "dog")
        private Dog dog;

    @Resource / @Resource(name  ="xxx") 。@Resource有两个重要的属性:name和type

     

    小结,@Resource 和 @Autowired的区别:

    • 都是用来自动装配的,都可以放在属性字段上。
    • @Autowired只通过byType的方式实现。
    • @Resource默认通过baName的方式实现,如果找不到名字,则通过byType实现。如果两个都找不到,就报错!Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。
    • 执行顺序不同:@Autowired通过byType的方式实现。@Resource默认通过baName的方式实现。
    展开全文
  • springboot自动装配笔记

    2020-01-16 02:23:35
    springboot自动装配的过程解析...
  • 滚子链自动装配设计.docx
  • SpringBoot自动装配原理,这一篇就够了!

    千次阅读 多人点赞 2020-05-08 20:41:41
    学习SpringBoot,绝对避不开自动装配这个概念,这也是SpringBoot的关键之一 本人也是SpringBoot的初学者,下面的一些总结都是结合个人理解和实践得出的,如果有错误或者疏漏,请一定一定一定(不是欢迎,是一定)帮...

    学习SpringBoot,绝对避不开自动装配这个概念,这也是SpringBoot的关键之一

    本人也是SpringBoot的初学者,下面的一些总结都是结合个人理解和实践得出的,如果有错误或者疏漏,请一定一定一定(不是欢迎,是一定)帮我指出,在评论区回复即可,一起学习!

    篇幅较长,希望你可以有耐心.

    如果只关心SpringBoot装配过程,可以直接跳到第7部分

    想要理解spring自动装配,需要明确两个含义:

    • 装配,装配什么?

    • 自动,怎么自动?



    1. Warm up

    在开始之前,让我们先来看点简单的开胃菜:spring中bean注入的三种形式

    首先我们先来一个Person类,这里为了篇幅长度考虑使用了lombok

    如果你不知道lombok是什么,那就最好不要知道,加了几个注解之后我的pojo类Person就完成了

    /**
     * @author dzzhyk
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Person {
        private String name;
        private Integer age;
        private Boolean sex;
    }
    

    在Spring中(不是Spring Boot),要实现bean的注入,我们有3种注入方式:


    1.1 setter注入

    这是最基本的注入方式

    首先我们创建applicationContext.xml文件,在里面加入:

    <!-- 手动配置bean对象 -->
    <bean id="person" class="pojo.Person">
        <property name="name" value="dzzhyk"/>
        <property name="age" value="20"/>
        <property name="sex" value="true"/>
    </bean>
    

    这里使用property为bean对象赋值

    紧接着我们会在test包下写一个version1.TestVersion1类

    /**
     * 第一种bean注入实现方式 - 在xml文件中直接配置属性
     */
    public class TestVersion1 {
        @Test
        public void test(){
            ApplicationContext ca = new 		ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = ca.getBean("person", Person.class);
            System.out.println(person);
        }
    }
    

    这里我使用了ClassPathXmlApplicationContext来加载spring配置文件并且读取其中定义的bean,然后使用getBean方法使用id和类来获取这个Person的Bean对象,结果成功输出:

    Person(name=dzzhyk, age=20, sex=true)
    

    1.2 构造器注入

    接下来是使用构造器注入,我们需要更改applicationContext.xml文件中的property为construct-arg

    <!-- 使用构造器 -->
    <bean id="person" class="pojo.Person">
        <constructor-arg index="0" type="java.lang.String" value="dzzhyk" />
        <constructor-arg index="1" type="java.lang.Integer" value="20"/>
        <constructor-arg index="2" type="java.lang.Boolean" value="true"/>
    </bean>
    

    version2.TestVersion2内容不变:

    public class TestVersion2 {
        @Test
        public void test(){
            ApplicationContext ca = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = ca.getBean("person", Person.class);
            System.out.println(person);
        }
    }
    

    依然正常输出结果:

    Person(name=dzzhyk, age=20, sex=true)
    

    1.3 属性注入

    使用注解方式的属性注入Bean是比较优雅的做法

    首先我们需要在applicationContext.xml中开启注解支持和自动包扫描:

    <context:annotation-config />
    <context:component-scan base-package="pojo"/>
    

    在pojo类中对Person类加上@Component注解,将其标记为组件,并且使用@Value注解为各属性赋初值

    @Component
    public class Person {
        
        @Value("dzzhyk")
        private String name;
        @Value("20")
        private Integer age;
        @Value("true")
        private Boolean sex;
    }
    

    然后添加新的测试类version3.TestVersion3

    public class TestVersion3 {
        @Test
        public void test(){
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = ac.getBean("person", Person.class);
            System.out.println(person);
        }
    }
    

    运行也可以得到如下结果:

    Person(name=dzzhyk, age=20, sex=true)
    


    2. Warm up again

    什么?还有什么?接下来我们来聊聊Spring的两种配置方式:基于XML的配置和基于JavaConfig类的配置方式,这对于理解SpringBoot的自动装配原理是非常重要的。

    首先我们在Person的基础上再创建几个pojo类:这个Person有Car、有Dog

    public class Car {
        private String brand;
        private Integer price;
    }
    
    public class Dog {
        private String name;
        private Integer age;
    }
    
    public class Person {
        private String name;
        private Integer age;
        private Boolean sex;
        private Dog dog;
        private Car car;
    }
    

    2.1 基于XML的配置

    接下来让我们尝试使用XML的配置方式来为一个Person注入

    <bean id="person" class="pojo.Person">
        <property name="name" value="dzzhyk"/>
        <property name="age" value="20"/>
        <property name="sex" value="true"/>
        <property name="dog" ref="dog"/>
        <property name="car" ref="car"/>
    </bean>
    
    <bean id="dog" class="pojo.Dog">
        <property name="name" value="旺财"/>
        <property name="age" value="5" />
    </bean>
    
    <bean id="car" class="pojo.Car">
        <property name="brand" value="奥迪双钻"/>
        <property name="price" value="100000"/>
    </bean>
    

    然后跟普通的Bean注入一样,使用ClassPathXmlApplicationContext来加载配置文件,然后获取Bean

    /**
     * 使用XML配置
     */
    public class TestVersion1 {
        @Test
        public void test(){
            ClassPathXmlApplicationContext ca = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = ca.getBean("person", Person.class);
            System.out.println(person);
        }
    }
    

    输出结果如下:

    Person(name=dzzhyk, age=20, sex=true, dog=Dog(name=旺财, age=5), car=Car(brand=奥迪双钻, price=100000))
    

    2.2 基于JavaConfig类的配置

    想要成为JavaConfig类,需要使用@Configuration注解

    我们新建一个包命名为config,在config中新增一个PersonConfig类

    @Configuration
    @ComponentScan
    public class PersonConfig {
    
        @Bean
        public Person person(Dog dog, Car car){
            return new Person("dzzhyk", 20, true, dog, car);
        }
    
        @Bean
        public Dog dog(){
            return new Dog("旺财", 5);
        }
    
        @Bean
        public Car car(){
            return new Car("奥迪双钻", 100000);
        }
    }
    

    此时我们的XML配置文件可以完全为空了,此时应该使用AnnotationConfigApplicationContext来获取注解配置

    /**
     * 使用JavaConfig配置
     */
    public class TestVersion2 {
        @Test
        public void test(){
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(PersonConfig.class);
            Person person = ac.getBean("person", Person.class);
            System.out.println(person);
        }
    }
    

    仍然正常输出了结果:

    Person(name=dzzhyk, age=20, sex=true, dog=Dog(name=旺财, age=5), car=Car(brand=奥迪双钻, price=100000))
    


    3. BeanDefinition

    AbstractBeanDefinition
    

    是spring中所有bean的抽象定义对象,我把他叫做bean定义

    当bean.class被JVM类加载到内存中时,会被spring扫描到一个map容器中:

    BeanDefinitionMap<beanName, BeanDefinition>
    

    这个容器存储了bean定义,但是bean此时还没有进行实例化,在进行实例化之前,还有一个

    BeanFactoryPostProcessor
    

    可以对bean对象进行一些自定义处理

    我们打开BeanFactoryProcessor这个接口的源码可以发现如下内容:

    /*
    * Modify the application context's internal bean factory after its standard
    * initialization. All bean definitions will have been loaded, but no beans
    * will have been instantiated yet. This allows for overriding or adding
    * properties even to eager-initializing beans.
    */
    

    在spring完成标准的初始化过程后,实现BeanFactoryPostProcessor接口的对象可以用于定制bean factory,所有的bean definition都会被加载,但是此时还没有被实例化。这个接口允许对一些bean定义做出属性上的改动。

    简言之就是实现了BeanFactoryPostProcessor这个接口的类,可以在bean实例化之前完成一些对bean的改动。

    大致流程我画了个图:

    在这里插入图片描述

    至此我们能总结出springIOC容器的本质:(我的理解)

    由BeanDefinitionMap、BeanFactoryPostProcessor、BeanPostProcessor、BeanMap等等容器共同组成、共同完成、提供依赖注入和控制反转功能的一组集合,叫IOC容器。



    4. BeanDefinition结构

    既然讲到了BeanDefinition,我们来看一下BeanDefinition里面究竟定义了些什么

    让我们点进AbstractBeanDefinition这个类,一探究竟:

    哇!好多成员变量,整个人都要看晕了@_@

    我们来重点关注以下三个成员:

    •   private volatile Object beanClass;
      
    •   private int autowireMode = AUTOWIRE_NO;
      
    •   private ConstructorArgumentValues constructorArgumentValues;
      

    4.1 beanClass

    这个属性决定了该Bean定义的真正class到底是谁,接下来我们来做点实验

    我们定义两个Bean类,A和B

    @Component
    public class A {
        @Value("我是AAA")
        private String name;
    }
    @Component
    public class B {
        @Value("我是BBB")
        private String name;
    }
    

    接下来我们实现上面的BeanFactoryPostProcessor接口,来创建一个自定义的bean后置处理器

    /**
     * 自定义的bean后置处理器
     * 通过这个MyBeanPostProcessor来修改bean定义的属性
     * @author dzzhyk
     */
    public class MyBeanPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            GenericBeanDefinition defA = (GenericBeanDefinition) beanFactory.getBeanDefinition("a");
            System.out.println("这里是MyBeanPostProcessor,我拿到了:" + defA.getBeanClassName());
        }
    }
    

    最后在XML配置文件中开启包扫描

    <context:component-scan base-package="pojo"/>
    <context:annotation-config />
    

    **注意:**这里不要使用JavaConfig类来配置bean,不然会报如下错误

    ConfigurationClassBeanDefinition cannot be cast to org.springframework.beans.factory.support.GenericBeanDefinition
    

    这个错误出自这一句:

    GenericBeanDefinition defA = (GenericBeanDefinition) beanFactory.getBeanDefinition("a");
    

    最后,我们创建一个测试类:

    public class Test {
        @org.junit.Test
        public void test(){
            ClassPathXmlApplicationContext ca = new ClassPathXmlApplicationContext("applicationContext.xml");
            A aaa = ca.getBean("a", A.class);
            System.out.println("最终拿到了==> " + aaa);
        }
    }
    

    测试运行!

    这里是MyBeanPostProcessor,我拿到了:pojo.A
    最终拿到了==> A(name=我是AAA, b=B(name=我是BBB))
    

    可以看到MyBeanPostProcessor成功拿到了A的Bean定义,并且输出了提示信息

    接下来让我们做点坏事

    我们在MyBeanPostProcessor中修改A的Bean对象,将A的beanClass修改为B.class

    System.out.println("这里是MyBeanPostProcessor,我修改了:"+ defA.getBeanClassName() + " 的class为 B.class");
    // 把A的class改成B
    defA.setBeanClass(B.class);
    

    重新运行Test类,输出了一些信息后:报错了!

    这里是MyBeanPostProcessor,我拿到了:pojo.A
    这里是MyBeanPostProcessor,我修改了:pojo.A 的class为 B.class
    
    BeanNotOfRequiredTypeException: 
    	Bean named 'a' is expected to be of type 'pojo.A' but was actually of type 'pojo.B'
    

    我要拿到一个A类对象,你怎么给我一个B类对象呢?这明显不对

    综上所述,我们可以得出beanClass属性控制bean定义的类


    4.2 autowireMode

    我们继续看第二个属性:autowireMode,自动装配模式

    我们在AbstractBeanDefinition源码中可以看到:

    private int autowireMode = AUTOWIRE_NO;
    

    自动装配模式默认是AUTOWIRE_NO,就是不开启自动装配

    可选的常量值有以下四种:不自动装配,通过名称装配,通过类型装配,通过构造器装配

    • AUTOWIRE_NO

    • AUTOWIRE_BY_NAME

    • AUTOWIRE_BY_TYPE

    • AUTOWIRE_CONSTRUCTOR

    接下来我们来模拟一个自动装配场景,仍然是A和B两个类,现在在A类中添加B类对象

    @Component
    public class A {
        @Value("我是AAA")
        private String name;
        @Autowired
        private B b;
    }
    

    我们希望b对象能够自动装配,于是我们给他加上了@Autowired注解,其他的完全不变,我们自定义的MyBeanPostProcessor中也不做任何操作,让我们运行测试类:

    这里是MyBeanPostProcessor,我拿到了:pojo.A
    最终拿到了==> A(name=我是AAA, b=B(name=我是BBB))
    

    自动装配成功了!我们拿到的A类对象里面成功注入了B类对象b

    现在问题来了,如果我把@Autowired注解去掉,自动装配会成功吗?

    这里是MyBeanPostProcessor,我拿到了:pojo.A
    最终拿到了==> A(name=我是AAA, b=null)
    

    必然是不成功的

    但是我就是想要不加@Autowired注解,仍然可以实现自动装配,需要怎么做?

    这时就要在我们的MyBeanPostProcessor中做文章了,加入如下内容:

    defA.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_NAME);
    

    再输出结果:

    这里是MyBeanPostProcessor,我拿到了:pojo.A
    最终拿到了==> A(name=我是AAA, b=B(name=我是BBB))
    

    自动装配成功了!这次我们可没加@Autowired,在我们的自定义的bean后置处理器中设置了autowireMode属性,也实现了自动装配

    综上,autowireMode属性是用来控制自动装配模式的,默认值是AUTOWIRE_NO,即不自动装配


    4.3 constructorArgumentValues

    constructorArgumentValues的字面含义是构造器参数值

    改变这个参数值,我们可以做到在实例化对象时指定特定的构造器

    话不多说,show me your code:

    因为要研究构造器,只能先”忍痛“关掉lombok插件,手写一个pojo.Student类

    /**
     * Student类
     * @author dzzhyk
     */
    @Component
    public class Student {
        private String name;
        private Integer age;
    
        public Student() {
            System.out.println("==>使用空参构造器 Student()");
        }
    
        public Student(String name, Integer age) {
            this.name = name;
            this.age = age;
            System.out.println("==>使用双参数构造器 Student(String name, Integer age)");
        }
    }
    

    我们都知道,spring在实例化对象时使用的是对象的默认空参构造器:

    我们新建一个测试方法test

    @Test
    public void test(){
        ApplicationContext ca = new ClassPathXmlApplicationContext("applicationContext.xml");
        Student student = ca.getBean("stu", Student.class);
        System.out.println("==>" + student);
    }
    

    运行可以得到下面结果:

    这里是MyBeanPostProcessor,我拿到了:pojo.Student
    ==>使用空参构造器 Student()
    ==>pojo.Student@402e37bc
    

    可以看到,确实使用了空参构造器

    但是如何指定(自定义)使用哪个构造器呢?我根本看不见摸不着,Spring全帮我做了,实在是太贴心了。

    接下来就聊聊constructorArgumentValues的使用:

    我们在MyBeanPostProcessor中加入如下内容,对获取到的pojo.Student的bean定义进行操作:

    ConstructorArgumentValues args = new ConstructorArgumentValues();
    args.addIndexedArgumentValue(0, "我指定的姓名");
    args.addIndexedArgumentValue(1, 20);
    defStu.setConstructorArgumentValues(args);
    

    再次运行test:

    这里是MyBeanPostProcessor,我拿到了:pojo.Student
    ==>使用双参数构造器 Student(String name, Integer age)
    ==>pojo.Student@2f177a4b
    

    可以看到这次使用了双参数构造器

    有人会好奇ConstructorArgumentValues到底是个什么东西,我点进源码研究一番,结果发现这个类就是一个普通的包装类,包装的对象是ValueHolder,里面一个List<ValueHolder>一个Map<Integer, ValueHolder>

    而ValueHolder这个对象继承于BeanMetadataElement,就是构造器参数的一个包装类型

    通过这个例子我们可以看到ConstructorArgumentValues就是用来管控构造器参数的,指定这个值会在进行bean注入的时候选择合适的构造器。


    5. 装配对象

    现在我们把目光放回到SpringBoot的自动装配上来,原来在真正进行bean实例化对象前,我们前面还有这些过程,尤其是存在使用后置处理器BeanFactoryPostProcessor来对bean定义进行各种自定义修改的操作。

    经过上面我们漫长的研究过程,我们终于可以回答第一个问题了:

    自动装配的对象:Bean定义 (BeanDefinition)


    6. My自动装配

    看到这里又自然会产生疑问:不会吧,上面可都是自动装配啊,我在配置文件或者使用注解都配置了变量的值,然后加个@Autowired注解就OK了,spring也是帮我自动去装配。

    再高端一点话,我就把XML文件写成JavaConfig配置类,然后使用@Configuration注解,这样也能自动装配,这不是很nice了吗?


    6.1 自动装配之再思考

    我的理解,上面的自动装配,我们至少要写一个配置文件,无论是什么形式,我们都至少需要一个文件把它全部写下来,就算这个文件的内容是固定的,但是为了装配这个对象,我们不得不写。

    我们甚至都可以做成模板了,比如我在学习spring框架整合时,把经常写的都搞成了模板:

    有了这些模板,我们只需要点点点,再进行修改,就能用了。

    这样做确实很好,可是对于越来越成型的项目体系,我们每次都搞一些重复动作,是会厌烦的。而且面对这么多xml配置文件,我太难了。

    于是我有了一个想说但不敢说的问题:

    我一个配置文件都不想写,程序还能照样跑,我只关心有我需要的组件就可以了,我只需要关注我的目标就可以了,**我想打开一个工程之后可以1秒进入开发状态,而不是花3小时写完配置文件(2.5小时找bug)**希望有个东西帮我把开始之前的准备工作全做了,即那些套路化的配置,这样在我接完水之后回来就可以直接进行开发。

    说到这里,想必大家都懂了:SpringBoot


    6.2 一个例子

    让我们在偷懒的道路上继续前进。

    来看下面这个例子:

    仍然是A类和B类,其中A类仍然引用了B类,我们给A类组件起id=“a”,B类组件起id=“b”

    @Component("a")
    public class A {
        @Value("我是AAA")
        private String name;
        @Autowired
        private B b;
    }
    
    @Component("b")
    public class B {
        @Value("我是BBB")
        private String name;
    }
    

    可以看到我们使用了@Autowired注解来自动注入b,测试类如下:

    @Test
    public void test(){
    AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyAutoConfig.class);
    A aaa = ac.getBean("a", A.class);
    System.out.println(aaa);
    }
    

    细心的同学已经发现了:我们这里使用了AnnotationConfigApplicationContext这个JavaConfig配置类会使用到的加载类,于是我们顺利成章地点开它所加载的MyAutoConfig类文件

    文件内容如下:

    @Configuration
    @MyEnableAutoConfig
    public class MyAutoConfig {
        // bean 都去哪了 ???
    }
    

    what? 我要声明的Bean对象都去哪了(注意:这里的applicationContext.xml是空的)?

    让我们运行test:

    A(name=我是AAA, b=B(name=我是BBB))
    

    竟然运行成功了,这究竟是为什么?(元芳,你怎么看?)


    细心的同学已经发现了:@MyEnableAutoConfig是什么注解?我怎么没有这个注解

    让我们点进@MyEnableAutoConfig一探究竟:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(MyImportSelector.class) 		// 导入bean定义
    public @interface MyEnableAutoConfig {
    }
    

    原来如此!你是用了@Import注解导入了Bean定义对吧,注释都写着呢!

    可是客官,@Import导入bean定义是没错,但是它导入的是MyImportSelector这个bean,不是A也不是B啊…


    6.3 @Import注解

    @Import的功能就是获取某个类的bean对象,他的使用形式大致如下:

    @Import(A.class)
    @Import(MyImportBeanDefinitionRegister.class)
    @Import(MyImportSelector.class)
    

    6.3.1 @Import(A.class)

    第一种形式@Import(A.class),是最简单易懂的形式

    我们需要哪个Bean定义,直接Import他的class即可


    6.3.2 @Import(MyImportBeanDefinitionRegister.class)

    第二种形式@Import(MyImportBeanDefinitionRegister.class)

    传递了一个bean定义注册器,这个注册器的具体内容如下:

    public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            
            RootBeanDefinition aDef = new RootBeanDefinition(A.class);
            registry.registerBeanDefinition("a", aDef);
            
        }
    }
    

    这个注册器实现了ImportBeanDefinitionRegistrar接口,并且重写了里面的registerBeanDefinitions方法

    看他做了什么事:创建了一个新的bean定义,他的类型就是A,然后把这个bean定义注册到BeanDefinitionMap(还记得吧!)里面,key值我们可以人为设置,这里就设置成"a"

    这样在传递一个注册器的时候,我们就可以把注册器中新增的bean定义注册进来使用


    6.3.3 @Import(MyImportSelector.class)

    可以看到,这种使用方式就是我们刚才的注解中使用的方式

    他传递了一个叫MyImportSelector的类,这个类依然是我们自己定义的,具体内容如下:

    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            // 导入配置类
            return new String[]{"config.MyConfig"};
        }
    }
    

    这个类实现了ImportSelector接口,并且重写了selectImports方法,返回一个字符串数组

    我们可以看到,返回的字符串数组中是我们要导入类的全类名

    这个Importer返回的类如果是组件bean对象,就会被加载进来使用;如果是一个配置类,就会加载这个配置类

    第三种和第二种的区别是第三种可以一次性写很多类,而且比较简洁,只需要清楚类的全包名即可。而第二种方式需要自己清楚包类名,手动创建bean定义,然后手动加入BeanDefinitionMap。


    6.4 例子的研究

    我们打开MyImportSelector,发现里面赫然写着几个大字:

    return new String[]{"config.MyConfig"};
    

    然后我们找到config.MyConfig类,发现这个类竟然就是我们刚才写的JavaConfig版本的配置文件:

    @Configuration
    public class MyConfig {
        @Bean
        public A a(){
            return new A();
        }
    
        @Bean
        public B b(){
            return new B();
        }
    }
    

    加载这个MyConfig配置类,就相当于加载了A和B两个Bean定义

    喂!你是不是搞我!绕了一大圈,怎么还是加载这个配置文件啊!这个配置文件明明就是我自己写的。

    总结一下,我们这个例子大概绕了这些过程:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mxB37Xzr-1588939783485)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508162724344.png)]


    6.5 将偷懒进行到底

    "没有会偷懒的人解决不掉的问题“ —— 鲁迅

    上面的例子也没有多大优化啊,我怎么觉得更加麻烦了?不但绕了一大圈,定义了许多新东西,到最后还是加载了我写好的JavaConfig类,说到底我不是还在写javaConfig类吗…

    但是你注意到没有:有了上面的机制,我只需要把JavaConfig类写一次,然后放在某个地方,在MyImportSelector中加入这个地方的全包名路径,下次用的时候直接导入最顶层的MyAutoConfig类,所有有关这个部件我需要的东西,就全部自动整理好了,甚至比鼠标点点点添加代码模板还要快!

    我突然有了个很棒的想法,不知道你有了没有 。


    如果你开始有点感觉了,就会自然提出另一个问题:我这样做确实可以提高效率,但是一段代码里写入我自己定制的内容,每次更改起来不是太费劲了吗?

    想到这里,我就不禁回想起使用JDBC的时候,在代码里改SQL语句的痛苦了,那真是生不如死…这种情况就构成了硬编码的行为,是不好的。

    我们自然会想到:要是我创建一个配置文件properties来专门保存我这个需求所使用的bean对象,然后使用的时候在MyImportSelector中读取配置文件并且返回全包名,不就更加nice了吗?

    于是MyImportSelector中的代码又改成了下面这样:

    public class MyImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        
            Properties properties = MyPropertyReader.readPropertyForMe("/MyProperty.properties");
            String strings = (String) properties.get(MyEnableAutoConfig.class.getName());
           
            return new String[]{strings};
        }
    }
    

    其中MyPropertyReader是我们自己新创建的用于读取properties文件的工具类

    之所以要自己再定义这样一个工具类,是为了以后在其中可以做一些其他操作(比如:去重、预检查)

    public class MyPropertyReader {
        public static Properties readPropertyForMe(String path){
            Properties properties = new Properties();
            try(InputStream sin = MyPropertyReader.class.getResourceAsStream(path)){
                properties.load(sin);
            }catch (IOException e){
                e.printStackTrace();
                System.out.println("读取异常...");
            }
            return properties;
        }
    }
    

    我们的配置文件里面这么写:

    anno.MyEnableAutoConfig=config.MyConfig
    

    可以看到,key是注解@MyEnableAutoConfig的类名,也就是根据这个注解,就会导入后面的MyConfig这个Bean,这个Bean就是我们的配置文件

    如此一来我们读取这个配置文件,然后加载跟这个注解名称相符的value(即JavaConfig配置文件),就相当于我们在代码里手写的"config.MyConfig",只不过现在的形式已经发生了巨大的变化:我们添加或者删除一个配件,完全只需要修改MyProperty.properties这个配置文件就行了!

    至此,无论是添加或者删除组件,无非是在配置文件中加上或者删除一行的问题了。

    让我们在更新之后运行程序,可以看到成功拿到了配置文件的全类名

    程序的运行当然也是没问题的:

    A(name=我是AAA, b=B(name=我是BBB))
    

    到此,我仿佛又领悟了一些东西。。。

    我的配置文件好像活了,在我需要的时候他会出现,在我不需要的时候只需要在配置文件里面给他”打个叉“,他自己就跑开了


    7. 自动装配源码分析

    终于来到了大家喜闻乐见的部分:源码分析

    在我们前面6节学习了各种”招式“之后,让我们请出对手:SpringBoot

    现在在你面前的是一个SpringBoot”空项目“,没有添加任何依赖包和starter包

    启动项目:

    正常启动,让我们从@SpringBootApplication开始研究


    7.1 @SpringBootConfiguration

    会看到@SpringBootApplication这个注解由好多注解组成

    主要的有以下三个:

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan
    

    先来看第一个:@SpringBootConfiguration

    进入这个注解之后会发现

    原来你就是一个@Configuration啊,一个JavaConfig配置类

    那我们使用JavaConfig不就是用来配置bean吗,所以有了这个注解之后我们可以在SpringBoot运行的主类中使用@Bean标签配置类了,如下图所示:


    7.2 @ComponentScan

    这个注解相信大家都认识了,组件扫描

    这个扫描的范围是:SpringBoot主启动类的同级路径及子路径


    7.3 @EnableAutoConfiguration

    来看这个注解,也是最核心的内容

    这个注解怎么这么眼熟啊,还记得刚才的@MyEnableAutoConfig注解吗?就是我们自己写的那个注解

    进入@EnableAutoConfiguration:

    看图中红圈位置的注解:@Import(AutoConfigurationImportSelector.class)

    是不是跟我们上面自己写的内容一样!

    这里的作用便是导入了 AutoConfigurationImportSelector 这个类的bean定义

    我们都知道,如果这个类实现了ImportSelector接口,那他肯定重写了一个方法,就是我们上面重写过的selectImports方法:

    果然,在这个类里面确实有这个selectImports方法:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jxz7sKtE-1588939783486)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508182925585.png)]

    我的天,好长的一串代码,一行都放不下!

    此时此刻,我又回想起了在家乡的母亲,夏天的蝉鸣,池塘的荷花…

    等等等等,这个类我们当时返回的是什么?是一个字符串数组String[ ],那这个类无论多么长,返回的肯定就是一个字符串数组,不信你自己看:

    这个字符串数组存放的内容我们是否清楚呢?当然清楚了!我们返回的是要加载的Config配置文件的全包名,通过返回这个全包名,我们就能自动装配上这些配置文件下定义的bean对象,从而达到了自动装配的目的!

    根据刚才我们自己实现的selectImports方法,我们是通过注解类的名字来查找,并且最终得到需要加载的Config类的全类名,最后返回的。

    因此,这里必然有一个根据注解类名字来查找相应的Config文件的操作

    我们继续反推,看到返回时的定义如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zoGSMu1g-1588939783488)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508183913236.png)]

    我们发现autoConfigurationEntry中保存着我们需要的配置信息,它是通过getAutoConfigurationEntry方法获取的,于是我们继续深入,进入getAutoConfigurationEntry方法

    这一段代码真是把人难住了,好大一片,不知道在做什么

    此时此刻,我又回想起了在家乡的母亲,夏天的蝉鸣,池塘的荷花…

    回家!有了!我们先想这个方法应该返回什么,根据我们前面的经验,这里应该返回一个类似于Entry的保存了我们需要的配置信息的对象

    这个方法返回的是新建的AutoConfigurationEntry对象,根据最后一行的构造函数来看,给他了两个参数:

    configurations, exclusions
    

    configurations显然使我们需要的配置文件,也是我们最关心的,而exclusions字面意思是排除,也就是不需要的,那我们接下来应该关注configurations到底是怎么来的

    根据我们前面的经验,我们是根据注解类名来从一个配置文件中读取出我们需要的Config配置类,这里configurations就代表了Config配置类,那么我们应该找到一个入口,这个入口跟注解相关,并且返回了configurations这个参数。

    正如我们所料,这个方法的参数确实传递过来了一个东西,跟注解有关:

    看见那个大大的Annotation(注解)了吗!
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vqCBeWrN-1588939783490)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508184921167.png)]
    那么根据这条”线索“,我们按图索骥,找到了三行代码,范围进一步缩小了!

    此时再加上返回了configurations,我们最终确定了一行代码:
    在这里插入图片描述
    就是这个getCandidateConfigurations方法,符合我们的要求!

    从字面意思上分析,获取候选的配置,确实是我们需要的方法

    OK,让我们继续前进,进入这个方法:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lrSIMzkO-1588939783491)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508185122648.png)]
    这个方法是不是也似曾相识呢?我们之前写过一个专门用于读取配置文件的类MyPropertyReader,还记得吗?

    如果你还记得的话,我们自己写的工具类里面也是一个静态方法readPropertyForMe来帮我读取配置文件

    但是我们的配置文件路径一定是需要指定的,不能乱放。

    从这个loadFactoryNames方法体来看,好像没有给他传递一个具体路径

    但是从下面的Assert断言中,我们发现了玄机:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-362Uw2un-1588939783492)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508185311730.png)]
    在META-INF/spring.factories文件中没有找到自动配置类Config,你要检查balabala。。。。

    根据我不太灵光的脑袋的判断,他的这个配置文件就叫spring.factories,存放的路径是META-INF/spring.factories

    于是我们打开spring boot自动装配的依赖jar包:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-20LlGwoO-1588939783493)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508185730439.png)]

    那这个配置文件里面的内容,是不是跟我们想的一样呢?

    原来如此。

    这里的EnableAutoConfiguration注解,正是我们此行的起点啊…

    到这里,自动装配到底是什么,应该比较清楚了,原来他是帮我们加载了各种已经写好的Config类文件,实现了这些JavaConfig配置文件的重复利用和组件化


    7.4 loadFactoryNames方法

    行程不能到此结束,学习不能浅尝辄止。

    我们还有最后一块(几块)面纱没有解开,现在还不能善罢甘休。

    让我们进入loadFactoryNames方法:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-88lF8sNH-1588939783493)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508190213629.png)]
    这个方法非常简短,因为他调用了真正实现的方法:loadSpringFactories
    这一行return代码我复制在下面:

    loadSpringFactories(classLoader)
        	.getOrDefault(factoryTypeName, Collections.emptyList());
    

    可以分析得出:loadSpringFactories方法的返回值又调用了一个getOrDefault方法,这明显是一个容器类的方法,目的是从容器中拿点东西出来

    就此推测:loadSpringFactories返回了一个包含我们需要的Config全类名(字符串)的集合容器,然后从这个集合容器中拿出来的东西就是我们的configurations

    让我们看这个loadSpringFactories方法:

    它确实返回了一个容器:Map<String, List<String>>
    这个容器的类型是:MultiValueMap<String, String>

    这个数据结构就非常牛逼了,多值集合映射(我自己的翻译)简单来说,一个key可以对应多个value,根据他的返回值,我们可以看到在这个方法中一个String对应了一个List<String>

    那么不难想到MultiValueMap中存放的形式:是”注解的类名——多个Config配置类“
    让我们打个断点来验证一下:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vg7Lh3VU-1588939783495)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508194518140.png)]
    果然是这样,并且@EnableAutoConfiguration注解竟然加载了多达124个配置类!

    接下来我们继续思考:我们来的目的是获取configurations,所以无论你做什么,必须得读取配置文件,拿到configurations

    于是我们在try方法体中果然发现了这个操作:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mnanTXyI-1588939783496)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508192007209.png)]
    他获取了一个路径urls,那么这个路径是否就是我们前面验证的META-INF/spring.factories呢?
    我们查看静态常量FACTORIES_RESOURCE_LOCATION的值:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CXkKntfH-1588939783497)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508192121252.png)]
    果真如此,bingo!
    继续往下看,果然他遍历了urls中的内容,从这个路径加载了配置文件:
    终于看到了我们熟悉的loadProperties方法!
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c1nPBjBg-1588939783497)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508192706813.png)]
    那我们大概就知道了,他确实是通过找到路径,然后根据路径读取了配置文件,然后返回了读取的result

    这就是loadFactoryNames方法的内部实现。


    7.5 cache探秘

    到这里有的人又要问了:是不是结束了?其实还远没有!

    细心地朋友已经发现了玄机,隐藏在loadFactoryNames方法的开头和结尾:

    喂喂,这个返回的result好像并不是直接new出来的

    它是从cache缓存中取出来的,你发现了没有

    根据下面的if判断,如果从缓存中读取出来了result,并且result的结果不为空,就直接返回,不需要再进行下面的读写操作了,这样减少了磁盘频繁的读写I/O

    同理,在我更新完所有的配置文件资源之后,退出时也要更新缓存。


    7.6 getAutoConfigurationEntry再探

    关键部分已经过去,让我们反过头来重新审视一下遗漏的内容:

    还记得getAutoConfigurationEntry方法吗?
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fdxZanAC-1588939783498)(/Users/dzzhyk/Desktop/apeBook/src/image-20200508195119398.png)]
    我们最后来研究一下这个类除了getCandidateConfigurations还干了哪些事情:

    • removeDuplicates
    • configurations.removeAll(exclusions)

    可以看到,这里对加载进来的配置进行了去重、排除的操作,这是为了使得用户自定义的排除包生效,同时避免包冲突异常,在SpringBoot的入口函数中我们可以通过注解指定需要排除哪些不用的包:

    例如我不使用RabbitMQ的配置包,就把它的配置类的class传给exclude

    @SpringBootApplication(exclude = {RabbitAutoConfiguration.class})
    

    8. 自动装配本质

    我的理解:

    • SpringBoot自动装配的本质就是通过Spring去读取META-INF/spring.factories中保存的配置类文件然后加载bean定义的过程。
    • 如果是标了@Configuration注解,就是批量加载了里面的bean定义
    • 如何实现”自动“:通过配置文件获取对应的批量配置类,然后通过配置类批量加载bean定义,只要有写好的配置文件spring.factories就实现了自动。

    9. 总结

    Spring Boot的自动装配特性可以说是Spring Boot最重要、最核心的一环,正是因为这个特性,使得我们的生产复杂性大大降低,极大地简化了开发流程,可以说是给我们带来了巨大的福音了~~

    笔者本人还是一名学生,对源码的理解仍然没有那么深刻,只是喜欢分享自己的一些学习经验,希望能和大家共同学习,毕竟掌握一门新技术的快感嘛… 大家都懂的!

    写这篇文章耗费了巨大的精力,每一个字均是手码,真的希望喜欢的朋友可以点赞收藏关注支持一波,这就是对我这个未出世的学生的最大激励了!

    最后,我整理了本文中用到的项目源码,还有一份Spring Boot自动装配详细流程图(自己画的),如果有需要的朋友可以在文章下面留下你的邮箱,我会尽快回复!

    如果文章内容有错误,欢迎在评论区指出,感谢捉虫!
    在这里插入图片描述
    更新:谢谢各位小伙伴的支持!鉴于大家太过热情,在这里就直接附上Spring Boot自动装配详细流程图
    Spring Boot自动装配详细流程图

    展开全文
  • 1.Springboot2.0.X自动装配原理自动装配原理a.Springboot如何自动装配: 以HttpEncodingAutoConfiguration通过源码为例; 1.@Configuration:标识此类为配置类,将此类纳入SpringIOC容器; 2. @...
  • Spring 自动装配及其注解 博客:https://blog.csdn.net/u010476739/article/details/76735241
  • Spring 自动装配

    万次阅读 多人点赞 2019-03-02 15:03:23
    Spring框架式默认不支持自动装配的,要想使用自动装配需要修改spring配置文件中&lt;bean&gt;标签的autowire属性 代码样例 package com.spring.auto.autowire; public class Cat { public void sayCat()...
  • 本篇文章主要介绍了浅谈Spring装配Bean之组件扫描和自动装配,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • 记录SpringBoot的启动与自动装配中,所涉及到的主要方法调用链
  • Bean的自动装配

    千次阅读 2021-01-22 11:19:51
    自动装配说明 自动装配是使用spring满足bean依赖的一种方法 spring会在应用上下文中为某个bean寻找其依赖的bean。 Spring中bean有三种装配机制,分别是: 在xml中显式配置; 在java中显式配置; 隐式的bean发现...
  • SpringBoot的自动装配是拆箱即用的基础,也是微服务化的前提。接下来通过本文给大家介绍SpringBoot中的自动装配,感兴趣的朋友跟随脚本之家小编一起学习吧
  • 自动装配技术(手动装配): @Resource: 默认是通过name来查找注入值,如果不存在就报错 @Autowired 通过类型查找(类型),然后再通过name 以上两种通过反射,然后设置值 AutowireMode(自动装配模型):在spring中有...
  • SpringBoot自动装配原理
  • Springboot 自动装配原理图文,里面描述了整个Springboot的装配流程和所有相关的组件。
  • 文章目录在Spring框架xml配置中共有5种自动装配使用@Autowired注解自动装配的过程是怎样的?自动装配有哪些局限性?自动装配的局限性是: 在Spring框架xml配置中共有5种自动装配 no:默认的方式是不进行自动装配的...
  • Spring Boot自动装配

    万次阅读 2019-01-30 10:57:22
    Spring Boot自动装配 题记 在日常的开发过程中Spring Boot自动装配的特性给我们开发减少了很多重复性的工作,具体时如果实现自动装配的呢,我们会在下一篇文章做详细的分析,以及用源码解析跟实战方式带大家了解...
  • Spring 手动装配和自动装配

    千次阅读 2017-05-19 19:25:45
    Spring 手动装配和自动装配
  • SpringBoot自动装配

    千次阅读 2021-03-30 15:58:26
    应用需要借助@Import或@ComponentScan的能力,由于应用依赖JAR存在变化的可能,因此其中的@Component类所在的包路径也随之不确定,如果要实现当前应用所有组件自动装配,则@Import显然是无能为力的,开发人员自然会...
  • spring 自动装配 bean 有哪些方式?

    万次阅读 2019-07-17 10:59:39
    spring 自动装配 bean 有哪些方式? spring 配置文件中 <bean> 节点的 autowire 参数可以控制 bean 自动装配的方式 default - 默认的方式和 "no" 方式一样 no - 不自动装配,需要使用 <ref />节点或...
  • springboot自动装配

    2019-04-24 21:59:05
    Spring boot自动装配 ## 激活自动装配 @EnableAutoConfiguration public class EnableAutoConfigurationBootstrap { public static void main(String[] args) { ConfigurableApplicationContext context = new Spr...
  • spring自动装配

    2016-12-13 14:49:39
    @Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。 试想,@Autowired 为什么能完成自动装配呢? 当 Spring 容器启动时,...
  • 自动装配模拟.zip

    2020-06-27 11:44:47
    springboot自动装配模拟 博客地址:https://blog.csdn.net/qq_36963950/article/details/106980641
  • 主要介绍了spring 自动装配和aop的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • Spring-Boot是如何自动装配的?

    万次阅读 2020-10-30 14:43:07
    Spring-Boot是如何自动装配的? 我们都知道Spring-Boot是Spring的延伸框架,相较于Spring它更快,且几乎用配置,即开箱即用的。但是真的是不用配置嘛? 一、自动装配过程解析 @SpringBootApplication注解 我们在...
  • 主要介绍了Spring自动装配Bean实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 110,999
精华内容 44,399
关键字:

自动装配