原文出自点击打开链接
这篇来先通过学习分析Spring Boot的运行原理后,根据已掌握的知识来自定义一个start pom。
Spring Boot关于自动配置的源码在spring-boot-autoconfigure-xxx.jar内。若想查看有哪些自动配置,可以查看这里的源码。可以通过下面几种方式查看当前项目中已启用和未启用的自动配置的报告。
1)运行jar包时增加--debug参数:
java -jar xx.jar --debug
2)在application中设置属性,debug=true:
- spring:
- profiles:
- active: prod
- book:
- author: jack
- name: hello world
- author:
- name: jack
- age: 18
- debug: true
此时启动,可以在控制台输出。已启用的自动配置为:
- Positive matches:
- -----------------
- DispatcherServletAutoConfiguration matched:
- - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- - @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
- DispatcherServletAutoConfiguration.DispatcherServletConfiguration matched:
- - @ConditionalOnClass found required class 'javax.servlet.ServletRegistration'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- - Default DispatcherServlet did not find dispatcher servlet beans (DispatcherServletAutoConfiguration.DefaultDispatcherServletCondition)
- DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration matched:
- - @ConditionalOnClass found required class 'javax.servlet.ServletRegistration'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- - DispatcherServlet Registration did not find servlet registration bean (DispatcherServletAutoConfiguration.DispatcherServletRegistrationCondition)
- DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration#dispatcherServletRegistration matched:
- - @ConditionalOnBean (names: dispatcherServlet; types: org.springframework.web.servlet.DispatcherServlet; SearchStrategy: all) found beans 'dispatcherServlet', 'dispatcherServlet' (OnBeanCondition)
- EmbeddedServletContainerAutoConfiguration matched:
- - @ConditionalOnWebApplication (required) found StandardServletEnvironment (OnWebApplicationCondition)
- EmbeddedServletContainerAutoConfiguration.EmbeddedTomcat matched:
- - @ConditionalOnClass found required classes 'javax.servlet.Servlet', 'org.apache.catalina.startup.Tomcat'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- - @ConditionalOnMissingBean (types: org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; SearchStrategy: current) did not find any beans (OnBeanCondition)
未启用的自动配置为:
- Negative matches:
- -----------------
- ActiveMQAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.ActiveMQConnectionFactory' (OnClassCondition)
- AopAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'org.aspectj.lang.annotation.Aspect', 'org.aspectj.lang.reflect.Advice' (OnClassCondition)
- ArtemisAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'javax.jms.ConnectionFactory', 'org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory' (OnClassCondition)
- BatchAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'org.springframework.batch.core.launch.JobLauncher', 'org.springframework.jdbc.core.JdbcOperations' (OnClassCondition)
- CacheAutoConfiguration:
- Did not match:
- - @ConditionalOnBean (types: org.springframework.cache.interceptor.CacheAspectSupport; SearchStrategy: all) did not find any beans (OnBeanCondition)
- Matched:
- - @ConditionalOnClass found required class 'org.springframework.cache.CacheManager'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition)
- CacheAutoConfiguration.CacheManagerJpaDependencyConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required class 'org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean' (OnClassCondition)
- - Ancestor org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration did not match (ConditionEvaluationReport.AncestorsMatchedCondition)
- CaffeineCacheConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'com.github.benmanes.caffeine.cache.Caffeine', 'org.springframework.cache.caffeine.CaffeineCacheManager' (OnClassCondition)
- CassandraAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required class 'com.datastax.driver.core.Cluster' (OnClassCondition)
- CassandraDataAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'com.datastax.driver.core.Cluster', 'org.springframework.data.cassandra.core.CassandraAdminOperations' (OnClassCondition)
- CassandraRepositoriesAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'com.datastax.driver.core.Session', 'org.springframework.data.cassandra.repository.CassandraRepository' (OnClassCondition)
- CloudAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required class 'org.springframework.cloud.config.java.CloudScanConfiguration' (OnClassCondition)
- CouchbaseAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'com.couchbase.client.java.CouchbaseBucket', 'com.couchbase.client.java.Cluster' (OnClassCondition)
- CouchbaseCacheConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'com.couchbase.client.java.Bucket', 'com.couchbase.client.spring.cache.CouchbaseCacheManager' (OnClassCondition)
- CouchbaseDataAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'com.couchbase.client.java.Bucket', 'org.springframework.data.couchbase.repository.CouchbaseRepository' (OnClassCondition)
- CouchbaseRepositoriesAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'com.couchbase.client.java.Bucket', 'org.springframework.data.couchbase.repository.CouchbaseRepository' (OnClassCondition)
- DataSourceAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required class 'org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType' (OnClassCondition)
- DataSourceTransactionManagerAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'org.springframework.jdbc.core.JdbcTemplate', 'org.springframework.transaction.PlatformTransactionManager' (OnClassCondition)
- DeviceDelegatingViewResolverAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required class 'org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver' (OnClassCondition)
- DeviceResolverAutoConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'org.springframework.mobile.device.DeviceResolverHandlerInterceptor', 'org.springframework.mobile.device.DeviceHandlerMethodArgumentResolver' (OnClassCondition)
- DispatcherServletAutoConfiguration.DispatcherServletConfiguration#multipartResolver:
- Did not match:
- - @ConditionalOnBean (types: org.springframework.web.multipart.MultipartResolver; SearchStrategy: all) did not find any beans (OnBeanCondition)
- EhCacheCacheConfiguration:
- Did not match:
- - @ConditionalOnClass did not find required classes 'net.sf.ehcache.Cache', 'org.springframework.cache.ehcache.EhCacheCacheManager' (OnClassCondition)
一:运作原理
关于Spring Boot的运作原理,我们还是回归到@SpringBootApplication注解上来,这个注解是一个组合注解,它的核心功能是由@EnableAutoConfiguration注解提供的,下面看看@EnableAutoConfiguration的注解的源码如下:
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by Fernflower decompiler)
- //
- package org.springframework.boot.autoconfigure;
- import java.lang.annotation.Documented;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Inherited;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- import org.springframework.context.annotation.Import;
- @Target({ElementType.TYPE})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- @AutoConfigurationPackage
- @Import({EnableAutoConfigurationImportSelector.class})
- public @interface EnableAutoConfiguration {
- String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
- Class<?>[] exclude() default {};
- String[] excludeName() default {};
- }
这里关键功能是@Import注解导入的配置功能,
- EnableAutoConfigurationImportSelector
使用SpringFactoriesLoader.loadFactoryNames方法来扫描具有META-INF/spring.factories文件的jar包,spring-boot-autoconfigure-xxx.jar里就有一个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
二:核心注解
打开上面任意一个AutoConfiguration文件,一般都有下面的条件注解,在spring-boot-autoconfigure-xxx.jar的org.springframework.boot.autocinfigure.condition包下,条件注解如下:
@ConditionalOnBean:当容器里有指定的Bean的条件下
@ConditionalOnClass:当类路径下有指定的类的条件下
@ConditionalOnExpression:基于SpEL表达式作为判断条件
@ConditionalOnJava:基于JVM版本作为判断条件
@ConditionalOnJndi:在JNDI存在的条件下查找指定的位置
@@ConditionalOnMissingBean:当容器里没有指定Bean的情况下
@ConditionalOnMissingClass:当类路径下没有指定的类的条件下
@ConditionalOnNotWebApplication:当前项目不是Web项目的条件下
@ConditionalOnProperty:指定的属性是否有指定的值
@ConditionalOnResource:类路径是否有指定的值
@ConditionalOnSingleCandidate:当指定bean在容器中只有一个,或者虽然有多个但是指定首先的Bean
@ConditionalOnWebApplication:当前项目是Web项目的条件下
这些注解都是组合了@Condition元注解,只是使用了不同的条件(Condition),
下面看看@ConditionalOnWebApplication的源代码:
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by Fernflower decompiler)
- //
- package org.springframework.boot.autoconfigure.condition;
- import java.lang.annotation.Documented;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- import org.springframework.context.annotation.Conditional;
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Conditional({OnWebApplicationCondition.class})
- public @interface ConditionalOnWebApplication {
- }
从源代码可以看出,此注解使用的条件是OnWebApplicationCondition,下面看看这个条件是如何构造的:
- //
- // Source code recreated from a .class file by IntelliJ IDEA
- // (powered by Fernflower decompiler)
- //
- package org.springframework.boot.autoconfigure.condition;
- import org.springframework.boot.autoconfigure.condition.ConditionMessage.Builder;
- import org.springframework.context.annotation.ConditionContext;
- import org.springframework.core.annotation.Order;
- import org.springframework.core.type.AnnotatedTypeMetadata;
- import org.springframework.util.ClassUtils;
- import org.springframework.util.ObjectUtils;
- import org.springframework.web.context.WebApplicationContext;
- import org.springframework.web.context.support.StandardServletEnvironment;
- @Order(-2147483628)
- class OnWebApplicationCondition extends SpringBootCondition {
- private static final String WEB_CONTEXT_CLASS = "org.springframework.web.context.support.GenericWebApplicationContext";
- OnWebApplicationCondition() {
- }
- public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
- boolean required = metadata.isAnnotated(ConditionalOnWebApplication.class.getName());
- ConditionOutcome outcome = this.isWebApplication(context, metadata, required);
- if (required && !outcome.isMatch()) {
- return ConditionOutcome.noMatch(outcome.getConditionMessage());
- } else {
- return !required && outcome.isMatch() ? ConditionOutcome.noMatch(outcome.getConditionMessage()) : ConditionOutcome.match(outcome.getConditionMessage());
- }
- }
- private ConditionOutcome isWebApplication(ConditionContext context, AnnotatedTypeMetadata metadata, boolean required) {
- Builder message = ConditionMessage.forCondition(ConditionalOnWebApplication.class, new Object[]{required ? "(required)" : ""});
- if (!ClassUtils.isPresent("org.springframework.web.context.support.GenericWebApplicationContext", context.getClassLoader())) {
- return ConditionOutcome.noMatch(message.didNotFind("web application classes").atAll());
- } else {
- if (context.getBeanFactory() != null) {
- String[] scopes = context.getBeanFactory().getRegisteredScopeNames();
- if (ObjectUtils.containsElement(scopes, "session")) {
- return ConditionOutcome.match(message.foundExactly("'session' scope"));
- }
- }
- if (context.getEnvironment() instanceof StandardServletEnvironment) {
- return ConditionOutcome.match(message.foundExactly("StandardServletEnvironment"));
- } else {
- return context.getResourceLoader() instanceof WebApplicationContext ? ConditionOutcome.match(message.foundExactly("WebApplicationContext")) : ConditionOutcome.noMatch(message.because("not a web application"));
- }
- }
- }
- }
从isWebApplication方法可以看出,判断条件是:
1)GenericWebApplicationContext是否在类路径中
2)容器里是否为session的scope
3)当前容器的Enviroment是否为StandardServletEnvironment
4)当前的ResourceLoader是否为WebApplicationContext
5)我们需要构造ConditionOutcome类的对象来帮助我们,最终通过ConditionOutcome.isMatch方法返回布尔值来确定条件
三:实战
下面我们自己来写一个starter pom,这意味着我们不仅有自动配的功能,而且具有更通用的藕合度更低的配置。为了方便理解,在这里将Bean的属性在application.yml中配置
1,新建start的Maven项目,这里我为了管理,把这个项目作为module,如图所示:
修改pom.xml代码如下:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>SpringCloudTwo</artifactId>
- <groupId>com.jack</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>com.jack.springboot-starter-hello</artifactId>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-autoconfigure</artifactId>
- <version>1.5.6.RELEASE</version>
- </dependency>
- </dependencies>
- </project>
上面增加了Spring Boot自身的自动配置作为依赖。
2,属性配置,代码如下:
- package com.jack.springboot.starter.hello;
- import org.springframework.boot.context.properties.ConfigurationProperties;
- @ConfigurationProperties(prefix = "hello")
- public class HelloServiceProperties {
- private static final String MSG = "world";
- private String msg = MSG;
- public static String getMSG() {
- return MSG;
- }
- public String getMsg() {
- return msg;
- }
- public void setMsg(String msg) {
- this.msg = msg;
- }
- }
在application.yml中通过hello.msg来设置,若不设置,默认为hello.msg=world
3,判断依据类,代码如下:
- package com.jack.springboot.starter.hello;
- public class HelloService {
- private String msg;
- public String getMsg() {
- return msg;
- }
- public void setMsg(String msg) {
- this.msg = msg;
- }
- public String sayHello(){
- return "Hello "+msg;
- }
- }
下面根据此类的存在与否来创建这个类的Bean,这个类可以是第三方的类库
4,自动配置类,代码如下:
- package com.jack.springboot.starter.hello;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
- import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
- import org.springframework.boot.context.properties.EnableConfigurationProperties;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- @Configuration
- @EnableConfigurationProperties(HelloServiceProperties.class)
- @ConditionalOnClass(HelloService.class)
- @ConditionalOnProperty(prefix = "hello",value = "enabled",matchIfMissing = true)
- public class HelloServiceAutoConfiguration {
- @Autowired
- private HelloServiceProperties helloServiceProperties;
- @Bean
- @ConditionalOnMissingBean(HelloService.class)
- public HelloService helloService(){
- HelloService helloService = new HelloService();
- helloService.setMsg(helloServiceProperties.getMsg());
- return helloService;
- }
- }
根据HelloServiceProperties提供的参数,并通过@ConditionalOnClass判断HelloService这个类在此类路径中是否存在,且当容器总没有这个Bean的情况下自动配置这个Bean
5,注册配置
若想自动配置生效,需要注册自动配置类,在src/main/resources下新建META-INF/spring.factories,结构如下:
在spring.factories中填写如下内容注册:
- org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.jack.springboot.starter.hello.HelloServiceAutoConfiguration
若有多个自动配置,则用“,”隔开,此处是为了换行后仍然能读到属性。
6,测试
在其他项目添加starter作为依赖,修改pom.xml添加依赖,代码如下:
- <dependency>
- <groupId>com.jack</groupId>
- <artifactId>com.jack.springboot-starter-hello</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
我们可以在Maven的依赖中查看依赖:
在开发阶段,我们引入的依赖是springboot-starter-hello这个项目,在starter稳定之后,我们可以将springboot-starter-hello通过mvn install安装到本地库,或将这个jar包发到Maven私服上。
测试代码如下;
- package com.jack.controller;
- import com.jack.springboot.starter.hello.HelloService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RestController;
- @RestController
- public class SpringBootStarterController {
- @Autowired
- private HelloService helloService;
- @RequestMapping(value = "/start")
- public String start(){
- return helloService.sayHello();
- }
- }
在代码中可以直接注入到HelloService的Bean,但是在项目中我们并没有配置这个Bean,这是通过自动注入配置完成的,在浏览器输入http://localhost:9090/start,效果如下所示:
这时在application.yml配置配置msg的内容:
- server:
- port: 9090
- hello:
- msg: jack
重启,进行测试,效果如下:
如果在application.yml中开启debug=true,则可以查看到自动配置报告。