美文网首页
SpringBoot-AutoConfiguration

SpringBoot-AutoConfiguration

作者: lazyguy | 来源:发表于2017-10-11 14:42 被阅读0次

    springBoot的自动注册

    整个springboot并没有在spring的基础上提供什么额外的功能。
    springBoot的最大作用就是引入某些jar包后,自动为spring上下文环境生成某些特定功能的Bean,这样就可以自动提供某些相关功能。
    本质上,spring通过被标记了@Configuration的类提供一些提前生成好的Bean提供特别的功能,而用@Contional系列的注解限制生成的条件,通常就是@ConditionalOnClass和@ConditionalOnMissingBean注解的配合使用。前者确定某些功能需要的class已经有了,后者确定你没有自己生成相关的bean,才提供默认的。

    spring-boot-autoconfigure

    spring通过spring-boot-autoconfigure这个jar提供大量的自动注册功能。
    springboot启动的时候会扫描jar下是否有 META-INF/spring.factories 文件,这个文件中包含了你需要自动注册的java类。
    比如spring-boot-autoconfigure这个jar下的META-INF/spring.factories文件提供了大量自动注册的配置类:

    # Initializers
    org.springframework.context.ApplicationContextInitializer=\
    org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
    org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer
    
    # Application Listeners
    org.springframework.context.ApplicationListener=\
    org.springframework.boot.autoconfigure.BackgroundPreinitializer
    
    # Auto Configuration Import Listeners
    org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
    org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
    
    # Auto Configuration Import Filters
    org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
    org.springframework.boot.autoconfigure.condition.OnClassCondition
    
    # 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
    
    # Failure analyzers
    org.springframework.boot.diagnostics.FailureAnalyzer=\
    org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
    org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\
    org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer
    
    # Template availability providers
    org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
    org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
    org.springframework.boot.autoconfigure.mustache.MustacheTemplateAvailabilityProvider,\
    org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAvailabilityProvider,\
    org.springframework.boot.autoconfigure.thymeleaf.ThymeleafTemplateAvailabilityProvider,\
    org.springframework.boot.autoconfigure.web.JspTemplateAvailabilityProvider
    

    由于springboot自己提供了这么多自动注册类,我们自己也可能写一些自动注册类。为了确定他们直接的生效顺序。我可以使用@AutoConfigureBefore,@AutoConfigureAfter,@AutoconfigureOrder 来确定某个自动注册类的生效顺序。作用类比@Order。

    注意:自动注册的类需要放到特定的包中,避免被应用的@ComponentScan扫描到。

    自动注册一般我们提供2个module:一个是autoconfigure jar包,一个是starter jar包。
    其中starter这种jar里面并没有代码,是空的。唯一的作用是将需要的各种jar写入构建文件,这样引入此starter,就不要再去关心相应的其他jar了。
    比如spring提供的 spring-boot-starter-data-redis 这个jar什么都没有,只是pom文件引入了使用spring-data-redis中的功能需要的相关jar。

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
            </dependency>
    </dependencies>
    

    而spring提供的spring-boot-autoconfigure里面有相关的类会根据相应的条件生成redis功能需要的bean,所以我们只需要加入springboot提供的spring-boot-starter-xxx 的jar就可以自动生成相应功能的bean了。

    image.png
    其中
    RedisProperties 是负责整合使用redis功能需要的相关配置.有关@ConfigurationProperties的作用解释:http://www.jianshu.com/p/552bc222ebe6
    RedisAutoConfiguration
    @Configuration
    @ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
    @EnableConfigurationProperties(RedisProperties.class)
    public class RedisAutoConfiguration {
    
        /**
         * Redis connection configuration.
         */
        @Configuration
        @ConditionalOnClass(GenericObjectPool.class)
        protected static class RedisConnectionConfiguration {
               ……略
        }
    
        /**
         * Standard Redis configuration.
         */
        @Configuration
        protected static class RedisConfiguration {
                ……略
        }
    
    }
    

    这个类里面有2个子类,一个RedisConfiguration,RedisConnectionConfiguration。
    先看简单的,RedisConfiguration:

    /**
         * Standard Redis configuration.
         */
        @Configuration
        protected static class RedisConfiguration {
            //当spring上下文中没有name叫redisTemplate的bean就会自动生成RedisTemplate
            //当然前提是的上下文中已经有RedisConnectionFactory了,否则自动注入失败会报错
            @Bean
            @ConditionalOnMissingBean(name = "redisTemplate")
            public RedisTemplate<Object, Object> redisTemplate(
                    RedisConnectionFactory redisConnectionFactory)
                            throws UnknownHostException {
                RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
                template.setConnectionFactory(redisConnectionFactory);
                return template;
            }
             //同理当上下文中没有类型为StringRedisTemplate的Bean就会自动生成StringRedisTemplate。
            //同理需要注入RedisConnectionFactory
            @Bean
            @ConditionalOnMissingBean(StringRedisTemplate.class)
            public StringRedisTemplate stringRedisTemplate(
                    RedisConnectionFactory redisConnectionFactory)
                            throws UnknownHostException {
                StringRedisTemplate template = new StringRedisTemplate();
                template.setConnectionFactory(redisConnectionFactory);
                return template;
            }
    
        }
    

    所以这个类到底干嘛呢?就是为spring上下文生成一个RedisTemplate,一个StringRedisTemp。好供用户操作redis。
    第二个类, RedisConnectionConfiguration:

        /**
         * Redis connection configuration.
         */
        @Configuration
        //这个条件是指需要commons-pool这个jar,因为jedis底层依赖此jar提供连接池的能力
        @ConditionalOnClass(GenericObjectPool.class)
        protected static class RedisConnectionConfiguration {
    
            private final RedisProperties properties;
    
            private final RedisSentinelConfiguration sentinelConfiguration;
    
            private final RedisClusterConfiguration clusterConfiguration;
            //注入RedisProperties,就是我们autoconfigure jar里面提供的类
            //另外2个是RedisSentinelConfiguration,RedisClusterConfiguration。但这2个bean并
            //不一定有,所以,使用ObjectProvider#getIfAvailable
            public RedisConnectionConfiguration(RedisProperties properties,
                    ObjectProvider<RedisSentinelConfiguration> sentinelConfigurationProvider,
                    ObjectProvider<RedisClusterConfiguration> clusterConfigurationProvider) {
                this.properties = properties;
                this.sentinelConfiguration = sentinelConfigurationProvider.getIfAvailable();
                this.clusterConfiguration = clusterConfigurationProvider.getIfAvailable();
            }
            //如果没有RedisConnectionFactory的bean,生成JedisConnectionFactory
            //同时为JedisConnectionFactory注入RedisProperties中的基本属性
            @Bean
            @ConditionalOnMissingBean(RedisConnectionFactory.class)
            public JedisConnectionFactory redisConnectionFactory()
                    throws UnknownHostException {
                return applyProperties(createJedisConnectionFactory());
            }
            //为JedisConnectionFactory注入host,port,password,database,timeout等基本属性
            protected final JedisConnectionFactory applyProperties(
                    JedisConnectionFactory factory) {
                factory.setHostName(this.properties.getHost());
                factory.setPort(this.properties.getPort());
                if (this.properties.getPassword() != null) {
                    factory.setPassword(this.properties.getPassword());
                }
                factory.setDatabase(this.properties.getDatabase());
                if (this.properties.getTimeout() > 0) {
                    factory.setTimeout(this.properties.getTimeout());
                }
                return factory;
            }
            //下面几个方法的作用类似,就是检查spring上下文中是否已经有sentinel,cluster的配置
            //bean(从构造函数注入的刚才),如果有,就用已有的,没有,就用
            //从RedisProperties中写入的属性生成。
            protected final RedisSentinelConfiguration getSentinelConfig() {
                if (this.sentinelConfiguration != null) {
                    return this.sentinelConfiguration;
                }
                Sentinel sentinelProperties = this.properties.getSentinel();
                if (sentinelProperties != null) {
                    RedisSentinelConfiguration config = new RedisSentinelConfiguration();
                    config.master(sentinelProperties.getMaster());
                    config.setSentinels(createSentinels(sentinelProperties));
                    return config;
                }
                return null;
            }
                   
            /**
             * Create a {@link RedisClusterConfiguration} if necessary.
             * @return {@literal null} if no cluster settings are set.
             */
            protected final RedisClusterConfiguration getClusterConfiguration() {
                if (this.clusterConfiguration != null) {
                    return this.clusterConfiguration;
                }
                if (this.properties.getCluster() == null) {
                    return null;
                }
                Cluster clusterProperties = this.properties.getCluster();
                RedisClusterConfiguration config = new RedisClusterConfiguration(
                        clusterProperties.getNodes());
    
                if (clusterProperties.getMaxRedirects() != null) {
                    config.setMaxRedirects(clusterProperties.getMaxRedirects());
                }
                return config;
            }
    
            private List<RedisNode> createSentinels(Sentinel sentinel) {
                List<RedisNode> nodes = new ArrayList<RedisNode>();
                for (String node : StringUtils
                        .commaDelimitedListToStringArray(sentinel.getNodes())) {
                    try {
                        String[] parts = StringUtils.split(node, ":");
                        Assert.state(parts.length == 2, "Must be defined as 'host:port'");
                        nodes.add(new RedisNode(parts[0], Integer.valueOf(parts[1])));
                    }
                    catch (RuntimeException ex) {
                        throw new IllegalStateException(
                                "Invalid redis sentinel " + "property '" + node + "'", ex);
                    }
                }
                return nodes;
            }
    
            private JedisConnectionFactory createJedisConnectionFactory() {
                JedisPoolConfig poolConfig = this.properties.getPool() != null
                        ? jedisPoolConfig() : new JedisPoolConfig();
    
                if (getSentinelConfig() != null) {
                    return new JedisConnectionFactory(getSentinelConfig(), poolConfig);
                }
                if (getClusterConfiguration() != null) {
                    return new JedisConnectionFactory(getClusterConfiguration(), poolConfig);
                }
                return new JedisConnectionFactory(poolConfig);
            }
    
            private JedisPoolConfig jedisPoolConfig() {
                JedisPoolConfig config = new JedisPoolConfig();
                RedisProperties.Pool props = this.properties.getPool();
                config.setMaxTotal(props.getMaxActive());
                config.setMaxIdle(props.getMaxIdle());
                config.setMinIdle(props.getMinIdle());
                config.setMaxWaitMillis(props.getMaxWait());
                return config;
            }
    
        }
    

    所以RedisConnectionConfiguration的主要作用就是在没有RedisConnectionFactory的时候,通过RedisProperties提供的属性,生成前文提到的RedisConnectionFactory(为RedisTemplate使用)

    相关文章

      网友评论

          本文标题:SpringBoot-AutoConfiguration

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