封面画师:adsuger 封面ID:77171064
SpringBoot原理
参考链接:Spring Boot参考指南
1. Hello World
使用IDEA创建SpringBoot项目:
选择spring initalizr ,可以看到默认就是去官网的快速构建工具实现的;
填写项目信息;
选择初始化组件(初学选择Web即可);
填写项目路径,等待项目构建完成。
项目结构分析:
程序的主启动类xxxxxxxApplication.java
一个 application.properties 配置文件
一个 测试类
一个 pom.xml
编写一个http接口
在主程序的同级目录下,新建一个controller包。注意:一定要在同级目录下,否则会识别不到
在创建的controller包下新建一个HelloController类:
1 2 3 4 5 6 7 @ RestController
public class HelloController {
@ RequestMapping ( "/hello" )
public String hello () {
return "Hello World" ;
}
}
编写完毕后,从主程序启动项目,浏览器发起请求,看页面返回;控制台输出了 Tomcat 访问的端口号!
彩蛋:自定义banner图案
到项目下的 resources 目录下新建一个banner.txt 文件。
将图案拷贝到文件中即可。
2. 运行原理初探
2.1 启动器
1 2 3 4 < dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-web</ artifactId >
</ dependency >
spring-boot-starter-xxx :就是Springboot的场景启动器
spring-boot-starter-web :帮助我们导入web模块正常运行所依赖的组件
作用:Springboot将所有的场景抽取出来,做成了一个个启动器(starter),只需要在项目中引入启动器即可,所有的依赖都会导入进来。我们只需要选择我们自己需要的启动器,同时我们还可以自定义启动器。
2.2 主启动类
1 2 3 4 5 6 7 8 9 @ SpringBootApplication //使用SpringBootApplication来标注这是一个主程序类
//说明这是一个Springboot应用
public class Springboot01HelloworldApplication {
public static void main ( String [] args ) {
//run方法不仅启动了一个方法,还启动了一个服务
SpringApplication . run ( Springboot01HelloworldApplication . class , args);
}
}
2.3 注解分析
2.3.1 @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 {
//......
}
2.3.2 @ComponentScan
Spring内主要注解,它对应XML配置中的<context:component-scan base-package="xxx" />元素。
作用: 自动扫描并加载符合条件的组件或者bean , 将这个bean定义加载到IOC容器中
2.3.3 @SpringBootConfiguration
1 2 3 4 5 6 @ Configuration
public @ interface SpringBootConfiguration { ... }
//点击进入Configuration
@ Component
public @ interface Configuration { ... }
分析:
@Configuration表明这是配置类,配置类就是对应Spring的xml配置文件。
@Component说明启动类本身也是Spring中的一个组件而已,负责启动应用。
回到@SpringBootApplication注解中,查看@EnableAutoConfiguration注解
2.3.4 @EnableAutoConfiguration
作用: 开启自动配置功能。以前的一些框架的配置需要我们手动配置,现在SpringBoot可以自动帮我们配置。而@SpringBootApplication可以开启SpringBoot的自动配置功能,这样自动配置才可以生效 。
点击进入@EnableAutoConfiguration注解:
1 2 3 @ AutoConfigurationPackage
@ Import ( AutoConfigurationImportSelector . class )
public @ interface EnableAutoConfiguration { ... }
@AutoConfigurationPackage:自动配置包
点击进入@AutoConfigurationPackage注解:
1 2 3 @ Import ( AutoConfigurationPackages . Registrar . class )
public @ interface AutoConfigurationPackage {
}
@import :Spring底层注解@import , 给容器中导入一个组件。
Registrar.class作用:将主启动类的所在包及包下面所有子包里面的所有组件扫描到Spring容器 。
@Import(AutoConfigurationImportSelector.class):给容器导入组件
AutoConfigurationImportSelector:自动配置导入选择器。那么它会导入哪些组件的选择器呢?
点击进入AutoConfigurationImportSelector类:
这个类中有这样的一个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 //获得候选的配置
protected List < String > getCandidateConfigurations ( AnnotationMetadata metadata ,
AnnotationAttributes attributes) {
/**getSpringFactoriesLoaderFactoryClass()方法
* 返回的是启动自动导入配置文件的注解类:EnableAutoConfiguration
*/
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 ;
}
//getSpringFactoriesLoaderFactoryClass()方法
protected Class < ? > getSpringFactoriesLoaderFactoryClass () {
return EnableAutoConfiguration . class ;
}
这个方法又调用了SpringFactoriesLoader 类的静态方法,进入SpringFactoriesLoader类中 loadFactoryNames() 方法:
1 2 3 4 5 6 7 public static List < String > loadFactoryNames ( Class < ? > factoryType ,
@ Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType . getName ();
//此处调用了loadSpringFactories()方法
return loadSpringFactories (classLoader) . getOrDefault (
factoryTypeName, Collections . emptyList ());
}
点击loadSpringFactories() 方法进行查看:
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 private static Map < String , List < String >> loadSpringFactories (
@ Nullable ClassLoader classLoader) {
//获得classLoader,这里得到的就是EnableAutoConfiguration标注的类本身
MultiValueMap < String , String > result = cache . get (classLoader);
if (result != null ) {
return result ;
}
try {
//public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
//获取一个资源 "META-INF/spring.factories"
Enumeration < URL > urls = (classLoader != null ?
classLoader . getResources (FACTORIES_RESOURCE_LOCATION) :
ClassLoader . getSystemResources (FACTORIES_RESOURCE_LOCATION) ) ;
result = new LinkedMultiValueMap <> () ;
//将读到的资源遍历,封装成一个properties
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 ();
for ( String factoryImplementationName : StringUtils . commaDelimitedListToStringArray ((String) entry . getValue ()) ) {
result . add (factoryTypeName, factoryImplementationName . trim ());
}
}
}
cache . put (classLoader, result);
return result ;
}
catch ( IOException ex ) {
throw new IllegalArgumentException ( "Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]" , ex) ;
}
}
在这个类中我们发现了多次出现的文件:spring.factories,进行全局搜索:
打开这个文件我们可以看到很多自动配置的文件,而这就是自动配置根源的所在:
在这些配置文件中我们选取一个我们熟悉的配置类打开,比如:WebMvcAutoConfiguration
我们可以看到这些都是一个个的JavaConfig配置类,同时注入了一些Bean。
所以,自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IoC容器配置类 , 然后将这些都汇总成为一个实例并加载到IoC容器中。
自动装配的核心: 可以用JavaConfig类取代xml配置,并可以用yaml文件对JavaConfig(标记@ConfigProperties)类的属性进行修改。
思考: 这么多的自动配置为什么有些没有生效而需要导入对应的starter才有作用?
我们没有导入AOP的相关依赖,所以我们找到AOP的自动配置并打开:
打开后我们会发现有这样一个注解:
我们可以看到,@ConditionalOnClass注解爆红!这是为什么?
答案很简单,因为我们没有导入AOP相关的依赖,我们需要导入依赖(对应的starter)后这个注解才不会爆红,而只有这个注解不爆红,SpringBoot的AOP自动配置才会生效。
@ConditionalOnxxxx:只有里面的条件都满足,自动配置才会生效。
结论:
SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入容器 , 自动配置类就会生效 , 帮我们进行自动配置的工作。
整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中,它将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中。
它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入了某一场景需要的所有组件 , 并配置好这些组件 。我们有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;
理一下注解:
到此,我们就大概的了解了SpringBoot的运行原理!
2.4 SpringApplication.run
该方法主要有两部分,一部分是SpringApplication的实例化,二是run方法的执行。
SpringApplication类主要做了一下四件事:
推断应用的类型是普通的项目还是Web项目
查找并加载所有可用初始化器 , 设置到initializers属性中
找出所有的应用程序监听器,设置到listeners属性中
推断并设置main方法的定义类,找到运行的主类
构造器:
1 2 3 4 5 6 7 public SpringApplication ( ResourceLoader resourceLoader , Class ... primarySources ) {
// ......
this . webApplicationType = WebApplicationType . deduceFromClasspath ();
this . setInitializers ( this . getSpringFactoriesInstances ();
this . setListeners ( this . getSpringFactoriesInstances ( ApplicationListener . class ));
this . mainApplicationClass = this . deduceMainApplicationClass ();
}
3. yaml配置注入
3.1 基本语法
说明:语法要严格要求!
空格不能省略。
以缩进控制层级关系。
属性和值的大小写都是十分敏感的。
引号的使用:
“ ” 双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;
比如:name: “mo \n fan” 输出:mo 换行 fan
‘’ 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出。
比如:name: ‘mo \n fan’ 输出:mo \n fan
3.2 其他语法
行内写法:
1 person : { name : mofan , age : 18 }
注意缩进和空格
1 2 3 4 person :
- student
- teacher
- doctor
行内写法:
1 person : [ student , teacher , doctor ]
3.3 配置文件注入
当我们需要给实体类注入匹配值时,根据Spring的学习,我们可以:使用@Component将bean注册到容器中,然后使用@Value注解给bean的每个属性注入值。现在我们还可以用yaml配置的方式进行注入:
首先编写一个实体类,Person类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /*
@ConfigurationProperties作用:
将配置文件中配置的每一个属性的值,映射到这个组件中;
告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
*/
@ Component //注册bean
@ ConfigurationProperties ( prefix = "person" )
public class Person {
private String name ;
private Integer age ;
private Boolean happy ;
private Date birth ;
private Map < String , Object > maps ;
private List < Object > lists ;
private Dog dog ;
//有参无参构造、get、set方法、toString()方法
}
编写一个yaml配置:
1 2 3 4 5 6 7 8 9 10 11 12 person :
name : mofan
age : 18
happy : true
birth : 2000/01/01
maps : { k1 : v1 , k2 : v2 }
lists :
- game
- music
dog :
name : 小黑
age : 3
然后我们在SpringBoot的测试类中编写测试即可。
1 2 3 4 5 6 @ Autowired
private Person person ;
void contextLoads (){
System . out . println (person);
}
如果IDEA提示:SpringBoot配置注解处理器没有找到,那么需要我们添加一个依赖。
1 2 3 4 5 6 <!--导入依赖后需要重启-->
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-configuration-processor</ artifactId >
< optional >true</ optional >
</ dependency >
注意:
如果配置文件的key值和属性值设置不一样,则输出结果会为null,表示注入失败。
注意注解@ConfigurationProperties的使用。@configurationProperties :默认从全局配置文件中获取值。
如果存在多个配置文件(比如还存在一个 person.properties 文件),这时我们进行注入并想要绑定这个配置文件时,可以使用 @PropertySource 注解来加载指定的配置文件。
1 2 3 4 5 6 7 @ PropertySource ( value = "classpath:person.properties" )
@ Component
public class Person {
@ Value ( "${name}" )
private String name ;
......
}
1 2 3 4 5 6 7 person :
name : mofan${random.uuid} # 随机uuid
age : ${random.int} # 随机int
...
dog :
name : ${person.hello:other}_小黑
age : 3
如果我们需要使用properties配置,在配置文件中书写中文时,IDEA会出现乱码,需要我们进行设置。settings–>FileEncodings -->设置编码格式为UTF-8(把旁边的勾打上)。
3.4 yaml总结
@ConfigurationProperties和@Value对比:
@ConfigurationProperties
@Value
功能
批量注入配置文件中的属性
一个一个地指定属性值
松散绑定
支持
不支持
SpEL
不支持
支持
JSR303校验
支持
不支持
复杂类型封装
支持
不支持
松散绑定:比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。
JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性。
yaml可以封装对象,而value不行。
总结:
如果配置yaml和配置properties都可以获取到值 , 推荐 使用yaml;
如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value;
如果我们专门编写了一个JavaBean来和配置文件进行一一映射,直接使用@ConfigurationProperties。
4. JSR303数据校验
使用:在SpringBoot中使用@Validated注解来校验数据,如果数据处在异常,则会抛出异常,方便统一处理。比如,我们可以写一个注解使我们的name属性不能为空:
1 2 3 4 5 6 7 8 @ Component //注册bean
@ ConfigurationProperties ( prefix = "person" )
@ Validated //数据校验
public class Person {
@ NotNull ( message = "名字不能为空" )
private String name ;
}
如果这时name为空,则会抛出异常,并显示设置的default message。
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 @ NotNull ( message = "名字不能为空" )
private String userName ;
@ Max ( value = 120 , message = "年龄最大不能查过120" )
private int age ;
@ Email ( message = "邮箱格式错误" )
private String email ;
空检查
@ Null 验证对象是否为null
@ NotNull 验证对象是否不为null , 无法查检长度为0的字符串
@ NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0 , 只对字符串 , 且会去掉前后空格 .
@ NotEmpty 检查约束元素是否为NULL或者是EMPTY .
Booelan检查
@ AssertTrue 验证 Boolean 对象是否为 true
@ AssertFalse 验证 Boolean 对象是否为 false
长度检查
@ Size ( min = , max = ) 验证对象(Array , Collection , Map , String)长度是否在给定的范围之内
@ Length ( min = , max = ) string is between min and max included .
日期检查
@ Past 验证 Date 和 Calendar 对象是否在当前时间之前
@ Future 验证 Date 和 Calendar 对象是否在当前时间之后
@ Pattern 验证 String 对象是否符合正则表达式的规则
等等 ...
我们也可以自定义一些校验规则
5. 多环境切换
5.1 多配置文件
我们在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml , 用来指定多个环境版本。
例如:
application-test.properties :测试环境配置
application-dev.properties :开发环境配置
但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件 ,我们需要通过一个配置来选择需要激活的环境:
1 2 3 #比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active = dev
5.2 yaml多文档块
同样可以使用yaml配置文件实现多环境切换,但是使用yaml可以不需要创建多个配置文件,比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 server :
port : 8081
#选择要激活那个环境块
spring :
profiles :
active : prod
---
server :
port : 8083
spring :
profiles : dev #配置环境的名称
---
server :
port : 8084
spring :
profiles : prod #配置环境的名称
注意:
使用yaml的多文档块时,需要指明环境名称,文档快之间用“—”隔开。
如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的!
5.3 配置文件加载顺序
SpringBoot启动会扫描一下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:
1 2 3 4 优先级1:file:./config/ 项目路径下的config文件夹配置文件
优先级2:file:./ 项目路径下配置文件
优先级3:classpath:/config/ 资源路径下的config文件夹配置文件
优先级4:classpath:/ 资源路径下配置文件
优先级由高到低,高优先级的配置会覆盖低优先级的配置。SpringBoot会从这四个位置全部加载主配置文件,互补配置。
6. 自动装配原理
思考: 经过编写yaml配置文件的学习,我们认识到可以使用yaml配置文件设置相关配置,但是配置文件到底该怎么写?又能写些什么?
6.1 原理分析
我们在 2. 运行原理初探 中已经找到了文件spring.factories所处的位置,
这时我们可以选取 HttpEncodingAutoConfiguration(Http编码自动配置) 为例解释自动配置原理:
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 //表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件
@ Configuration
//启动指定类的ConfigurationProperties功能
//进入这个HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来
//并把HttpProperties加入到ioc容器中
@ EnableConfigurationProperties ({ HttpProperties . class })
//Spring底层@Conditional注解
//根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效
//这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
@ ConditionalOnWebApplication (
type = Type . SERVLET
)
//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器
@ ConditionalOnClass ({ CharacterEncodingFilter . class })
//判断配置文件中是否存在某个配置:spring.http.encoding.enabled
//如果不存在,判断也是成立的
//即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的
@ ConditionalOnProperty (
prefix = "spring.http.encoding" ,
value = { "enabled" } ,
matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
//他已经和SpringBoot的配置文件映射了
private final Encoding properties ;
//只有一个有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration ( HttpProperties properties ) {
this . properties = properties . getEncoding ();
}
//给容器中添加一个组件,这个组件的某些值需要从properties中获取
@ Bean
@ ConditionalOnMissingBean //判断容器没有这个组件?
public CharacterEncodingFilter characterEncodingFilter () {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter ();
filter . setEncoding ( this . properties . getCharset (). name ());
filter . setForceRequestEncoding ( this . properties . shouldForce ( org . springframework . boot . autoconfigure . http . HttpProperties . Encoding . Type . REQUEST ));
filter . setForceResponseEncoding ( this . properties . shouldForce ( org . springframework . boot . autoconfigure . http . HttpProperties . Encoding . Type . RESPONSE ));
return filter;
}
//......
}
简单总结:SpringBoot根据当前不同的条件判断,决定这个配置文件是否生效。
一但这个配置类生效,这个配置类就会给容器中添加各种组件;
这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;
配置文件能配置什么就可以参照某个功能对应的这个属性类。
点击进入HttpProperties.class :
1 2 3 4 5 //从配置文件中获取指定的值和bean的属性进行绑定
@ ConfigurationProperties ( prefix = "spring.http" )
public class HttpProperties {
//....
}
然后我们可以在配置文件中进行httpencoding的相关配置,并进行对比:
到此,我们就明白了自动装配的核心!
6.2 原理总结
SpringBoot启动会加载大量的自动配置类
我们判断我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;
我们再来看这个自动配置类中到底配置了哪些组件(只要我们要用的组件存在在其中,我们就不需要再手动配置了);
给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们只需要在配置文件中指定这些属性的值即可。
6.3 @Conditional
SpringBoot的自动装配类必须在一定的条件下才能生效,SpringBoot用到了 @Conditional派生注解 。
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效。
@Conditional拓展注解
作用(判断是否满足当前指定条件)
@ConditionalOnJava
系统的Java版本是否符合要求
@ConditionalOnBean
容器中存在指定的Bean
@ConditionalOnMissingBean
容器中不存在指定的Bean
@ConditionalOnExpression
满足SpEL表达式的指定
@ConditionalOnClass
系统中有指定的类
@ConditionalOnMissingClass
系统中没有指定的类
@ConditionalOnSingleCandidate
容器中只有一个指定的Bean,或者这个Bean是首选Bean
@ConditionalOnProperty
系统中指定的属性是否有指定的值
@ConditionalOnResource
类路径下是否存在指定的资源文件
@ConditionalOnWebApplication
当前是Web环境
@ConditionalOnNotWebApplication
当前不是Web环境
@ConditionalOnJndi
JNDI存在指定项
如此多的自动配置类必须在满足了指定条件下才会生效,那么我们怎么知道哪些自动配置生效了呢?
我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
1 2 #开启springboot的调试类
debug = true
控制台会输出三大项:
Positive matches:(自动配置类启用的:正匹配)
Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
Unconditional classes: (没有条件的类)
7. 自定义Starter
我们先明白Starter的一些基础知识:
明白命名规约有助于帮助我们命名自定义启动器。
7.1 编写启动器
在IDEA中新建一个空项目spring-boot-starter-diy;
完成第一步后,新建一个普通Maven模块:yang-spring-boot-starter:
新建一个Springboot模块:yang-spring-boot-starter-autoconfigure
新建好两个Module后,基本结构为:
在我们的 starter 中 导入 autoconfigure 的依赖:
1 2 3 4 5 6 7 8 9 <!-- 启动器 -->
< dependencies >
<!-- 引入自动配置模块 -->
< dependency >
< groupId >com.yang</ groupId >
< artifactId >yang-spring-boot-starter-autoconfigure</ artifactId >
< version >0.0.1-SNAPSHOT</ version >
</ dependency >
</ dependencies >
将 autoconfigure 项目下多余的文件都删掉,Pom中只留下一个 starter,这是所有的启动器基本配置:
注意:记得将test目录也删除,否则会安装到maven仓库时会失败!!!
编写我们自己的服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /**
* @author Mofan_Yang
*/
public class HelloService {
HelloProperties helloProperties ;
public HelloProperties getHelloProperties () {
return helloProperties;
}
public void setHelloProperties ( HelloProperties helloProperties ) {
this . helloProperties = helloProperties;
}
public String sayHello ( String name ){
return helloProperties . getPrefix () + name + helloProperties . getSuffix ();
}
}
编写HelloProperties 配置类:
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 /**
* @author Mofan_Yang
*/
// 设置前缀 yang.hello
@ ConfigurationProperties ( prefix = "yang.hello" )
public class HelloProperties {
private String prefix ;
private String suffix ;
public String getPrefix () {
return prefix;
}
public void setPrefix ( String prefix ) {
this . prefix = prefix;
}
public String getSuffix () {
return suffix;
}
public void setSuffix ( String suffix ) {
this . suffix = suffix;
}
}
编写自动配置类并注入bean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /**
* @author Mofan_Yang
*/
@ Configuration
@ ConditionalOnWebApplication //web应用生效
@ EnableConfigurationProperties ( HelloProperties . class )
public class HelloServiceAutoConfiguration {
@ Autowired
HelloProperties helloProperties ;
@ Bean
public HelloService helloService (){
HelloService service = new HelloService ();
service . setHelloProperties (helloProperties);
return service;
}
}
在resources编写一个自己的 META-INF\spring.factories
1 2 3 # Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration = \
com.yang.HelloServiceAutoConfiguration
编写完成后,安装到Maven仓库:
注意: 代码只在 yang-spring-boot-starter-autoconfigure 中编写,启动器 Starter 中没有任何代码。
7.2 测试Starter
新建一个SpringBoot项目;
导入我们自定义的启动器:
1 2 3 4 5 < dependency >
< groupId >com.yang</ groupId >
< artifactId >yang-spring-boot-starter</ artifactId >
< version >1.0-SNAPSHOT</ version >
</ dependency >
编写一个HelloController控制器,测试自定义的启动器:
1 2 3 4 5 6 7 8 9 10 11 @ RestController
@ RequestMapping ( "/test" )
public class HelloController {
@ Autowired
HelloService helloService ;
@ RequestMapping ( "/hello" )
public String hello (){
return helloService . sayHello ( "我是内容 " );
}
}
编写配置文件 application.yml
1 2 3 4 yang :
hello :
prefix : "我是前缀 "
suffix : "我是后缀 "
启动项目测试,查看结果:
自定义启动器编写成功!!