前段时间在面试的过程中遇到面试官的一个问题,怎么自己定义一个spring boot的starter
,当时其实自己是有点懵的,说实话以前真的没有注意过这个问题,不过好在自己看过一些具体的starter
依赖,然后大概回答了一下。然后趁着周末决定来看一下到底是怎么一回事。
在spring boot项目中我们经常会使用到各种starter
,比如spring-boot-starter-web
、spring-boot-starter-data-jpa
等等,其实如果你深入的跟踪过这些pom.xml
的话你会发现,其实这些所谓的starter
不过是一个依赖的集合而已,可以理解为对所需要的依赖进行了一层包装。这样的好处就是相对更加灵活一些,每一个starter
可以看作是一个组件,这个组件包了相关的依赖,以spring-boot-starter-web
为例,我们看下它的组成到底是怎么样的:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.1.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.9.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.9.RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
根据上面的依赖可以知道,其实它也不过是引用了一些其他相关的依赖而已,它只是将这些依赖集中起来而已。比如有spring-webmvc
、有spring-boot-starter-tomcat
(你可以接着向下看它的组成)。这样它就做成了一个组件,不管是引用还是移除我们只需要关心它就行了。
一、自定义一个starter
根据上面的这些如果我们想自定义一个starter我们应该怎么做呢?在工作中我也在项目中使用过我们公司自己定义的一些starter
,比如ES、redis等等。接下来尝试自己定义一个很简单的starter
1、创建一个maven项目
使用IDE创建一个maven工程,然后定义好相关的 groupId
、 artifactId
和version
,然后在pom文件引入相关的依赖,主要是spring boot自动配置相关的依赖,pom.xm
文件依赖如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.1.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.1.8.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
然后我们需要定义一个配置类ServiceConfigProperties
,其实如果不会的话参考一下其他的starter
,代码如下:
@ConfigurationProperties(prefix = "com.ypc.service")
public class ServiceConfigProperties {
private String name = "starter";
private String url = "localhost";
private String username;
private String password;
private Integer count = 1;
// 省略get set
......
}
然后我们需要定义一个自动配置类ServiceAutoConfiguration
,这个自动配置的作用就是对外提供一个或多个相关的bean,以便可以直接注入到spring容器中。比如RedisAutoConfiguration
会创建RedisTemplate
、StringRedisTemplate
两个bean。所以我们也需要创建一个具体的服务类(这个根据具体的starter
决定)StarterService
,这个类本身在这里并不具备很具体的功能,仅仅是作为一个例子,代码如下:
public class StarterService {
private String serviceName;
private String url;
private String password;
private Integer count;
public StarterService() {
}
public StarterService(String serviceName, String url, String password, Integer count) {
this.serviceName = serviceName;
this.url = url;
this.password = password;
this.count = count;
}
// 省略get set方法
.......
}
最后就是自动配置类的代码,这个配置我们需要spring boot能自动进行配置,代码如下:
@Configuration
@EnableConfigurationProperties(ServiceConfigProperties.class)
public class ServiceAutoConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAutoConfiguration.class);
@Autowired
private ServiceConfigProperties serviceConfigProperties;
@Bean("starterService")
public StarterService starterService() {
LOGGER.info(">>>> starter service start <<<<");
StarterService starterService = new StarterService();
starterService.setCount(serviceConfigProperties.getCount());
starterService.setUrl(serviceConfigProperties.getUrl());
starterService.setPassword(serviceConfigProperties.getPassword());
starterService.setServiceName(serviceConfigProperties.getName());
return starterService;
}
}
需要注意一点就是在该类上使用@EnableAutoConfiguration
注解并不能让spring去注入我们创建的bean。一开始我只是添加了@EnableAutoConfiguration
,但是在引入到项目中启动时报错,显示无法注入自定义的bean——StarterService
。后来网上找了下相关资料发现需要在resources
目录下创建名为META-INF
文件夹,并新建一个文件spring.factories
,然后添加下面的内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.ypc.springboot.starter.ServiceAutoConfiguration
详情可以参考Spring-boot @EnableAutoConfiguration源码分析。
2、在其他项目中使用starter
然后我们需要将项目打包,并安装到我们本地的maven仓库,执行下面的maven命令:
mvn clean install
或者直接使用maven插件进行也可以。
接下来我们需要新创建一个spring boot的项目,并在该项目中引入自定义的starter
,我的依赖如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入自定义的service starter -->
<dependency>
<groupId>com.ypc.springboot.custom</groupId>
<artifactId>service-starter</artifactId>
<version>1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
然后在application.properties
配置自定义starter
配置类的相关内容,如下:

编写一个简单的接口,并在相应代码中注入依赖使用的bean——
StarterService
,然后调用一个方法即可,代码如下:
@Slf4j
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private StarterService starterService;
@Override
public UserEntity queryByUserName(String userName) {
String result = starterService.hello();
log.info(">>>> starter service hello={} <<<<",result);
UserEntity userEntity = userRepository.findByUserName(userName);
return userEntity;
}
}
看下日志输出如下:

说明自定义的
starter
在项目中是可以正常使用的,当然这个例子有点过于简单了,也并没有什么实际的价值,只是提供了一种自定义starter
的思路。如果在实际开发中需要自定义starter
其实参考spring boot提供那些starter
就可以了。
网友评论