SpringBoot-自動構成ソース解析

24919 ワード

次に、前のブログ「SpringBoot-快速構築WEBプロジェクト」が提出した分析が必要な3つの面を深く探究します.SpringBootがどのように構成ファイルが1つもない状況で完全なWEBプロジェクトをスタートさせたのか、まず@SpringBootApplicationからここの分析は副次的な情報を切り取って主幹に沿って歩くので、少し省略するところがあるかもしれません.以下のソースコードはspring-boot-1.4.0から切り取る.RELEASE
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class))
public @interface SpringBootApplication {}

@Target,@Retention,@Documented,@Inheritedの4つの注釈はあまり説明されていない複合注釈であることがわかる.ComponentScanこれはSpringでよく使われる注釈で説明もしません.次に@SpringBootConfigurationを見てみましょう.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {}

この注釈は、@Configuration:現在のクラスを:JavaConfigクラスとしてマークします.最後の注釈を見てみましょう.@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

この注記の@Import(E n a b l e A u t o C o n f i g u r a t i o n f i g u r ationImportSelector.class)は、他のSpringを導入したJavaConfigを表し、E n a b l e A t o u C o n f i g u r ationImportSelectorに進む.classは以下の方法に注目します.
@Override
public String[] selectImports(AnnotationMetadata metadata) {
    if (!isEnabled(metadata)) {
        return NO_IMPORTS;
    }
    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);
    }
}

アクセス:List configurations=getCandidateConfigurations(metadata,attributes);
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;
}

アクセス:List configurations=SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); コードは次のとおりです.
public static List loadFactoryNames(Class> factoryClass, ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    try {
        Enumeration urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
                ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
        List result = new ArrayList();
        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_RESOURCE_LOCATION + "]", ex);
    }
}
public static final String FACTORIES_RESOURCE_LOCATION = 
"META-INF/spring.factories";

上記のコードでは、自動コンフィギュレーションが受信factoryClassに従うことがわかります.getName()からspring.factoriesのファイルには対応するkeyが見つかり、中のクラスをロードしますがspring-boot-autoconfigure-1.4.0を開きます.RELEASE.义齿factoriesは多くのkeyを発見することができて、それではここはどのような1つのロードの流れですかここはコードだけを貼って説明しないで、次のブログはSpringBootが起動した全体の流れに対して深い分析《SpringBoot-起動の流れの分析》に入ります.
public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.started();
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);
        Banner printedBanner = printBanner(environment);
        context = createApplicationContext();
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        listeners.finished(context, null);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
        }
        return context;
    }
    catch (Throwable ex) {
        handleRunFailure(context, listeners, ex);
        throw new IllegalStateException(ex);
    }
}

この文章は自動構成機能を説明するだけなので、ここでは自動構成のロードがrefreshContext(context)で発生していることを示すだけです.この一言.紙面の都合でここで一部を切り取ったので、完全にspring-boot-autoconfigure-1.4.0に行ってください.RELEASE.JArパッケージにspringを表示します.factoriesファイル.
# 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.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.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.data.redis.RedisAutoConfigurationの例では、次のコードが表示されます.
@Configuration
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
@EnableConfigurationProperties(RedisProperties.class)
public class RedisAutoConfiguration {
    @Configuration
    @ConditionalOnClass(GenericObjectPool.class)
    protected static class RedisConnectionConfiguration {
        @Bean
        @ConditionalOnMissingBean(RedisConnectionFactory.class)
        public JedisConnectionFactory redisConnectionFactory()
                throws UnknownHostException {
            return applyProperties(createJedisConnectionFactory());
        }
    }
    @Configuration
    protected static class RedisConfiguration {
        @Bean
        @ConditionalOnMissingBean(name = "redisTemplate")
        public RedisTemplate redisTemplate(
                RedisConnectionFactory redisConnectionFactory)
                        throws UnknownHostException {
            RedisTemplate template = new RedisTemplate();
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }
        @Bean
        @ConditionalOnMissingBean(StringRedisTemplate.class)
        public StringRedisTemplate stringRedisTemplate(
                RedisConnectionFactory redisConnectionFactory)
                        throws UnknownHostException {
            StringRedisTemplate template = new StringRedisTemplate();
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }

    }
}

クラスを簡略化すると基本的にSpringの注釈版の構成であることがわかります@ConditionalOnClass({JedisConnection.class,RedisOperations.class,Jedis.class})この注釈の意味はJedisConnectionが存在する場合です.class, RedisOperations.class, Jedis.classの3つのクラスはRedisAutoConfiguration構成クラスを解析します.そうしないと、この構成クラスを解析しません.@C o n t i o tionalOnMissingBean(name="redisTemplate")この注釈は、コンテナにnameで指定されたbeanが存在しない場合はbean注入を作成します.そうしないと、内部コードを実行しないと、@Configuration注釈付きの構成クラスが2つ定義されていることがわかります.この2つの構成クラスはSpringIOCコンテナに3つのbeanを注入する可能性があります.まずクラスパスの下に(GenericObjectPool.class)が存在する場合、JedisConnectionFactoryのインスタンスを注入します.Springコンテナにname=「redisTemplate」のエンティティが存在しない場合、RedisTemplateとStringRedisTemplateのインスタンス注入コンテナを作成します.これによりSpringのプロジェクトでは、任意のSpring管理のbeanにRedisTemplateとStringRedisTemplateのインスタンスを登録してredisを操作することができます.以上の分析の過程により、SpringBootプロジェクトに基づくクラスパスの下にJedisConnectionが存在することが分かった.class, RedisOperations.class, Jedis.classは自動化構成をトリガーすることができ、mavenのプロジェクトでspring-data-redis-1.7.2に依存すればよいという意味です.RELEASE.JArとC:jedis-2.8.2.JArは自動構成をトリガーできますが、1つの機能を統合するたびに自動化構成クラスを分析するわけではありません.それは箱を開けてすぐに使う効果にはなりません.Spring-bootは、redisのstartのような自動構成をトリガするすべてのクラスの依存セットを直接構成できる統一的なstarterを提供してくれました.
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-redisartifactId>
dependency>

ここではspring-boot-starter-data-redisのソースコードのpomを切り取る.xmlファイル内のすべての依存:
<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starterartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.datagroupId>
        <artifactId>spring-data-redisartifactId>
    dependency>
    <dependency>
        <groupId>redis.clientsgroupId>
        <artifactId>jedisartifactId>
    dependency>
dependencies>

maven依存の伝達性のため,starterに依存するだけでクラスパスの下ですべてのトリガ自動構成のすべてのクラスを構成し,開梱即用の機能を実現することができる.ここではSpringBootのStarterの使い方を大まかに説明しただけで、後で自作のstarterを説明するときにも深く説明します.