(目录)
1、自定义Starter
1.1、项目结构
$ tree
.
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ ├── ReadingConfiguration.java
│ │ ├── config
│ │ │ └── ReadingConfig.java
│ │ └── service
│ │ ├── ReadingService.java
│ │ └── impl
│ │ └── ReadingServiceImpl.java
│ └── resources
│ ├── META-INF
│ │ └── spring.factories
│ └── application.properties
└── test
├── java
│ └── com
│ └── example
│ └── demo
│ └── ReadingServiceTests.java
└── resources
└── application.yml
1.2、代码实现
pom.xml maven依赖
<?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 https://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.7.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>thinking-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- 自动配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<!-- 不会编译测试 -->
<skipTests>true</skipTests>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.properties 默认值
# 注意:该文件名只能是application.properties
# 实践发现:该文件不能出现,否则业务工程的application.yml文件无法覆盖默认值
# 设置默认的值
reading.type=txt
ReadingConfig.java 配置映射
package com.example.demo.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 读取application.properties中reading相关的配置
*/
@Data
@ConfigurationProperties(prefix = "reading")
public class ReadingConfig {
// 类型
private String type;
}
ReadingService.java 接口
package com.example.demo.service;
public interface ReadingService {
void reading();
}
ReadingServiceImpl.java 接口实现类
package com.example.demo.service.impl;
import com.example.demo.config.ReadingConfig;
import com.example.demo.service.ReadingService;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class ReadingServiceImpl implements ReadingService {
/**
* reading相关配置类
*/
private ReadingConfig readingConfig;
public ReadingServiceImpl(ReadingConfig readingConfig) {
this.readingConfig = readingConfig;
}
@Override
public void reading() {
log.info("reading type: {}", this.readingConfig.getType());
}
}
ReadingConfiguration.java 自动装配的核心
package com.example.demo;
import com.example.demo.config.ReadingConfig;
import com.example.demo.service.ReadingService;
import com.example.demo.service.impl.ReadingServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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;
@Configuration
@EnableConfigurationProperties(ReadingConfig.class)
// 当存在reading.enable属性,且其值为true时,才初始化该Bean
@ConditionalOnProperty(name = "reading.enable", havingValue = "true")
public class ReadingConfiguration {
@Autowired
private ReadingConfig readingConfig;
// 若当前IOC容器中没有Reading接口实现时,提供一个默认的Reading实现
@Bean
@ConditionalOnMissingBean(ReadingService.class)
public ReadingService readingService() {
return new ReadingServiceImpl(this.readingConfig);
}
}
spring.factories 自动装配注册
# 提醒SpringBoot在启动时,自动装配ReadingConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.demo.ReadingConfiguration
1.3、测试
ReadingServiceTests.java
package com.example.demo;
import com.example.demo.service.ReadingService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest(classes = ReadingConfiguration.class)
class ReadingServiceTests {
@Autowired
private ReadingService readingService;
@Test
void testReadingService() {
readingService.reading();
}
}
application.yml
reading:
enable: true
1.4、打包
将项目安装到本地maven仓库
mvn install
2、引用Starter
新建一个业务工程
2.1、项目结构
$ tree
.
├── pom.xml
└── src
└── main
├── java
│ └── com
│ └── example
│ └── demo
│ ├── Application.java
│ └── controller
│ └── IndexController.java
└── resources
└── application.yml
2.2、引入starter
<!-- 引入自定义starter -->
<dependency>
<groupId>com.example</groupId>
<artifactId>thinking-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
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 https://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.7.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 引入自定义starter -->
<dependency>
<groupId>com.example</groupId>
<artifactId>thinking-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
reading:
type: json
enable: true
IndexController.java
package com.example.demo.controller;
import com.example.demo.service.ReadingService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@Autowired(required = false)
private ReadingService readingService;
@GetMapping("/")
public String index(){
if(this.readingService != null){
this.readingService.reading();
}
return "Hello";
}
}
Application.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3、重写默认配置
修改项目配置文件application.yml
reading:
enable: true
type: json # 重写starter默认配置
4、重写默认实现
默认提供的实现
public class ReadingConfiguration {
@Bean
@ConditionalOnMissingBean(ReadingService.class)
public ReadingService readingService() {
return new ReadingServiceImpl(this.readingConfig);
}
}
若当前IOC容器中没有Reading接口实现时,提供一个默认的Reading实现
@ConditionalOnMissingBean(ReadingService.class)
可以自行实现ReadingService
package com.example.web.service;
import com.example.demo.config.ReadingConfig;
import com.example.demo.service.ReadingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class MyReadingService implements ReadingService {
@Autowired
private ReadingConfig readingConfig;
@Override
public void reading() {
log.info("my reading service start reading... type is {}", this.readingConfig.getType());
}
}
5、实现@Enable
注解
类似的注解
@EnableScheduling
@EnableAsync
@EnableCaching
5.1、starter项目创建注解
创建注解
package com.example.demo.annotation;
import com.example.demo.ReadingSelector;
import org.springframework.context.annotation.Import;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// @Import作用是往SpringIOC中导入一个类,这里即导入ReadingSelector
@Import(ReadingSelector.class)
public @interface EnableReading {
}
创建 ReadingSelector类取代 ReadingConfiguration
package com.example.demo;
import com.example.demo.config.ReadingConfig;
import com.example.demo.service.ReadingService;
import com.example.demo.service.impl.ReadingServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(ReadingConfig.class)
public class ReadingSelector {
@Autowired
private ReadingConfig readingConfig;
// 当SpringIOC容器中不存在Reading实现时,才往Spring中初始化ReadingService作为Reading接口的实现
@Bean
@ConditionalOnMissingBean(ReadingService.class)
public ReadingService readingService() {
return new ReadingServiceImpl(this.readingConfig);
}
}
5.2、业务工程使用注解
修改配置文件 application.yml
reading:
# enable: true
type: json
启动类增加注解@EnableReading
package com.example.web;
import com.example.demo.annotation.EnableReading;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@EnableReading
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
6、元数据
元数据描述后,开发者便能通过IDE提示看到此配置属性的默认值/值类型等信息
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
重新打包,会自动生成spring-configuration-metadata.json
7、参考文章
项目代码:https://github.com/mouday/spring-boot-demo
标签:Java,自定义,boot,springframework,org,import,com,example,Starter From: https://blog.51cto.com/mouday/8001601