关注“Java后端技术全栈”**
回复“面试”获取全套大厂面试材料
在文章中常常会看到一个-starter-,比方:
spring-boot-starter-quartzspring-boot-starter-webspring-boot-starter-jdbcspring-boot-starter-data-jpa...
很多人可能会感觉这种starter形式很牛B,增加一个starter就搞定了很多事件。明天咱们也来搞一个本人的starter。
starter的原理
先来说说starter的原理,咱们晓得应用一个专用的starter的时候,只须要将相应的依赖增加的Maven的配置文件当中即可,免去了本人须要援用很多依赖类,并且SpringBoot会主动进行类的主动配置。那么 SpringBoot 是如何晓得要实例化哪些类,并进行主动配置的呢?上面简略说一下。
第一步,SpringBoot 在启动时会去依赖的starter包中寻找
resources/META-INF/spring.factories
文件,而后依据文件中配置的Jar包去扫描我的项目所依赖的Jar包,这相似于 Java 的 SPI 机制(前面会专门写一篇对于java 的SPI机制)。
第二步,依据 spring.factories
配置加载AutoConfigure
类。
最初,依据 @Conditional
注解的条件,进行主动配置并将Bean注入Spring Context 上下文当中。
咱们也能够应用@ImportAutoConfiguration({MyAutoConfiguration.class})
指定主动配置哪些类。
starter的机制
SpringBoot中的starter是一种十分重要的机制,可能摈弃以前繁冗的配置,将其对立集成进starter,利用者只须要在maven中引入starter依赖,SpringBoot就能主动扫描到要加载的信息并启动相应的默认配置。starter让咱们解脱了各种依赖库的解决,须要配置各种信息的困扰。SpringBoot会主动通过classpath门路下的类发现须要的Bean,并注册进IOC容器。SpringBoot提供了针对日常企业应用研发各种场景的spring-boot-starter依赖模块。所有这些依赖模块都遵循着约定成俗的默认配置,并容许咱们调整这些配置,也就是大家所说的“约定大于配置”。
starter的益处
在咱们的日常开发工作中,常常会有一些独立于业务之外的配置模块,咱们常常将其放到一个特定的包下,而后如果另一个工程须要复用这块性能的时候,须要将代码硬拷贝到另一个工程,从新集成一遍,麻烦至极。如果咱们将这些可独立于业务代码之外的功配置模块封装成一个个starter,复用的时候只须要将其在pom中援用依赖即可,SpringBoot为咱们实现主动拆卸,几乎不要太爽。
实战自定义starter
创立一个项目名称为demo-spring-boot-starter
别离创立好对应目录。上面来说说几个类的内容。
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"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> </parent> <groupId>com.demo</groupId> <artifactId>demo-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> </dependencies></project>
DemoProperties读取配置文件内容,前缀为demo
import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "demo")public class DemoProperties { private String sayWhat; private String toWho; public String getSayWhat() { return sayWhat; } public void setSayWhat(String sayWhat) { this.sayWhat = sayWhat; } public String getToWho() { return toWho; } public void setToWho(String toWho) { this.toWho = toWho; }}
创立一个service类DemoService
public class DemoService { public String sayWhat; public String toWho; public DemoService(String sayWhat, String toWho) { this.sayWhat = sayWhat; this.toWho = toWho; } public String say() { return this.sayWhat + " " + toWho; }}
接下来的这个类是最要害的类
import com.demo.properties.DemoProperties;import com.demo.service.DemoService;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;import javax.annotation.Resource;@Configuration@ConditionalOnClass(DemoService.class)@EnableConfigurationProperties(DemoProperties.class)public class DemoConfig { @Resource private DemoProperties demoProperties; @Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix = "demo", value = "enabled", havingValue = "true") public DemoService demoService() { return new DemoService(demoProperties.getSayWhat(), demoProperties.getToWho()); }}
解释一下代码中用到的几个注解:
@ConditionalOnClass
,当classpath
下发现该类的状况下进行主动配置。@ConditionalOnMissingBean
,当Spring Context
中不存在该Bean
时。@ConditionalOnProperty(prefix = "example.service",value = "enabled",havingValue = "true")
,当配置文件中example.service.enabled=true
时。
上面列举SpringBoot中的所有@Conditional注解及作用
@ConditionalOnBean:当容器中有指定的Bean的条件下 @ConditionalOnClass:当类门路下有指定的类的条件下 @ConditionalOnExpression:基于SpEL表达式作为判断条件 @ConditionalOnJava:基于JVM版本作为判断条件 @ConditionalOnJndi:在JNDI存在的条件下查找指定的地位 @ConditionalOnMissingBean:当容器中没有指定Bean的状况下 @ConditionalOnMissingClass:当类门路下没有指定的类的条件下 @ConditionalOnNotWebApplication:以后我的项目不是Web我的项目的条件下 @ConditionalOnProperty:指定的属性是否有指定的值 @ConditionalOnResource:类门路下是否有指定的资源 @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的状况下,用来指定首选的Bean @ConditionalOnWebApplication:以后我的项目是Web我的项目的条件下
最初一步,在resources/META-INF/
下创立spring.factories
文件,并增加如下内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.demo.config.DemoConfig
至此,咱们的一个Starter代码局部就是实现了,上面将我的项目mvn install装置到本地Maven仓库中。
测试自定义starter
在后面文章中的我的项目中增加咱们自定义的starter依赖
<dependency> <groupId>com.demo</groupId> <artifactId>demo-spring-boot-starter</artifactId> <version>1.0-SNAPSHOT</version></dependency>
在application.properties中增加配置项
demo.isopen=truedemo.say-what=hellodemo.to-who=mystarter
定义一个DemoStarterController
import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestControllerpublic class DemoStarterController { @Resource private DemoService demoService; @GetMapping("/test/starter") public String sayWhat(){ return demoService.say(); }}
启动我的项目。
申请:http:localhost:8080/test/starter
输入:hello mystarter
starter 的命名标准
a. spring 提供的 starter:
spring-boot-starter-XXX-x.y.z.jar
spring-boot-XXX-autoconfigure-x.y.z.jar
b. 第三方提供的 jar
XXX-spring-boot-starter-x.y.z.jar
XXX-spring-boot-autoconfigure-x.y.z.jar
ok,自定义starter就这么轻松的搞定了。码字不易,点个 在看 +分享 再走呗。感激!!!
举荐浏览
应用 ThreadLocal 一次解决老大难问题
一个月薪 12000 的北京程序员的实在生存
一波骚操作,我把 SQL 执行效率进步了 10,000,000 倍!