zoukankan      html  css  js  c++  java
  • springboot自动装配原理

    springboot主要是帮助我们简化开发中繁琐的配置,如何简化???

    pom.xml

    父依赖

    管理SpringBoot应用里面所有依赖版本,如果导入的包没有被管理就需要手动配置版本

    启动器 spring-boot-starter

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>

    springboot-boot-starter-xxx:就是spring-boot的场景启动器

    spring-boot-starter-web:帮我们导入了web模块正常运行所依赖的组件;

    官网提供的start:https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters

    starter就是实现自动装配的核心,如何实现????

    启动类

    启动类

    由两部分组成@SpringBootApplication、run方法

    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
    }

    @SpringBootApplication 

    作用:标注在某个类上说明这个类是SpringBoot的主配置类 , SpringBoot就应该运行这个类的main方法来启动SpringBoot应用;

    @SpringBootApplication结构

      |-- @SpringBootConfiguration :表示为SpringBoot的配置类

      |-- @EnableAutoConfiguration:开启自动配置功能

        |-- @AutoConfigurationPackage:自动包配置

        |-- @Import({AutoConfigurationImportSelector.class}):导入组件到spring容器中

      |-- @ComponentScan :自动扫描并加载符合条件的组件或者bean , 并加载到Spring容器中

     AutoConfigurationImportSelector.class

        protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    
            List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(),
                    this.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;
        }
        // 获取注解类
        protected Class<?> getSpringFactoriesLoaderFactoryClass() {
            return EnableAutoConfiguration.class;
        }
    View Code

    SpringFactoriesLoader

    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
            ClassLoader classLoaderToUse = classLoader;
            if (classLoader == null) {
                classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
            }
    
            String factoryTypeName = factoryType.getName();
            return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
        }
    
        private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
            Map<String, List<String>> result = (Map)cache.get(classLoader);
            if (result != null) {
                return result;
            } else {
                HashMap result = new HashMap();
    
                try {
                    Enumeration urls = classLoader.getResources("META-INF/spring.factories");
    
                    while(urls.hasMoreElements()) {
                        URL url = (URL)urls.nextElement();
                        UrlResource resource = new UrlResource(url);
                        Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                        Iterator var6 = properties.entrySet().iterator();
    
                        while(var6.hasNext()) {
                            Entry<?, ?> entry = (Entry)var6.next();
                            String factoryTypeName = ((String)entry.getKey()).trim();
                            String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                            String[] var10 = factoryImplementationNames;
                            int var11 = factoryImplementationNames.length;
    
                            for(int var12 = 0; var12 < var11; ++var12) {
                                String factoryImplementationName = var10[var12];
                                ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                    return new ArrayList();
                                })).add(factoryImplementationName.trim());
                            }
                        }
                    }
    
                    result.replaceAll((factoryType, implementations) -> {
                        return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                    });
                    cache.put(classLoader, result);
                    return result;
                } catch (IOException var14) {
                    throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
                }
            }
        }
    View Code

    META-INF/spring.factories

    以org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration为例

    自动装配的本质:将开发所需的对象都放到spring容器中

    分析:

       1、loadSpringFactories方法获取META-INF/spring.factories数据保存到Map集合

       2、通过与Map集合key(EnableAutoConfiguration名称)获取AutoConfiguration类的全名称集合

       3、根据配置类的全名称和注解实例化配置类对象

          4、实例化配置类过程中的会将组件(具体类)一并实例化并放入到spring容器中

    自定义starter

    自定义starter需要哪些文件

    1、META-INF/spring.factories

    2、spring管理的类

    3、AutoConfiguration配置类文件

    创建项目

    1、创建maven工程

     

     

     项目结构

     

    2、添加依赖(这里使用spring-boot-maven-plugin插件会有问题)

        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.5.3</version>
        </parent>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-autoconfigure</artifactId>
                <version>2.5.3</version>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <!-- 打包插件 -->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>2.5.3</version>
                </plugin>
            </plugins>
        </build>

    3、META-INF/spring.factories,以下红字是固定的,上面分析中有原因

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
      com.test.starter.config.TestAutoConfigure

    4、组件(具体类)

    public class TestService {
    
        public void sayHello(){
            System.out.println("TestService 的sayHello方法执行了。。。。。");
        }
        public TestService(){
            System.out.println("TestService 已经实例化了。。。。。");
        }
    }
    View Code

    3、AutoConfiguration类,实例化组件

    @Configuration
    public class TestAutoConfiguration {
        @Bean
        TestService testService(){
            return new TestService();
        }
    }
    View Code

    3、打成jar包

     

    错误:Unable to find main class

    猜测spring-boot-maven-plugin插件只能用于spring-boot项目,spring-boot需要main class

    所以不使用spring-boot-maven-plugin插件,使用自己下载的maven

    3.1、设置maven,

    3.2、Sttings

     

     

    使用自定义starter

     使用自定义starter之前项目必须maven 仓库要一致

     

    添加依赖(pom.xml)

            <dependency>
                <groupId>org.marw</groupId>
                <artifactId>test-starter</artifactId>
                <version>1.0-SNAPSHOT</version>
            </dependency>

     

    编写Controller

    @RestController
    public class DemoController {
    
        @Autowired
        TestService testService;
    
        @RequestMapping("/hello")
        public String sayHello() {
            testService.sayHello();
            return "Hello World";
        }
    
    }
    View Code

    启动项目

    配置文件与JavaConfig绑定

    如果想使用配置那么就需要一个Properties,正常情况下Properties和AutoConfiguration一起使用的

    前期解决错误

    创建一个TestProperties,并使用@ConfigurationProperties(prefix="org.xxx")注解 

    @ConfigurationProperties(prefix="org.marw")
    public class TestProperties {
        private String name;
    }

    出现Spring Boot Configuration Annotation Processor not configured

     

    解决方法:添加依赖

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-configuration-processor</artifactId>
                <optional>true</optional>
            </dependency>

    接着出现:Not registered via @EnableConfigurationProperties, marked as Spring component, or scanned via @ConfigurationPropertiesScan

    在其对应的AutoConfiguration类上添加@EnableConfigurationProperties

    @Configuration
    @EnableConfigurationProperties({TestProperties.class})
    public class TestAutoConfiguration {

    编写properties

    @Data // 提供类的get、set、equals、hashCode、canEqual、toString方法
    @ConfigurationProperties(prefix="org.marw")
    public class TestProperties {
        private String name;
    }
    View Code

    使用properties

    public class TestService {
    
        String name;
    
        public void sayHello() {
            System.out.println(this.name + " sayHello执行了。。。。。");
        }
    
        public TestService(TestProperties properties) {
            this.name = properties.getName();
        }
    }
    View Code

    AutoConfiguration实例化带有properties的类

    @Configuration
    @EnableConfigurationProperties({TestProperties.class})
    public class TestAutoConfiguration {
        @Autowired
        private TestProperties testProperties;
        @Bean
        TestService testService(){
    
            return new TestService(testProperties);
        }
    }

    打包,安装到maven仓库中。

    使用上面的DemoController测试,刷新maven就可以了

    编写配置application.properties

    org.marw.name=zhangsan

  • 相关阅读:
    Python 内置数据结构之 set
    python 在指定的文件夹下生成随机的测验试卷文件
    Python 的 import 语句
    Python 和 R 中的一数多图
    Python 语法练习题
    python 3.x 和 2.x 不同
    R 的 plyr 包
    Python 和 R语言 中的折线图
    设置 Jupyter notebook 默认路径、启动快捷键、打开浏览器
    Python 虚拟环境
  • 原文地址:https://www.cnblogs.com/WarBlog/p/15098483.html
Copyright © 2011-2022 走看看