关于java:原创Spring-Boot-如何手写stater

54次阅读

共计 6110 个字符,预计需要花费 16 分钟才能阅读完成。

关注Java 后端技术全栈”**

回复“面试”获取全套大厂面试材料

在文章中常常会看到一个-starter-,比方:

spring-boot-starter-quartz
spring-boot-starter-web
spring-boot-starter-jdbc
spring-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=true
demo.say-what=hello
demo.to-who=mystarter

定义一个 DemoStarterController

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public 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 倍!

正文完
 0