SpringBoot之自动配置


声明:本文转载自https://my.oschina.net/qixiaobo025/blog/1574084,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

背景

提到SpringBoot各位开发者大概能想到一些标签 “新” “快” “FatJar” “微服务” “SpringCloud” “约定大约配置” “开箱即用” “starter" "EmbedTomcat" ”Spring全家桶“ ”profile“ ”注解“

事实上SpringBoot基于Spring提供了大量的配置帮开发者做了许多默认配置【一定程度上帮开发者搞定了许多默认配置 但是稍有不慎也可能导致出现一些奇怪的问题】

本篇简单梳理一下自动配置的实现

源码

SpringBoot的启动代码 通常都是一句

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

我们来关注一下做了哪些操作

/**  * Static helper that can be used to run a {@link SpringApplication} from the  * specified source using default settings.  * @param source the source to load  * @param args the application arguments (usually passed from a Java main method)  * @return the running {@link ApplicationContext}  */ public static ConfigurableApplicationContext run(Object source, String... args) {    return run(new Object[] { source }, args); } /**  * Static helper that can be used to run a {@link SpringApplication} from the  * specified sources using default settings and user supplied arguments.  * @param sources the sources to load  * @param args the application arguments (usually passed from a Java main method)  * @return the running {@link ApplicationContext}  */ public static ConfigurableApplicationContext run(Object[] sources, String[] args) {    return new SpringApplication(sources).run(args); }

首先创建了SpringApplication实例 其次调用对应的run方法

@SuppressWarnings({ "unchecked", "rawtypes" }) private void initialize(Object[] sources) {    if (sources != null && sources.length > 0) {       this.sources.addAll(Arrays.asList(sources));    }    this.webEnvironment = deduceWebEnvironment();    setInitializers((Collection) getSpringFactoriesInstances(          ApplicationContextInitializer.class));    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));    this.mainApplicationClass = deduceMainApplicationClass(); }   private boolean deduceWebEnvironment() {    for (String className : WEB_ENVIRONMENT_CLASSES) {       if (!ClassUtils.isPresent(className, null)) {          return false;       }    }    return true; }   private Class<?> deduceMainApplicationClass() {    try {       StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();       for (StackTraceElement stackTraceElement : stackTrace) {          if ("main".equals(stackTraceElement.getMethodName())) {             return Class.forName(stackTraceElement.getClassName());          }       }    }    catch (ClassNotFoundException ex) {       // Swallow and continue    }    return null; }

首先根据当前classpath中是否包含WEB_ENVIRONMENT_CLASSES判断是否是web环境

Spring利用spring.factories文件做了许多事情  比如一些初始化 比如一些监听器

比如SpringBoot jar中提供了如下的spring.factories

# PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader   # Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener   # Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer   # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\ org.springframework.boot.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.logging.LoggingApplicationListener   # Environment Post Processors org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor   # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer   # FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

相对扩展了spi的思想【dubbo也是类似实现】

从SpringBoot的autoConfig包下面的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
EnableAutoConfiguration这个注解表示打开自动配置

而我们通常在SpringBoot第一行就是如下

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

SpringBootApplication注解实现了大部分的功能【事实上是一个注解的聚合】

/**  * Indicates a {@link Configuration configuration} class that declares one or more  * {@link Bean @Bean} methods and also triggers {@link EnableAutoConfiguration  * auto-configuration} and {@link ComponentScan component scanning}. This is a convenience  * annotation that is equivalent to declaring {@code @Configuration},  * {@code @EnableAutoConfiguration} and {@code @ComponentScan}.  *  * @author Phillip Webb  * @author Stephane Nicoll  * @since 1.2.0  */ @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 {      /**     * Exclude specific auto-configuration classes such that they will never be applied.     * @return the classes to exclude     */    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")    Class<?>[] exclude() default {};      /**     * Exclude specific auto-configuration class names such that they will never be     * applied.     * @return the class names to exclude     * @since 1.3.0     */    @AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")    String[] excludeName() default {};      /**     * Base packages to scan for annotated components. Use {@link #scanBasePackageClasses}     * for a type-safe alternative to String-based package names.     * @return base packages to scan     * @since 1.3.0     */    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")    String[] scanBasePackages() default {};      /**     * Type-safe alternative to {@link #scanBasePackages} for specifying the packages to     * scan for annotated components. The package of each class specified will be scanned.     * <p>     * Consider creating a special no-op marker class or interface in each package that     * serves no purpose other than being referenced by this attribute.     * @return base packages to scan     * @since 1.3.0     */    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")    Class<?>[] scanBasePackageClasses() default {};   }

SpringBoot将对应的Application注册到Spring容器中通过调用Spring的ApplicationContext refresh方法实现对应备案的处理【包括初始化 注入等等 】

其中也包括了处理注解。

比如针对CompomentScan的处理如下

