# Spring Boot Starter Demo **Repository Path**: demo_focus/Spring-Boot-Starter-Demo ## Basic Information - **Project Name**: Spring Boot Starter Demo - **Description**: Spring Boot Starter Demo - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 1 - **Created**: 2019-11-04 - **Last Updated**: 2024-08-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ### 关于Starter > Spring Boot秉承“约定大于配置”的开发方式,使得我们基于Spring Boot开发项目的效率变得十分高。相信使用过Spring Boot的小伙伴都会发现,当我们要用到某个Spring提供的组件时,只需要在`pom.xml`文件中添加该组件的starter依赖就能集成到项目中。 > > 例如,在`pom.xml`文件中添加`spring-boot-starter-web`依赖,就能让项目整合Spring MVC的功能。并且在最简使用下几乎不需要进行任何的配置,而以往想要集成Spring MVC,不仅要添加一堆类似于`spring-web`、`spring-webmvc`等相关依赖包,以及完成许多繁杂的配置才能够实现集成。 > > 这是因为starter里已经帮我们整合了各种依赖包,避免了依赖包缺失或依赖包之间出现版本冲突等问题。以及完成了许多基础配置和自动装配,让我们可以在最简使用下,跳过绝大部分的配置,从而达到开箱即用的效果。这也是Spring Boot实现“约定大于配置”的核心之一。 ---------- ### 动手开发一个Starter 通过以上的描述,我们可以简单地将starter看作是对一个组件功能粒度较大的模块化封装,包括了所需依赖包的整合及基础配置和自动装配等。 除了Spring官方提供的starter外,我们自己也可以根据业务开发一个starter。例如,当项目积累到一定程度时,我们可以将一些通用功能下沉为一个starter。而开发一个starter也很简单,只需要以下步骤: 1. 新建一个Maven项目,在pom.xml文件中定义好所需依赖; 2. 新建配置类,写好配置项和默认值,使用`@ConfigurationProperties`指明配置项前缀; 3. 新建自动装配类,使用`@Configuration`和`@Bean`来进行自动装配; 4. 新建`spring.factories`文件,用于指定自动装配类的路径; 5. 将starter安装到maven仓库,让其他项目能够引用; 接下来,以封装一个用于操作redis的starter为例,一步步展示这些步骤的具体实现过程。首先是**第一步**,新建一个maven项目,完整的pom.xml内容如下: ```xml 4.0.0 org.springframework.boot spring-boot-starter-parent 2.2.0.RELEASE com.example spring-boot-starter-demo 0.0.1-SNAPSHOT spring-boot-starter-demo Demo project for Spring Boot 1.8 org.springframework.boot spring-boot-starter org.springframework.boot spring-boot-configuration-processor true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine redis.clients jedis 3.1.0 com.google.code.gson gson 2.8.6 ``` **第二步**,新建一个属性配置类,写好配置项和默认值。并使用`@ConfigurationProperties`指明配置项前缀,用于加载配置文件对应的前缀配置项: ```java package com.example.starter.demo.properties; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; /** * 属性配置类,用于加载配置文件对应的前缀配置项 * * @author zero * @date 2019-11-04 **/ @Data @ConfigurationProperties("demo.redis") public class RedisProperties { private String host = "127.0.0.1"; private int port = 6379; private int timeout = 2000; private int maxIdle = 5; private int maxTotal = 10; private long maxWaitMillis = 10000; private String password; } ``` 编写一个简单的redis操作工具,代码如下: ```java package com.example.starter.demo.component; import com.google.gson.Gson; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; /** * redis 操作组件 * * @author zero * @date 2019-11-04 **/ @Slf4j @RequiredArgsConstructor public class RedisComponent { private final JedisPool jedisPool; /** * get value with key */ public T get(String key, Class clazz) { try (Jedis resource = jedisPool.getResource()) { String str = resource.get(key); return stringToBean(str, clazz); } } /** * set value with key */ public boolean set(String key, T value, int expireSeconds) { try (Jedis resource = jedisPool.getResource()) { String valueStr = beanToString(value); if (valueStr == null || valueStr.length() == 0) { return false; } if (expireSeconds <= 0) { resource.set(key, valueStr); } else { resource.setex(key, expireSeconds, valueStr); } return true; } } private T stringToBean(String str, Class clazz) { Gson gson = new Gson(); return gson.fromJson(str, clazz); } private String beanToString(T value) { Gson gson = new Gson(); return gson.toJson(value); } } ``` **第三步**,新建自动装配类,使用`@Configuration`和`@Bean`来实现对`JedisPool`和`RedisComponent`的自动装配; ```java package com.example.starter.demo.configuration; import com.example.starter.demo.component.RedisComponent; import com.example.starter.demo.properties.RedisProperties; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; 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; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * 自动装配类 * * @author zero * @date 2019-11-04 **/ @Slf4j @Configuration @RequiredArgsConstructor @EnableConfigurationProperties(RedisProperties.class) public class RedisConfiguration { private final RedisProperties properties; @Bean // 表示当Spring容器中没有JedisPool类的对象时,才调用该方法 @ConditionalOnMissingBean(JedisPool.class) public JedisPool jedisPool() { log.info("redis connect string: {}:{}", properties.getHost(), properties.getPort()); JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(properties.getMaxIdle()); jedisPoolConfig.setMaxTotal(properties.getMaxTotal()); jedisPoolConfig.setMaxWaitMillis(properties.getMaxWaitMillis()); String password = properties.getPassword(); if (password == null || password.length() == 0) { return new JedisPool(jedisPoolConfig, properties.getHost(), properties.getPort(), properties.getTimeout()); } return new JedisPool(jedisPoolConfig, properties.getHost(), properties.getPort(), properties.getTimeout(), properties.getPassword()); } @Bean @ConditionalOnMissingBean(RedisComponent.class) public RedisComponent redisComponent(JedisPool jedisPool){ return new RedisComponent(jedisPool); } } ``` **第四步**,在项目的`resources`目录下新建一个`META-INF`目录,并在该目录下新建`spring.factories`文件。如下图所示: ![spring.factories](https://images.gitee.com/uploads/images/2019/1104/175743_55bddaec_1765987.png "屏幕截图.png") 在`spring.factories`文件里指定自动装配类的路径: ```bash org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.starter.demo.configuration.RedisConfiguration ``` 若需要指定多个自动装配类的路径,则使用逗号分隔。如下示例: ```bash org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.starter.demo.configuration.DemoConfiguration,\ com.example.starter.demo.configuration.RedisConfiguration ``` 最后install这个maven项目,命令如下: ``` mvn clean install ``` 如果使用的开发工具是IDEA的话就比较简单,只需要双击一下install即可: ![maven install](https://images.gitee.com/uploads/images/2019/1104/175723_206139b6_1765987.png "屏幕截图.png") ---------- ### 使用Starter 在任意一个Spring Boot项目的`pom.xml`文件中添加如下依赖: ```xml com.example spring-boot-starter-demo 0.0.1-SNAPSHOT ``` 在项目的`application.yml`中添加如下配置项来覆盖默认配置,若默认配置已符合需求则可以省略这一步: ```yml demo: redis: host: 192.168.11.130 port: 6379 timeout: 3000 password: A8^MZ59qOr*gkhv51tSdifvb max-total: 10 max-wait-millis: 10000 max-idle: 10 ``` 编写一个单元测试类进行测试,代码如下: ```java package com.example.firstproject.starter; import com.example.starter.demo.component.RedisComponent; import lombok.extern.slf4j.Slf4j; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @Slf4j @SpringBootTest @RunWith(SpringRunner.class) public class StarterTests { @Autowired private RedisComponent redisComponent; @Test public void redisTest() { String key = "redisTest"; String value = "this is a test value"; boolean success = redisComponent.set(key, value, 3600); log.info("set value to redis {}!", success ? "success" : "failed"); String result = redisComponent.get(key, String.class); log.info("get value from redis: [{}]", result); } } ``` 运行结果如下: ![输出结果](https://images.gitee.com/uploads/images/2019/1104/175652_a709daf0_1765987.png "屏幕截图.png")