zoukankan      html  css  js  c++  java
  • SpringBoot自动配置原理

    SpringBoot作为一款全新的框架,有着诸多的优点,正受到越来越多的Java开发者的欢迎。

    SpringBoot极大地简化了Spring应用的初始创建和开发过程。其优点如下:

    1、内嵌Tomcat,无需部署WAR文件;

    2、创建独立的Spring应用;

    3、简化Maven配置;

    4、自动配置Spring;

    5、提供生产就绪型功能,如指标,健康检查和外部配置;

    6、绝对没有代码生成并且对XML也没有配置要求。

    下面就来深入源码分析下SpringBoot自动配置的原理(此文针对的SpringBoot版本为1.5.17.RELEASE)。

     首先从主类SpringbootApplication入手:

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

     类上的@SpringBootApplication注解定义如下:

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(
        excludeFilters = {@Filter(
        type = FilterType.CUSTOM,
        classes = {TypeExcludeFilter.class}
    ), @Filter(
        type = FilterType.CUSTOM,
        classes = {AutoConfigurationExcludeFilter.class}
    )}
    )
    public @interface SpringBootApplication {

    其中的@EnableAutoConfiguration注解是关键所在,其定义如下:

    @SuppressWarnings("deprecation")
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(EnableAutoConfigurationImportSelector.class)
    public @interface EnableAutoConfiguration {

    @Import注解可以让普通的类导入到Spring的IOC容器中,由Spring进行管理。

    EnableAutoConfigurationImportSelector类定义如下:

    @Deprecated
    public class EnableAutoConfigurationImportSelector
            extends AutoConfigurationImportSelector {

    由于该类已被标记为过时,我们来看下它的父类AutoConfigurationImportSelector:

    public class AutoConfigurationImportSelector
            implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware,
            BeanFactoryAware, EnvironmentAware, Ordered {

    AutoConfigurationImportSelector类实现了多个接口,作为一个选择器实现了对自动配置类的选择导入功能,其类图关系如下:

    AutoConfigurationImportSelector类中有一个重要的selectImports方法,其定义如下:

      @Override
        public String[] selectImports(AnnotationMetadata annotationMetadata) {
            if (!isEnabled(annotationMetadata)) {
                return NO_IMPORTS;
            }
            try {
                AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
                        .loadMetadata(this.beanClassLoader);//1.1
                AnnotationAttributes attributes = getAttributes(annotationMetadata);//1.2
                List<String> configurations = getCandidateConfigurations(annotationMetadata,
                        attributes);//1.3
                configurations = removeDuplicates(configurations);//1.4
                configurations = sort(configurations, autoConfigurationMetadata);//1.5
                Set<String> exclusions = getExclusions(annotationMetadata, attributes);//1.6
                checkExcludedClasses(configurations, exclusions);//1.7
                configurations.removeAll(exclusions);//1.8
                configurations = filter(configurations, autoConfigurationMetadata);//1.9
                fireAutoConfigurationImportEvents(configurations, exclusions);//2.0
                return configurations.toArray(new String[configurations.size()]);//2.1
            }
            catch (IOException ex) {
                throw new IllegalStateException(ex);
            }
        }

    1.1 加载元数据并返回AutoConfigurationMetadata对象;

    1.2 获取传入的元数据对应的属性值(AnnotationAttributes对象);

    1.3 返回候选自动配置类名的list集合;

    1.4 移除list中的重复自动配置类名;

    1.5 通过读取@AutoConfigureOrder、@link AutoConfigureBefore、@AutoConfigureAfter注解对自动配置类名进行优先级排序;

    1.6 返回排除掉的自动配置类的set集合;

    1.7 检查候选配置类中是否存在排除项,然后返回给SpringFactoriesLoader加载的候选自动配置类;

    1.8 移除候选配置类当中的的所有排除项(不需要自动配置的类)

    1.9 利用在spring工厂注册过的AutoConfigurationImportFilter过滤器对候选自动配置类进行过滤;

    2.0 通过AutoConfigurationImportListener监听器触发自动配置导入事件;

    2.1 返回经过上述步骤得到的自动配置类的数组。

    该方法最终返回了能进行自动配置的类的数组。

    我们着重看下红色标注的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;
        }

    其中的getSpringFactoriesLoaderFactoryClass()方法正是返回EnableAutoConfiguration.class。

    该方法里面调用了SpringFactoriesLoader.loadFactoryNames()方法扫描加载引入的jar包中包含META-INF/spring.factories文件中的自动配置类。

    具体方法如下:

    /**
     * The location to look for factories.
     * <p>Can be present in multiple JAR files.
     */
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    
    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>();
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
                    String factoryClassNames = properties.getProperty(factoryClassName);
                    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
                }
                return result;
            }
            catch (IOException ex) {
                throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
                        "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
            }
        }

    蓝色加粗的程序表示会将扫描到的文件内容包装成properties对象。

    红色标注的文件spring.factories可以在spring-boot-autoconfigure等springboot相关的jar包中找到:

    该文件里面内容都是键值对形式的,其中spring-boot-autoconfigure这个jar中的org.springframework.boot.autoconfigure.EnableAutoConfiguration正是我们要找的自动配置的类,包括Aop、WebMvc、Jpa、redis、jdbc等自动配置类。

    # 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.batch.BatchAutoConfiguration,
    org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
    org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
    org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,
    org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,
    org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,
    org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,
    org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,
    org.springframework.boot.autoconfigure.dao.PersistenceExceptionTranslationAutoConfiguration,
    org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration,
    org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,
    org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,
    org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,
    org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,
    org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,
    org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,
    org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,
    org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,
    org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,
    org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,
    org.springframework.boot.autoconfigure.elasticsearch.jest.JestAutoConfiguration,
    org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration,
    org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration,
    org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration,
    org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration,
    org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration,
    org.springframework.boot.autoconfigure.hazelcast.HazelcastJpaDependencyAutoConfiguration,
    org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration,
    org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration,
    org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,
    org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,
    org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,
    org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration,
    org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration,
    org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,
    org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration,
    org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration,
    org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration,
    org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration,
    org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration,
    org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,
    org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration,
    org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,
    org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,
    org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration,
    org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration,
    org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration,
    org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,
    org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration,
    org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration,
    org.springframework.boot.autoconfigure.mobile.DeviceResolverAutoConfiguration,
    org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration,
    org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,
    org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,
    org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,
    org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,
    org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,
    org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,
    org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,
    org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration,
    org.springframework.boot.autoconfigure.security.FallbackWebSecurityAutoConfiguration,
    org.springframework.boot.autoconfigure.security.oauth2.OAuth2AutoConfiguration,
    org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,
    org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,
    org.springframework.boot.autoconfigure.social.SocialWebAutoConfiguration,
    org.springframework.boot.autoconfigure.social.FacebookAutoConfiguration,
    org.springframework.boot.autoconfigure.social.LinkedInAutoConfiguration,
    org.springframework.boot.autoconfigure.social.TwitterAutoConfiguration,
    org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,
    org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,
    org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,
    org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,
    org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration,
    org.springframework.boot.autoconfigure.web.DispatcherServletAutoConfiguration,
    org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,
    org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration,
    org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,
    org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,
    org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,
    org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,
    org.springframework.boot.autoconfigure.web.WebClientAutoConfiguration,
    org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration,
    org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,
    org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration,
    org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration

    当然这些自动配置类并不是都能自动配置进来的,里面会根据@Conditional等注解控制bean的创建行为。

    只有满足了条件才能自动注入相关的bean。

    以RabbitAutoConfiguration为例,其定义如下:

    @Configuration
    @ConditionalOnClass({ RabbitTemplate.class, Channel.class })
    @EnableConfigurationProperties(RabbitProperties.class)
    @Import(RabbitAnnotationDrivenConfiguration.class)
    public class RabbitAutoConfiguration {

    // Only available in rabbitmq-java-client 5.4.0 +
    private static final boolean CAN_ENABLE_HOSTNAME_VERIFICATION = ReflectionUtils
    .findMethod(com.rabbitmq.client.ConnectionFactory.class,
    "enableHostnameVerification") != null;

      @Bean
      public CachingConnectionFactory rabbitConnectionFactory(RabbitProperties config)
       throws Exception {
       RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean();
      if (config.determineHost() != null) {
    factory.setHost(config.determineHost());
        .
        .
        .
      }

    @ConditionalOnClass表示有某个类的情况下才会加载bean,这里需要同时有RabbitTemplate和Channel类,当所有条件满足的情况下,就能通过@Bean注解,让方法产生一个bean对象,交由Spring容器来进行管理,这样就能在SpringBoot项目启动的时候实现自动配置。

    如果上述2个类提示找不到,可以在pom.xml引入以下依赖解决:

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

    @EnableConfigurationProperties(RabbitProperties.class)能实现属性类的自动配置,RabbitProperties类是配置Rabbitmq属性用的,其定义如下:

    @ConfigurationProperties(prefix = "spring.rabbitmq")
    public class RabbitProperties {
    
        /**
         * RabbitMQ host.
         */
        private String host = "localhost";
    
        /**
         * RabbitMQ port.
         */
        private int port = 5672;
    
        /**
         * Login user to authenticate to the broker.
         */
        private String username;
    
        /**
         * Login to authenticate against the broker.
         */
        private String password;

    而这些属性值我们同样可以配置在resources下的application.properties文件里面,而配置的这些属性将会覆盖RabbitProperties类里面配置的默认值。

    #自定义rabbitmq属性值
    spring.rabbitmq.host=198.168.121.1
    spring.rabbitmq.username=root
    spring.rabbitmq.password=123456

    至此,SpringBoot自动配置的源码分析告一段落,总结如下:

    (1)SpringBoot在启动的时候会扫描所有jar包里面的META-INF/spring.properties,找出自动配置的类信息并将这些信息包装成properties对象。到时会从properties中获取EnableAutoConfiguration.class类名对应的值,然后使用@Bean注解将这些bean添加到Spring容器中。

    (2)给Spring容器添加自动配置组件时,会从properties类中获取属性值,我们可以配置自定义的属性覆盖对应xxxProperties.class类里面的默认属性值,实现个性化配置。

  • 相关阅读:
    java计算组合数
    编写一个方法,使用以上算法生成指定数目(比如1000个)的随机整数
    不用static,巧用对象.方法调用java中的函数
    主函数调用相同函数名的小知识
    poj 3608 旋转卡壳求不相交凸包最近距离;
    UVa1453或La4728 凸包+枚举(或旋转卡壳)
    hdu4666 最远曼哈顿距离
    poj2926 曼哈顿最远距离
    poj 2187 凸包加旋转卡壳算法
    UVa 10256 凸包简单应用
  • 原文地址:https://www.cnblogs.com/stm32stm32/p/10560933.html
Copyright © 2011-2022 走看看