上一节:springboot开发笔记-(8)-配置文件的加载程序
springboot主动拆卸原理和两个注解类的关系是深有千千结: @EnableAutoConfiguration和@Conditinal
咱们从springboot的启动类上的注解看下这千头万绪: 张宇的《一言难尽》不是有这么几句:
从哪里开始 从哪里失去
我一言难尽 忍不住伤心
掂量不出爱或不爱之间的间隔
模摸糊糊中 明确你的决定
不敢勉强你 只好尴尬本人
我尴尬我本人...
9.1 从哪里开始: @SpringBootApplication
package com.niewj.springboot;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class ConfigApplication { public static void main(String[] args) { SpringApplication.run(ConfigApplication.class, args); }}
@SpringBootApplication:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration // 1@EnableAutoConfiguration // 2@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class), @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication {}
咱们来说下这两个注解的性能 :
// 1. 次要是讲此类标识为: @Configuration, 作为配置类, 让spring容器启动辨认;
// 2. @EnableAutoConfiguration次要是主动拆卸; 上面细说 它;
9.2 主动拆卸去: @EnableAutoConfiguration:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage // 3@Import(AutoConfigurationImportSelector.class) // 4public @interface EnableAutoConfiguration
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(AutoConfigurationPackages.Registrar.class) // 5public @interface AutoConfigurationPackage {}
// 3. @AutoConfigurationPackage 次要做了什么? 看注解链:
@SpringBootApplication -> @EnableAutoConfiguration -> @AutoConfigurationPackage -> @Import(AutoConfigurationPackages.Registrar.class)
好了, 咱们就次要看看 AutoConfigurationPackages.Registrar.class
做了什么咱们见不得的事件:
参见上面的 #9.2.1 而后小结:
把入口类的package名, 注册到容器的Bean定义中, 后续扫描注解用(@Component/@Service/@Controller/@Repository等)
// 4. @Import(AutoConfigurationImportSelector.class) 咱们也另立门户:
参见上面的 #9.2.2 而后小结:
做了啥啥啥
9.2.1 AutoConfigurationPackages.Registrar.class
/** * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing * configuration. */static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { register(registry, new PackageImport(metadata).getPackageName()); } @Override public Set<Object> determineImports(AnnotationMetadata metadata) { return Collections.singleton(new PackageImport(metadata)); }}
实现了 ImportBeanDefinitionRegistrar
接口, 也就是说, 是向容器中注册Bean的(不明确的能够参考:spring注解驱动开发-(5) 向Spring容器中注册组件的办法), 注册什么Bean呢?
register(registry, new PackageImport(metadata).getPackageName());
打个断点debug看看: 相当于向容器中注册了以后入口类的包名, 后续扫描包下注解的时候就能够用到了!
原来如此, 小结: AutoConfigurationPackages.Registrar.class
的性能如其名: 把入口类的package名注册到容器的Bean定义中以供后续加载和扫描注解用; 比方 @Component/@Service/@Controller/@Repository等这些;
9.2.2 @Import(AutoConfigurationImportSelector.class)
@Import就不必介绍了(能够参考文末的链接): 向容器中注册一个一般Bean的; 那么AutoConfigurationImportSelector
是一个什么样的一般Bean呢?
@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader .loadMetadata(this.beanClassLoader); // ==>要害在这里: getAutoConfigurationEntry() AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}/** * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata} * of the importing {@link Configuration @Configuration} class. * @param autoConfigurationMetadata the auto-configuration metadata * @param annotationMetadata the annotation metadata of the configuration class * @return the auto-configurations that should be imported */protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); // ==>要害在这里:getCandidateConfigurations() List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = filter(configurations, autoConfigurationMetadata); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions);}/** * 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) { // ==>要害在这里: SpringFactoriesLoader.loadFactoryNames() 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;}
那么外围问题来了, SpringFactoriesLoader的loadFactoryNames()是作甚的?
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());/** * Load the fully qualified class names of factory implementations of the * given type from {@value #FACTORIES_RESOURCE_LOCATION}, using the given * class loader. * @param factoryType the interface or abstract class representing the factory * @param classLoader the ClassLoader to use for loading resources; can be * {@code null} to use the default * @throws IllegalArgumentException if an error occurs while loading factory names * @see #loadFactories */public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());}
Load the fully qualified class names of factory implementations of the given type from "META-INF/spring.factories", using the given class loader.
工具人翻译:
从"META-INF/spring.factories"配置文件里, 加载给定类型的工厂factoryType
实现的全限定类名, 应用给定的类加载器。
例如 org.springframework.boot.autoconfigure包下的 spring-boot-autoconfigure-2.2.2.RELEASE.jar中的"META-INF/spring.factories"
# Initializersorg.springframework.context.ApplicationContextInitializer=\org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener# Application Listenersorg.springframework.context.ApplicationListener=\org.springframework.boot.autoconfigure.BackgroundPreinitializer# Auto Configuration Import Listenersorg.springframework.boot.autoconfigure.AutoConfigurationImportListener=\org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener# Auto Configuration Import Filtersorg.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\org.springframework.boot.autoconfigure.condition.OnBeanCondition,\org.springframework.boot.autoconfigure.condition.OnClassCondition,\org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition# Auto Configureorg.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.CloudServiceConnectorsAutoConfiguration,\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.CassandraReactiveDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\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.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveRestClientAutoConfiguration,\org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration,\org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\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.RedisReactiveAutoConfiguration,\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.elasticsearch.rest.RestClientAutoConfiguration,\org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\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.http.HttpMessageConvertersAutoConfiguration,\org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration,\org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration,\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.groovy.template.GroovyTemplateAutoConfiguration,\org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration,\org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration,\org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration,\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.mongo.embedded.EmbeddedMongoAutoConfiguration,\org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration,\org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration,\org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration,\org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration,\org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration,\org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration,\org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration,\org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration,\org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration,\org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration,\org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration,\org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration,\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.client.RestTemplateAutoConfiguration,\org.springframework.boot.autoconfigure.web.embedded.EmbeddedWebServerFactoryCustomizerAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.ReactiveWebServerFactoryAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration,\org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration,\org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration,\org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration,\org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration,\org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration,\org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration,\org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration# Failure analyzersorg.springframework.boot.diagnostics.FailureAnalyzer=\org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\org.springframework.boot.autoconfigure.flyway.FlywayMigrationScriptMissingFailureAnalyzer,\org.springframework.boot.autoconfigure.jdbc.DataSourceBeanCreationFailureAnalyzer,\org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer,\org.springframework.boot.autoconfigure.session.NonUniqueSessionRepositoryFailureAnalyzer# Template availability providersorg.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.servlet.JspTemplateAvailabilityProvider
到这里是不是感觉快迷失了? 回顾下下面那句歌词:从哪里开始 从哪里失去
感觉是不是很恐怖? 好了, 咱们收住!
小结一下: @Import(AutoConfigurationImportSelector.class)次要做的事:
- 因为
ImportSelector
接口就是返回一个 类名的字符串数组String[]
, 而后交给spring容器让它来把这些字符串模式的类初始化了, 而后都注册到容器中;- 这里就是, 应用 @EnableAutoConfiguration 的全限定名去它所在的jar包spring-boot-autoconfigure.jar上来找
META-INF/spring.factories
, 而后去读取那124个类, 转换成String[]
(当然不是全副, 上面的@Conditinal就是限定满足条件的才会放进去! 如下图的debug状态, 通过filter后, 只剩下了24个)- 那么这24个类都做了什么呢? 其实就相似于咱们本人写一个配置类(标注@Configuration), 而后提供初始化Bean的办法(标注@Bean), 让它注册到容器中被容器治理; 只不过是这样的类多了, 不免凌乱, 这种治理形式只是为了对立, 简洁!
也就是说, 如果加载类是: org.springframework.boot.autoconfigure.EnableAutoConfiguration
就能读取到这么多全限定类名, 没错, 我数了下, 一共 124 个类
filter图:
9.3 @Conditional和xxxAutoConfiguration类
紧接着下面的124个类-->那么问题来了:
这些类是干嘛的?
向容器中提供注册Bean的, 各种性能的Bean, 相似于咱们本人的@Configuration + @Bean;
这些类124个都加载注册到容器中吗?
不是的, 是有条件的:@Conditinal
这是什么操作? 为什么有
SpringFactoriesLoader
? 为什么有META-INF/spring.factories
? 这都是什么鬼?SPI 机制(Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动静加载机制), 很多中央有用到:
- JDBC加载不同类型数据库的驱动
- 日志门面类和具体的日志实现
- Dubbo
参考: 高级开发必须了解的Java中SPI机制
9.3.1 Conditional相干注解一览
springboot中常见的 Conditinal以及其用意:
@Conditional@ConditionalOnJava // 零碎的java版本是否符合要求@ConditionalOnBean // 容器中存在指定的Bean@ConditionalOnClass // 零碎中有指定的类@ConditionalOnProperty // 零碎中指定的属性是否有指定的值@ConditionalOnWebApplication // 以后是Web环境@ConditionalOnNotWebApplication // 以后不是web环境@ConditionalOnResource // 类门路下是否存在指定的资源文件@ConditionalOnMissingBean // 容器中不存在指定的Bean@ConditionalOnMissingClass // 零碎中不存在指定类@ConditionalOnSingleCandidate // 容器中只有一个指定Bean, 或者这个Bean是首选Bean(primary的)
9.3.2 几个示例
上面咱们找几个springboot中的XXXAutoConfiguration的示例:
示例1: AOP主动拆卸类
AopAutoConfiguration源码(正文删去了)
package org.springframework.boot.autoconfigure.aop;import org.aspectj.weaver.Advice;import org.springframework.aop.config.AopConfigUtils;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.support.BeanDefinitionRegistry;import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.EnableAspectJAutoProxy;@Configuration(proxyBeanMethods = false)@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) // ===> #1.public class AopAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnClass(Advice.class) // ==> #2 static class AspectJAutoProxyingConfiguration { @Configuration(proxyBeanMethods = false) @EnableAspectJAutoProxy(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false) static class JdkDynamicAutoProxyConfiguration { } @Configuration(proxyBeanMethods = false) @EnableAspectJAutoProxy(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) static class CglibAutoProxyConfiguration { } } @Configuration(proxyBeanMethods = false) @ConditionalOnMissingClass("org.aspectj.weaver.Advice") // ==> #3 @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) static class ClassProxyingConfiguration { ClassProxyingConfiguration(BeanFactory beanFactory) { if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } } }}
// #1. @ConditionalOnProperty
(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
类上注解: 是说只有在配置文件里能找到: spring.aop.auto=true 此类才注册到容器; matchIfMissing限定是否肯定要匹配为true, 这里阐明 不为true 也注册;
// #2. @ConditionalOnClass
(Advice.class)
类上注解: 只有在零碎中能找到类文件 Advice.class 时 才注册AspectJAutoProxyingConfiguration
示例2: DispatcherServlet主动拆卸类
DispatcherServletAutoConfiguration源码部分(删去局部正文)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@Configuration(proxyBeanMethods = false)// #1 只在web环境下能力拆卸, 且是servlet的环境下;@ConditionalOnWebApplication(type = Type.SERVLET) // #2 只有零碎中有类 DispatcherServlet 存在能力拆卸;@ConditionalOnClass(DispatcherServlet.class)@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)public class DispatcherServletAutoConfiguration { /* * The bean name for a DispatcherServlet that will be mapped to the root URL "/" */ public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet"; /* * The bean name for a ServletRegistrationBean for the DispatcherServlet "/" */ public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration"; @Configuration(proxyBeanMethods = false) // #3 括号中的类DefaultDispatcherServletCondition定义了条件 @Conditional(DefaultDispatcherServletCondition.class) // #4 上面所有都是零碎有ServletRegistration类才拆卸 @ConditionalOnClass(ServletRegistration.class) @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class }) protected static class DispatcherServletConfiguration { @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME) public DispatcherServlet dispatcherServlet(HttpProperties httpProperties, WebMvcProperties webMvcProperties) { DispatcherServlet dispatcherServlet = new DispatcherServlet(); dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest()); dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest()); dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound()); dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents()); dispatcherServlet.setEnableLoggingRequestDetails(httpProperties.isLogRequestDetails()); return dispatcherServlet; } @Bean @ConditionalOnBean(MultipartResolver.class) // ==>#5 @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) // ==>#6 public MultipartResolver multipartResolver(MultipartResolver resolver) { // Detect if the user has created a MultipartResolver but named it incorrectly return resolver; } } ......省略前面局部......}
阐明见类正文中;
另外阐明:
咱们在基于注解的spring开发中没有配置 DispatcherServlet, 就是因为这个DispatcherServlet主动拆卸类在起作用, 这里向容器中注册了一个Bean:public DispatcherServlet dispatcherServlet()
这块! 相干的配置信息都在参数类:WebMvcProperties
中(天然它也是容器中已注册的.)
示例3: WebMvc主动拆卸类
@Configuration(proxyBeanMethods = false)// 1. 要求servlet的web环境;@ConditionalOnWebApplication(type = Type.SERVLET) // 2. 要求能找到Servlet/DispatcherServlet/WebMvcConfigure这几个类才拆卸@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) // 3. 要求容器中没有已注册的Bean WebMvcConfigurationSupport的示例才会拆卸;@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class })public class WebMvcAutoConfiguration {}
参考文档:
- 【Spring Boot源码剖析】@EnableAutoConfiguration注解(一)@AutoConfigurationImportSelector注解的解决
- 高级开发必须了解的Java中SPI机制