zoukankan      html  css  js  c++  java
  • springboot自动装配、启动后执行

    spring boot(二):启动原理解析 (nice)

    Spring Boot自动配置原理

    springboot自动装配

    springboot配置文件

    Spring Boot的出现,得益于“习惯优于配置”的理念,没有繁琐的配置、难以集成的内容(大多数流行第三方技术都被集成),这是基于Spring 4.x提供的按条件配置Bean的能力。

    Spring Boot有一个全局配置文件:application.properties或application.yml。我们的各种属性都可以在这个文件中进行配置,最常配置的比如:server.port、logging.level.* 等等,然而我们实际用到的往往只是很少的一部分,那么这些属性是否有据可依呢?答案当然是肯定的,这些属性都可以在官方文档中查找到。

    工作原理解析

    Spring Boot关于自动配置的源码在spring-boot-autoconfigure-x.x.x.x.jar中

    当然,自动配置原理的相关描述,官方文档貌似是没有提及。不过我们不难猜出,Spring Boot的启动类上有一个@SpringBootApplication注解,这个注解是Spring Boot项目必不可少的注解。那么自动配置原理一定和这个注解有着千丝万缕的联系!

    @EnableAutoConfiguration

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Configuration
    @EnableAutoConfiguration
    @ComponentScan
    public @interface SpringBootApplication {
    
    
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(EnableAutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {

    @SpringBootApplication是一个复合注解或派生注解,在@SpringBootApplication中有一个注解@EnableAutoConfiguration,就是开启自动配置。

    另:

    @Enable*注释并不是SpringBoot新发明的注释,Spring 3框架就引入了这些注释,用这些注释替代XML配置文件。比如:
    @EnableTransactionManagement注释,它能够声明事务管理
    @EnableWebMvc注释,它能启用Spring MVC
    @EnableScheduling注释,它可以初始化一个调度器。

    这些注释事实上都是简单的配置,通过@Import注释导入。

    @EnableAutoConfiguration注解也是一个派生注解,其中的关键功能由@Import提供,导入了EnableAutoConfigurationImportSelector。

    进入他的父类AutoConfigurationImportSelector(4.2.6好像没了),找到selectImports()方法,他调用了getCandidateConfigurations()方法,在这里,这个方法又调用了Spring Core包中的loadFactoryNames()方法。这个方法的作用是,会查询META-INF/spring.factories文件中包含的JAR文件。

    public String[] selectImports(AnnotationMetadata metadata) {
            try {
                AnnotationAttributes attributes = getAttributes(metadata);
                List<String> configurations = getCandidateConfigurations(metadata,
                        attributes);
                configurations = removeDuplicates(configurations);
                Set<String> exclusions = getExclusions(metadata, attributes);
                configurations.removeAll(exclusions);
                configurations = sort(configurations);
                recordWithConditionEvaluationReport(configurations, exclusions);
                return configurations.toArray(new String[configurations.size()]);
            }
            catch (IOException ex) {
                throw new IllegalStateException(ex);
            }
        }
    protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
                AnnotationAttributes attributes) {
            return SpringFactoriesLoader.loadFactoryNames(
                    getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
        }
    public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
            String factoryClassName = factoryClass.getName();
            try {
                Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                        ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
                List<String> result = new ArrayList<String>();

    SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。

    这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:

    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=
    org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
    org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
    org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
    org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration,
    org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration,
    org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
    org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
    org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
    org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,

    这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(...)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

    自动配置生效注解

    每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:

    @ConditionalOnBean:当容器里有指定的bean的条件下。
    
    @ConditionalOnMissingBean:当容器里不存在指定bean的条件下。
    
    @ConditionalOnClass:当类路径下有指定类的条件下。
    
    @ConditionalOnMissingClass:当类路径下不存在指定类的条件下。
    
    @ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),
    代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。

    以ServletWebServerFactoryAutoConfiguration配置类举例

    以ServletWebServerFactoryAutoConfiguration配置类为例,解释一下全局配置文件中的属性如何生效,比如:server.port=8081,是如何生效的(当然不配置也会有默认值,这个默认值来自于org.apache.catalina.startup.Tomcat)。

    在ServletWebServerFactoryAutoConfiguration类上,有一个@EnableConfigurationProperties注解:开启配置属性,而它后面的参数是一个ServerProperties类,这就是习惯优于配置的最终落地点。

    @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
    public class ServerProperties
            implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered {
    
        /**
         * Server HTTP port.
         */
        private Integer port;
    
        /**
         * Network address to which the server should bind to.
         */
        private InetAddress address;
    
        /**
         * Context path of the application.
         */
        private String contextPath;
    
        /**
         * Display name of the application.
         */
        private String displayName = "application";
    
        @NestedConfigurationProperty
        private ErrorProperties error = new ErrorProperties();
    
        ........

    在这个类上,我们看到了一个非常熟悉的注解:@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中(见上面截图)。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。

    至此,我们大致可以了解。在全局配置的属性如:server.port等,通过@ConfigurationProperties注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过@EnableConfigurationProperties注解导入到Spring容器中。

    而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。

    面试回答

    Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类(自定义的starter其实也可以通过在本starter jar中写一个META-INF/spring.factories文件),并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

    小结

     

    综上是对自动配置原理的讲解。当然,在浏览源码的时候一定要记得不要太过拘泥与代码的实现,而是应该抓住重点脉络。

    一定要记得XxxxProperties类的含义是:封装配置文件中相关属性;XxxxAutoConfiguration类的含义是:自动配置类,目的是给容器中添加组件。

    而其他的主方法启动,则是为了加载这些五花八门的XxxxAutoConfiguration类。

    自定义starter

    第二十八章:SpringBoot使用AutoConfiguration自定义Starter

    项目启动后执行 方式

    CommandLineRunner

    添加一个model并实现CommandLineRunner接口,并在IOC中。

    ApplicationRunner

    和CommandLineRunner接口功能一样。

    不同点在于,前者的run方法参数是String...args,直接传入字符串

    CommandLineRunner的参数是ApplicationArguments,对参数进行了封装。

    ContextRefreshedEvent事件

    ApplicationEvent相当于一个事件,所有自定义事件都需要继承这个抽象类。

    Application下抽象子类ApplicationContextEvent的下面有4个已经实现好的事件 (当然还有很多其他事件)
    ContextClosedEvent(容器关闭时) 
    ContextRefreshedEvent(容器初始化、刷新时) 
    ContextStartedEvent(容器启动时时) 
    ContextStoppedEvent(容器停止时) 
    同样,这四个事件都继承了ApplicationEvent,如果我们想自定义事件,也可以通过继承ApplicationEvent来实现 
    嗯,同样是一句话总结ApplicationEvent就是一个抽象类,创建事件的时候只需要继承它就可以。

  • 相关阅读:
    【转】js 获取浏览器高度和宽度值(多浏览器)
    Css相册
    微信公众号开发笔记2-自定义菜单
    微信公众号开发笔记1-获取Access Token
    【转】CSS选择器笔记
    【转】CSS浮动(float,clear)通俗讲解
    高云的jQuery源码分析笔记
    经典闭包例子详解
    执行控制——节流模式
    图片上下左右的无缝滚动的实现
  • 原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/10739321.html
Copyright © 2011-2022 走看看