场景:在微服务项目中,或者在一些项目,例如在一个网站中的消息提示、聊天机器人等功能场景中,它相当于是一个公共的功能,在所有模块中都需要,这时候我们肯定不能把代码各复制一份给每个功能模块,这时候就要抽取一个公共模块,也就是自定义starter
效果:任何项目导入此starter
都具有打招呼功能,并且问候语中的人名需要可以在配置文件中修改
- 创建
自定义starter
项目,引入spring-boot-starter
基础依赖 - 编写模块功能,引入模块所有需要的依赖。
- 编写
xxxAutoConfiguration
自动配置类,帮其他项目导入这个模块需要的所有组件 - 编写配置文件
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
指定启动需要加载的自动配置 - 其他项目引入即可使用
以上是大概的流程,现在有三种方式来进行自定义starter,由麻烦到简单的方法。
1.业务代码
首先创建一个properties的类来连接与properties配置文件进行bean连接
@Data
@Component
@ConfigurationProperties(prefix = "robot")
public class RobotProperties {
private String name;
private int age;
private String email;
}
自定义配置没有提示。导入以下依赖重启项目,再写配置文件就有提示
<!-- 导入配置处理器,配置文件自定义的properties配置都会有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
robot.name=代浩楠
robot.age=24
robot.email=913219642@qq.com
创建一个service
@Service
public class RobotService {
@Autowired
RobotProperties robotProperties;
public String sayHello(){
return "你好:名字:["+robotProperties.getName()+"],年龄:["+robotProperties.getAge()+"]";
}
}
再创建一个controller进行调用
@RestController
@RequestMapping("robot")
public class RobotController {
@Autowired
private RobotService robotService;
@GetMapping("hello")
public String hello(){
return robotService.sayHello();
}
}
2.基本抽取
- 创建starter项目,把公共代码需要的所有依赖导入
- 把公共代码复制进来
- 自己写一个
RobotAutoConfiguration
,给容器中导入这个场景需要的所有组件 - 别人引用这个
starter
,直接导入这个RobotAutoConfiguration
,就能把这个场景的组件导入进来 - 功能生效。
- 测试编写配置文件
这个遇到的一个问题是我们导入了新模块的pom依赖了,为什么这些组件默认不会扫描进去呢?
因为starter所在的包和引入它的项目的主程序所在的包不是父子层级,比如我的原始项目的层级在**com/dhnsoft/boot/core/Boot307CoreApplication.java**
,抽取的新starter的层级在**com/dhnsoft/boot3/starter/RobotAutoConfiguration.java**
,这两个层级不在一个里面的话就扫描不到组件,需要使用**@import**
来扫描进来。
1.首先我创建了一个新的项目模块,里面包含了之前创建的那些代码
2.在其他功能模块中引用新项目模块的pom依赖
<dependency>
<groupId>com.dhnsoft</groupId>
<artifactId>boot3-08-robot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
3.在新项目模块的根目录创建一个xxxAutoConfiguration.java
类
这个类中的配置有两种方式:
1.可以使用@Import
来把需要公共输出的功能模块给加载到组件中
2.也可以使用@Bean
来将功能代码给加载到组件中
@Import({RobotService.class, RobotProperties.class})
//@Import({RobotController.class, RobotService.class, RobotProperties.class})
@Configuration
public class RobotAutoConfiguration {
@Bean
public RobotController robotController(){
return new RobotController();
}
}
4.最后在之前的功能模块中的启动类上直接使用@Import
注解来引用新模块的公共功能@Import(RobotAutoConfiguration.class)
3.使用@EnableXxx机制
以上使用@import
还是有点麻烦,我们可以自定义注解来进行抽取
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(RobotAutoConfiguration.class)
public @interface EnableRobot {
}
然后直接在其他功能模块的启动类上标上@EnableRobot
注解
4.完全自动配置
- 依赖SpringBoot的SPI机制
- META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中编写好我们自动配置类的全类名即可
- 项目启动,自动加载我们的自动配置类
自己在resources下自己创建META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
在里面填入新模块功能的哪个配置类就行了,这样就也不用注解了,直接把pom依赖引入到其他功能模块就可以了