private void addComponentScanningPackages(Set<String> packages,       AnnotationMetadata metadata) {    AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata          .getAnnotationAttributes(ComponentScan.class.getName(), true));    if (attributes != null) {       addPackages(packages, attributes.getStringArray("value"));       addPackages(packages, attributes.getStringArray("basePackages"));       addClasses(packages, attributes.getStringArray("basePackageClasses"));       if (packages.isEmpty()) {          packages.add(ClassUtils.getPackageName(metadata.getClassName()));       }    } }

从上述代码中可以得知 当CompomentScan没有配置value时默认注册为对应的包名【小知识点】

同样的道理对于如下注解

/**  * Enable auto-configuration of the Spring Application Context, attempting to guess and  * configure beans that you are likely to need. Auto-configuration classes are usually  * applied based on your classpath and what beans you have defined. For example, If you  * have {@code tomcat-embedded.jar} on your classpath you are likely to want a  * {@link TomcatEmbeddedServletContainerFactory} (unless you have defined your own  * {@link EmbeddedServletContainerFactory} bean).  * <p>  * When using {@link SpringBootApplication}, the auto-configuration of the context is  * automatically enabled and adding this annotation has therefore no additional effect.  * <p>  * Auto-configuration tries to be as intelligent as possible and will back-away as you  * define more of your own configuration. You can always manually {@link #exclude()} any  * configuration that you never want to apply (use {@link #excludeName()} if you don't  * have access to them). You can also exclude them via the  * {@code spring.autoconfigure.exclude} property. Auto-configuration is always applied  * after user-defined beans have been registered.  * <p>  * The package of the class that is annotated with {@code @EnableAutoConfiguration},  * usually via {@code @SpringBootApplication}, has specific significance and is often used  * as a 'default'. For example, it will be used when scanning for {@code @Entity} classes.  * It is generally recommended that you place {@code @EnableAutoConfiguration} (if you're  * not using {@code @SpringBootApplication}) in a root package so that all sub-packages  * and classes can be searched.  * <p>  * Auto-configuration classes are regular Spring {@link Configuration} beans. They are  * located using the {@link SpringFactoriesLoader} mechanism (keyed against this class).  * Generally auto-configuration beans are {@link Conditional @Conditional} beans (most  * often using {@link ConditionalOnClass @ConditionalOnClass} and  * {@link ConditionalOnMissingBean @ConditionalOnMissingBean} annotations).  *  * @author Phillip Webb  * @author Stephane Nicoll  * @see ConditionalOnBean  * @see ConditionalOnMissingBean  * @see ConditionalOnClass  * @see AutoConfigureAfter  * @see SpringBootApplication  */ @SuppressWarnings("deprecation") @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(EnableAutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration {      String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";      /**     * Exclude specific auto-configuration classes such that they will never be applied.     * @return the classes to exclude     */    Class<?>[] exclude() default {};      /**     * Exclude specific auto-configuration class names such that they will never be     * applied.     * @return the class names to exclude     * @since 1.3.0     */    String[] excludeName() default {};   }

其中引入了一个很关键的import  

EnableAutoConfigurationImportSelector

对于AutoConfigurationImportSelector

@Override public String[] selectImports(AnnotationMetadata annotationMetadata) {    if (!isEnabled(annotationMetadata)) {       return NO_IMPORTS;    }    try {       AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader             .loadMetadata(this.beanClassLoader);       AnnotationAttributes attributes = getAttributes(annotationMetadata);       List<String> configurations = getCandidateConfigurations(annotationMetadata,             attributes);       configurations = removeDuplicates(configurations);       configurations = sort(configurations, autoConfigurationMetadata);       Set<String> exclusions = getExclusions(annotationMetadata, attributes);       checkExcludedClasses(configurations, exclusions);       configurations.removeAll(exclusions);       configurations = filter(configurations, autoConfigurationMetadata);       fireAutoConfigurationImportEvents(configurations, exclusions);       return configurations.toArray(new String[configurations.size()]);    }    catch (IOException ex) {       throw new IllegalStateException(ex);    } } /**  * Return the auto-configuration class names that should be considered. By default  * this method will load candidates using {@link SpringFactoriesLoader} with  * {@link #getSpringFactoriesLoaderFactoryClass()}.  * @param metadata the source metadata  * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation  * attributes}  * @return a list of candidate configurations  */ 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; }   /**  * Return the class used by {@link SpringFactoriesLoader} to load configuration  * candidates.  * @return the factory class  */ protected Class<?> getSpringFactoriesLoaderFactoryClass() {    return EnableAutoConfiguration.class; }

当调用getCandidateConfigurations 回去获取对spring.factories 中的EnableAutoConfiguration也就是上文中我们列出的一大堆自动配置

其中默认也提供了exclude选项 同时需要判断某些候选者需要排除【毕竟某些主键我们没有用到 比如不使用redis的情况下RedisAutoConfiguration这个就不处理 】

这个涉及到一些条件bean的注册【spring高级用法 条件注入】

那么到了这里基本可以分析出我们需要自动初始化的autoConfig

如果我们要实现一个自动配置的话我们也可以通过如上方法来完成【spring.factories】

本文发表于2017年11月15日 18:33
(c)注:本文转载自https://my.oschina.net/qixiaobo025/blog/1574084,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 1907 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1