SpringBoot自动化配置原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jeffleo/article/details/77173551

一、@EnableAutoConfiguration

SpringBoot的自动化配置原理,首先是从@SpringBootApplication开始的,这个注解是一个组合注解,核心功能时由@EnableAutoConfiguration提供的

EnableAutoConfiguration

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({EnableAutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    Class<?>[] exclude() default {};

    String[] excludeName() default {};
}

观察@EnableAutoConfiguration可以发现,这里Import了@EnableAutoConfigurationImportSelector,这就是Spring Boot自动化配置的“始作俑者”

EnableAutoConfigurationImportSelector

一路追踪代码,我们看到EnableAutoConfigurationImportSelector的关键代码在这里

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
        return SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    }

继续进入loadFactoryNames方法,便知道它的原理的(代码不贴了)

主要就是使用Spring 4 提供的的SpringFactoriesLoader工具类。通过SpringFactoriesLoader.loadFactoryNames()读取了ClassPath下面的所有META-INF/spring.factories文件(没错,是所有,也就意味着其他的starter也是在他们的jar包中定义META-INF/spring.factories文件,这样就可以让SpringBoot加载到,达到了自动化配置的目的,这也是自定义Starter的思路),并且指定了key为org.springframework.boot.autoconfigure.EnableAutoConfiguration.class

# 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,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
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.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.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration,\
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.integration.IntegrationAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
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.jms.hornetq.HornetQAutoConfiguration,\
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.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.velocity.VelocityAutoConfiguration,\
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.jta.JtaAutoConfiguration,\
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.WebMvcAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketAutoConfiguration,\
org.springframework.boot.autoconfigure.websocket.WebSocketMessagingAutoConfiguration

总结

通过@EnableAutoConfiguration启用Spring应用程序上下文的自动配置,这个注解会导入一个EnableAutoConfigurationImportSelector的类,而这个类会去读取classpath下所有的spring.factories下key为EnableAutoConfiguration对应的全限定名的值。

这个spring.factories里面配置的那些类,主要作用是告诉Spring Boot这个stareter所需要加载的那些xxxAutoConfiguration类(其实这个类的作用就是定义Bean,注册Bean,就像我们xml配置bean一样),也就是你真正的要自动注册的那些bean或功能。然后,我们实现一个spring.factories指定的类,标上@Configuration注解,这样就形成了一个Starter

二、实例分析RabbitAutoConfiguration自动化配置

我们使用RabbitMQ过程中,只要添加了RabbitMQ的依赖,我们就可以直接注入RabbitTemplate使用了,这肯定就是自动化配置帮我们做好了默认的配置,然后生成RabbitTemplate实例到Spring容器中

首先看RabbitAutoConfiguration

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

这里面的注解可以解释一下:

1、@Configuration

@Configuration 的注解类表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源,也就是说用@Configuration注解该类,等价 与XML中配置beans

扫描二维码关注公众号,回复: 3802138 查看本文章

使用Configuration

@Configuration
public class HelloWorldConfig {
   @Bean 
   public HelloWorld helloWorld(){
      return new HelloWorld();
   }
}

等价于使用xml:

<beans>
   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" />
</beans>

2、ConditionalOnClass

表示当容器中存在对应的Class文件时才会去解析RabbitAutoConfiguration,否则直接跳过不解析,这也是为什么在不导入RabbitMQ依赖Jar时工程能正常启动的原因

3、EnableConfigurationProperties

表示启动对RabbitProperties.class的内嵌配置支持,自动将RabbitProperties注册为一个bean。这个RabbitProperties类里面就是关于RabbitMQ的属性的配置

@ConfigurationProperties(prefix = "spring.rabbitmq")  
public class RabbitProperties {  

    /**  
     * RabbitMQ host.  
     */  
    private String host = "localhost";  

    /**  
     * RabbitMQ port.  
     */  
    private int port = 5672;   .... //省略部分代码}  

4、更多

@ConditionalBean:当容器中存在对应的bean,才会去解析
@ConditionalOnMissingBean:当容器中不存在对应的Bean时,才会去解析
@ConditionalOnMissingClass:当容器中不存在对应的class文件时,才会去解析
@ConditionalOnProperty:当指定的属性存在指定的值时,才会去解析
@ConditionalOnResource:当类路径存在指定的值时,才会去解析

5、生成RabbitTemplate实例

我们继续分析RabbitAutoConfiguration
上面说到了@Configuration的作用,也就是说,我们可以直接把RabbitAutoConfiguration这个类当成我们xml中的配置

首先生成ConnectionFactory

@Configuration
    @ConditionalOnMissingBean({ConnectionFactory.class})
    protected static class RabbitConnectionFactoryCreator {
        protected RabbitConnectionFactoryCreator() {
        }

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

            if(config.getUsername() != null) {
                factory.setUsername(config.getUsername());
            }

            if(config.getPassword() != null) {
                factory.setPassword(config.getPassword());
            }

            if(config.getVirtualHost() != null) {
                factory.setVirtualHost(config.getVirtualHost());
            }

            if(config.getRequestedHeartbeat() != null) {
                factory.setRequestedHeartbeat(config.getRequestedHeartbeat().intValue());
            }

            Ssl ssl = config.getSsl();
            if(ssl.isEnabled()) {
                factory.setUseSSL(true);
                if(ssl.getAlgorithm() != null) {
                    factory.setSslAlgorithm(ssl.getAlgorithm());
                }

                factory.setKeyStore(ssl.getKeyStore());
                factory.setKeyStorePassphrase(ssl.getKeyStorePassword());
                factory.setTrustStore(ssl.getTrustStore());
                factory.setTrustStorePassphrase(ssl.getTrustStorePassword());
            }

            factory.afterPropertiesSet();
            CachingConnectionFactory connectionFactory = new CachingConnectionFactory((com.rabbitmq.client.ConnectionFactory)factory.getObject());
            connectionFactory.setAddresses(config.getAddresses());
            return connectionFactory;
        }
    }

这个方法虽长,本质就是生成了一个connectionFactory

然后生成RabbitTemplate实例

 @Bean
 @ConditionalOnMissingBean({RabbitTemplate.class})
 public RabbitTemplate rabbitTemplate() {
     return new RabbitTemplate(this.connectionFactory);
 }

总结

至此,我们终于了解了SpringBoot的自动化配置原理,SpringBoot的starter的奥秘就在于此

猜你喜欢

转载自blog.csdn.net/jeffleo/article/details/77173551