SpringBootApplication是什么

概述我们先来了解一下 @springbootapplication 是什么,以及如何在一个简单的 spring boot 应用程序中使用它。我们先看看 spring team 在源码中对它的定义是什么?
indicates a configuration class that declares one or more @bean methods and also triggers auto-configuration and component scanning. this is a convenience annotation that is equivalent to declaring @configuration, @enableautoconfiguration and @componentscan.
表示一个配置类,它声明了一个或多个@bean方法,也触发了自动配置和组件扫描。这是一个方便的注解,相当于声明了@configuration、@enableautoconfiguration和@componentscan。
从上面的定义我们可以看出,@springbootapplication 注解其实是一个组合注解。使用 @springbootapplication 相当于同时使用了 @configuration、@enableautoconfiguration 和 @componentscan 。@springbootapplication 是在 spring boot 1.2.0 之后才开始有的,如何你的项目使用的 spring boot 1.2.0 之前的版本,那需要抱歉了,你不能使用这个注解,你只能完整的使用那 3 个注解来代替它。
那我们接下来看看,通过一个简单的示例来看看怎么使用的。
@springbootapplication 示例下面是一个简单的例子,说明如何使用 @springbootapplication 注解来编写 spring boot 应用程序。
import org.springframework.boot.springapplication;import org.springframework.boot.autoconfigure.springbootapplication;@springbootapplicationpublic class application { public static void main(string[] args) { springapplication.run(application.class, args); }}spring boot 项目的启动类非常的简洁,没有一行多余的代码。@springbootapplication 放在项目启动类上主要起到了自动化配置的作用。下面我们看看 @springbootapplication 具体的代码。
@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 { @aliasfor(annotation = enableautoconfiguration.class) class[] exclude() default {}; @aliasfor(annotation = enableautoconfiguration.class) string[] excludename() default {}; @aliasfor(annotation = componentscan.class, attribute = basepackages) string[] scanbasepackages() default {}; @aliasfor(annotation = componentscan.class, attribute = basepackageclasses) class[] scanbasepackageclasses() default {}; @aliasfor(annotation = componentscan.class, attribute = namegenerator) class namegenerator() default beannamegenerator.class; @aliasfor(annotation = configuration.class) boolean proxybeanmethods() default true;}从 @springbootapplication 源码可以看出 @springbootapplication = @springbootconfiguration + @componentscan+ @enableautoconfiguration 。
前面已经提过了,@springbootapplication 是3个注解的组合,下面分别介绍一下每个注解都有什么作用吧。
@springbootconfiguration
这个注解将一个类标记为基于 java config 的配置类。如果你喜欢基于 java 的配置而不是基于 xml 的配置,这一点就特别重要。
@componentscan
该注解使组件扫描成为可能,这样你创建的 web 控制器类和其他组件将被自动发现,并在 spring 应用上下文中注册为 bean。你编写的所有 @controller 类将被该注解发现。
@enableautoconfiguration
这个注解可以启用 spring boot 自动配置功能。
如果你仔细的话会发现和前面讲的不一样, @springbootconfiguration 是从那里冒出来的,不是应该是 @configuration 吗?下面就告诉你答案。
@springbootconfiguration@target(elementtype.type)@retention(retentionpolicy.runtime)@documented@configuration@indexedpublic @interface springbootconfiguration { @aliasfor(annotation = configuration.class) boolean proxybeanmethods() default true;}从源码可以看出,@springbootconfiguration 继承自 @configuration,二者功能也一致,标注当前类是配置类,不过 @springbootconfiguration 是一个特殊的标记类,在项目中只能使用一次。
@componentscan@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 namegenerator() default beannamegenerator.class; class scoperesolver() default annotationscopemetadataresolver.class; scopedproxymode scopedproxy() default scopedproxymode.default; ...}@componentscan 不做过多的解释了,使用过 spring 的朋友都懂的。其他的朋友我就啰嗦一句吧, 可以通过该注解指定扫描某些包下包含如下注解的均自动注册为 spring beans:@component、@service、 @repository、 @controller 等等注释的类。spring boot 除了可以使用 @componentscan 注解来加载我们的bean,还可以使用 @import 指定该类。
@enableautoconfiguration@enableautoconfiguration 的作用启动自动的配置,意思就是 spring boot 根据你添加的 jar 包来配置你项目的默认配置,比如根据 spring-boot-starter-web ,来判断你的项目是否需要添加了 web mvc 和 tomcat,就会自动的帮你配置 web 项目中所需要的默认配置。简单点说就是它会根据定义在 classpath 下的类,自动的给你生成一些 bean,并加载到 spring 的上下文中。
@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 类。autoconfigurationimportselector 使用了 spring core 包的 springfactoriesloader#loadfactorynames() 方法。autoconfigurationimportselector 类实现了 deferredimportselector 接口,并实现了 selectimports 方法,用来导出 configuration 类。
public class autoconfigurationimportselector implements deferredimportselector, beanclassloaderaware, resourceloaderaware, beanfactoryaware, environmentaware, ordered { @override public string[] selectimports(annotationmetadata annotationmetadata) { if (!isenabled(annotationmetadata)) { return no_imports; } autoconfigurationentry autoconfigurationentry = getautoconfigurationentry(annotationmetadata); return stringutils.tostringarray(autoconfigurationentry.getconfigurations()); } protected autoconfigurationentry getautoconfigurationentry(annotationmetadata annotationmetadata) { if (!isenabled(annotationmetadata)) { return empty_entry; } annotationattributes attributes = getattributes(annotationmetadata); list configurations = getcandidateconfigurations(annotationmetadata, attributes); ... return new autoconfigurationentry(configurations, exclusions); } protected boolean isenabled(annotationmetadata metadata) { if (getclass() == autoconfigurationimportselector.class) { return getenvironment().getproperty(enableautoconfiguration.enabled_override_property, boolean.class, true); } return true; } protected list getcandidateconfigurations(annotationmetadata metadata, annotationattributes attributes) { list 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() 读取了 classpath 下面的 meta-inf/spring.factories 文件。
public final class springfactoriesloader { public static final string factories_resource_location = meta-inf/spring.factories; public static list loadfactorynames(class factorytype, @nullable classloader classloader) { classloader classloadertouse = classloader; if (classloadertouse == null) { classloadertouse = springfactoriesloader.class.getclassloader(); } string factorytypename = factorytype.getname(); return loadspringfactories(classloadertouse).getordefault(factorytypename, collections.emptylist()); } private static map< string, list> loadspringfactories(classloader classloader) { map< string, list> result = cache.get(classloader); if (result != null) { return result; } result = new hashmap(); try { enumeration urls = classloader.getresources(factories_resource_location); while (urls.hasmoreelements()) { url url = urls.nextelement(); urlresource resource = new urlresource(url); properties properties = propertiesloaderutils.loadproperties(resource); for (map.entry entry : properties.entryset()) { string factorytypename = ((string) entry.getkey()).trim(); string[] factoryimplementationnames = stringutils.commadelimitedlisttostringarray((string) entry.getvalue()); for (string factoryimplementationname : factoryimplementationnames) { result.computeifabsent(factorytypename, key - > new arraylist()) .add(factoryimplementationname.trim()); } } } // replace all lists with unmodifiable lists containing unique elements result.replaceall((factorytype, implementations) - > implementations.stream().distinct() .collect(collectors.collectingandthen(collectors.tolist(), collections::unmodifiablelist))); cache.put(classloader, result); } catch (ioexception ex) { throw new illegalargumentexception(unable to load factories from location [ + factories_resource_location + ], ex); } return result; }}meta-inf/spring.factories 文件中一部分自动配置的内容:
# 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.context.configurationpropertiesautoconfiguration,org.springframework.boot.autoconfigure.context.lifecycleautoconfiguration,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,如果你发现自动装配的 bean 不是你想要的,你也可以 disable 它。比如说,我不想要自动装配 database 的那些bean:
@enableautoconfiguration(exclude = {datasourceautoconfiguration.class})这也是一种为 spring boot 项目瘦身的方法。你可以看到网上一些为项目瘦身的方法都是通过这个注解来操作的。
@autoconfigurationpackage@enableautoconfiguration 又继承了 @autoconfigurationpackage ,@autoconfigurationpackage 会引导类(@springbootapplication 标注的类)所在的包及下面所有子包里面的所有组件扫描到spring容器。具体怎么实现的呢,我们来看代码,原来它 import 了 autoconfigurationpackages.registrar.class, 我们来看看它做了什么?
@import(autoconfigurationpackages.registrar.class)public @interface autoconfigurationpackage { string[] basepackages() default {}; class[] basepackageclasses() default {};}static class registrar implements importbeandefinitionregistrar, determinableimports { @override public void registerbeandefinitions(annotationmetadata metadata, beandefinitionregistry registry) { register(registry, new packageimports(metadata).getpackagenames().toarray(new string[0])); } @override public set determineimports(annotationmetadata metadata) { return collections.singleton(new packageimports(metadata)); }}看代码就很容易理解,把注解扫描进来的 package 全部给注册到 spring bean中。这样 spring boot 的自动配置也就完成了。
总结经过这样的一番折腾,相信大家已经对 @springbootapplication 注解,有了一定的了解。也知道了 @springbootapplication 怎么实现 spring boot 的自动配置功能。

汽车变速器工作原理是什么?
银河微电IPO成功过会!
精密焊接中频逆变直流点焊机的特点说明
荣耀Magic2评测 和前辈一样成为又一款经典产品
矽昌通信发布系列无线路由芯片 打造具有竞争力的解决方案
SpringBootApplication是什么
解决室内定位刚需痛点 掘金物联网“蓝海”
ACPL-C79B/C79A/C790 隔离放大器
用于牵引驱动电源模块的双面冷却架构
华为荣耀Magic手撕Mate9?为何会出现窝里斗局面
无线回程电源
高精度时间间隔测量芯片TDC-GP1的工作原理及设计应用
生物毒性测定仪可以检测什么
verilog运算符的优先级
区块链为对冲基金提供了一个巨大的机会
预测:2020年我国VR市场规模有望突破300亿元
“中国硬件创新大赛”上海站培训会战火再燃
盘点集成电路产业投资额超百亿元的项目
顺着5G的藤,摸出物联网的“瓜”
一文了解陶瓷基板的现状及未来