早期的Spring项目需要添加需要配置繁琐的xml,比如MVC、事务、数据库连接等繁琐的配置。Spring Boot的出现就无需这些繁琐的配置,因为Spring Boot基于约定大于配置 的理念,在项目启动时候,将约定的配置类自动配置到IOC容器里。这些都因为Spring Boot有自动配置的特性。
main方法 Spring Boot
都需要创建一个main
启动类,而启动类都含有@SpringBootApplication
注解,使用Spring Boot
零配置就可以运行起来,这就是 Spring Boot
自动装配的能力了。
看看Spring Boot
入口——main
方法:
1 2 3 4 5 6 @SpringBootApplication public class Application { public static void main (String[] args) throws Exception { SpringApplication.run(Application.class, args); } }
核心注解 @SpringBootApplication 注解 Spring Boot
启动类上都有一个 @SpringBootApplication
注解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @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 {
我们需要关注的有以下几个:
@ComponentScan
组件扫描指令
@SpringBootConfiguration
@EnableAutoConfiguration
从源码声明可以看出,@SpringBootApplication
相当于@SpringBootConfiguration
+ @EnableAutoConfiguration
+ @ComponentScan
,因此我们直接拆开来分析。
@SpringBootConfiguration @SpringBootConfiguration
是继承自Spring
的@Configuration
注解,@SpringBootConfiguration
作用相当于@Configuration
。
1 2 3 4 5 6 7 8 9 10 11 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration @Indexed public @interface SpringBootConfiguration { @AliasFor( annotation = Configuration.class ) boolean proxyBeanMethods () default true ; }
Spring 3.0中增加了@Configuration
,@Bean
。可基JavaConfig
形式对Spring
容器中的bean
进行更直观的配置。SpringBoot
推荐使用基于JavaConfig
的配置形式。
基于xml
配置:
1 2 3 4 5 6 7 8 9 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns ="http://www.springframework.org/schema/beans" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-lazy-init ="true" > <bean id ="myService" class ="..myServiceImpl" > ... </bean > </beans >
基于JavaConfig
配置:
1 2 3 4 5 6 public class MyConfiguration { @Bean public MyService mockService () { return new MyServiceImpl(); } }
总结,@Configuration
相当于一个spring
的xml
文件,配合@Bean
注解,可以在里面配置需要Spring
容器管理的bean
。
@ComponentScan 源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { @AliasFor("basePackages") String[] value() default {}; @AliasFor("value") String[] basePackages() default {}; Class<?>[] basePackageClasses() default {}; Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class; ScopedProxyMode scopedProxy () default ScopedProxyMode.DEFAULT ; String resourcePattern () default "**/ *.class" ; boolean useDefaultFilters () default true ; Filter[] includeFilters() default {}; Filter[] excludeFilters() default {}; boolean lazyInit () default false ; @Retention(RetentionPolicy.RUNTIME) @Target({}) public @interface Filter { FilterType type () default FilterType.ANNOTATION ; @AliasFor("classes") Class<?>[] value() default {}; @AliasFor("value") Class<?>[] classes() default {}; String[] pattern() default {}; } }
相关属性解释:
basePackages
与value
: 指定扫描的包或包数组
basePackageClasses
: 指定具体的要扫描的类
nameGenerator
: 对应的bean名称的生成器 默认的是BeanNameGenerator
useDefaultFilters
: 是否对带有@Component
@Repository
@Service
@Controller
注解的类开启检测,默认是开启的
includeFilters
: 通过includeFilters
加入扫描路径下没有以上注解的类加入spring容器
excludeFilters
: 通过excludeFilters
过滤出不用加入spring容器的类
lazyInit
: 扫描到的类是都开启懒加载 ,默认是不开启的
@ComponentScan
通常与@Configuration
一起配合使用,用来告诉Spring需要扫描哪些包或类。如果不设值的话默认扫描@ComponentScan
注解所在类所在的包及其所有子包,所以对于一个Spring Boot项目,一般会把入口类放在顶层目录中,这样就能够保证源码目录下的所有类都能够被扫描到。
@EnableAutoConfiguration @EnableAutoConfiguration
是SpringBoot
自动配置的核心注解
源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration" ; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
其中@Import({AutoConfigurationImportSelector.class})
就是自动配置的核心入口。
@Import({AutoConfigurationImportSelector.class})
可以自定义导入规则,主要就是AutoConfigurationImportSelector
类的selectImports
方法来选择需要自动配置的类进行配置。
1 2 3 4 5 6 7 8 public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!this .isEnabled(annotationMetadata)) { return NO_IMPORTS; } else { AutoConfigurationEntry autoConfigurationEntry = this .getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } }
selectImports
方法中主要是getAutoConfigurationEntry
这个方法,而getAutoConfigurationEntry
方法中最主要是getCandidateConfigurations
这个方法。
1 2 3 4 5 6 protected List<String> getCandidateConfigurations (AnnotationMetadata metadata, AnnotationAttributes attributes) { List<String> configurations = new ArrayList(SpringFactoriesLoader.loadFactoryNames(this .getSpringFactoriesLoaderFactoryClass(), this .getBeanClassLoader())); ImportCandidates.load(AutoConfiguration.class, this .getBeanClassLoader()).forEach(configurations::add); Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories nor in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you are using a custom packaging, make sure that file is correct." ); return configurations; }
1 2 3 4 5 6 7 8 9 public static List<String> loadFactoryNames (Class<?> factoryType, @Nullable ClassLoader classLoader) { ClassLoader classLoaderToUse = classLoader; if (classLoader == null ) { classLoaderToUse = SpringFactoriesLoader.class.getClassLoader(); } String factoryTypeName = factoryType.getName(); return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList()); }
1 2 3 4 5 6 7 8 9 10 11 private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) { Map<String, List<String>> result = (Map)cache.get(classLoader); if (result != null ) { return result; } else { Map<String, List<String>> result = new HashMap(); try { Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories" ); ...... }
SpringFactoriesLoader.loadFactoryNames()
方法主要作用是读取spring-boot-autoconfigure.jar
包下的META-INF/spring.factories
中配置可以进行自动配置的类,这些类都是以JavaConfig
形式进行导入的,在满足了@Conditional
中定义的加载条件后,Spring会将这些类加载到IOC
容器中。
spring.factories
内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 # Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener # 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.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.jpa.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ .... 省略了很多
Spring.factories
定义了哪些类可以被自动配置,每个配置类定了在什么条件下可以被自动配置,并将这些类实例化被Spring容器管理。
这里以AopAutoConfiguration
为例子,当类路径下存在EnableAspectJAutoProxy.class
,Aspect.class
,Advice.class
等类时才会注入AopAutoConfiguration
,并且默认是创建CglibAutoProxyConfiguration
配置。
总的来说:
从上面查看的源码,可以知道Spring Boot
自动配置主要是@EnableAutoConfiguration
实现的,@EnableAutoConfiguration
注解导入AutoConfigurationImportSelector
类,通过selectImports
方法调用SpringFactoriesLoader.loadFactoryNames()
扫描所有含有META-INF/spring.factories
文件的jar
包,将所有jar
包里面的spring.factories
文件中@EnableAutoConfiguration
对应的类注入到IOC
容器中。
Spring Boot
基于约定大于配置 的理念,配置如果没有额外的配置的话,就给按照默认的配置使用约定的默认值,按照约定配置到IOC
容器中,无需开发人员手动添加配置,加快开发效率。