Spring Boot秉承「約定大於配置」的開發方式,使得咱們基於Spring Boot開發項目的效率變得十分高。相信使用過Spring Boot的小夥伴都會發現,當咱們要用到某個Spring提供的組件時,只須要在
pom.xml
文件中添加該組件的starter依賴就能集成到項目中。html例如,在
pom.xml
文件中添加spring-boot-starter-web
依賴,就能讓項目整合Spring MVC的功能。而且在最簡使用下幾乎不須要進行任何的配置,而以往想要集成Spring MVC,不只要添加一堆相似於spring-web
、spring-webmvc
等相關依賴包,以及完成許多繁雜的配置纔可以實現集成。java這是由於starter裏已經幫咱們整合了各類依賴包,避免了依賴包缺失或依賴包之間出現版本衝突等問題。以及完成了許多基礎配置和自動裝配,讓咱們能夠在最簡使用下,跳過絕大部分的配置,從而達到開箱即用的效果。這也是Spring Boot實現「約定大於配置」的核心之一。web
經過以上的描述,咱們能夠簡單地將starter看做是對一個組件功能粒度較大的模塊化封裝,包括了所需依賴包的整合及基礎配置和自動裝配等。redis
這裏說下
artifactId
的命名問題,Spring 官方 Starter一般命名爲spring-boot-starter-{name}
如spring-boot-starter-web
, Spring官方建議非官方Starter命名應遵循{name}-spring-boot-starter
的格式。spring
除了Spring官方提供的starter外,咱們本身也能夠根據業務開發一個starter。例如,當項目積累到必定程度時,咱們能夠將一些通用功能下沉爲一個starter。而開發一個starter也很簡單,只須要如下步驟:apache
@ConfigurationProperties
指明配置項前綴;@Configuration
和@Bean
來進行自動裝配;spring.factories
文件,用於指定自動裝配類的路徑;接下來,以封裝一個用於操做redis的starter爲例,一步步展現這些步驟的具體實現過程。首先是第一步,新建一個maven項目,完整的pom.xml內容以下:bash
<?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.2.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>redis-spring-boot-starter</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-boot-starter-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</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </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> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <!-- jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.1.0</version> </dependency> <!-- gson --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency> </dependencies> </project>
第二步,新建一個屬性配置類,寫好配置項和默認值。並使用@ConfigurationProperties
指明配置項前綴,用於加載配置文件對應的前綴配置項:mvc
package com.example.starter.demo.properties; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; /** * 屬性配置類,用於加載配置文件對應的前綴配置項 **/ @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操做工具,代碼以下:app
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 操做組件 **/ @Slf4j @RequiredArgsConstructor public class RedisComponent { private final JedisPool jedisPool; /** * get value with key */ public <T> T get(String key, Class<T> clazz) { try (Jedis resource = jedisPool.getResource()) { String str = resource.get(key); return stringToBean(str, clazz); } } /** * set value with key */ public <T> 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> T stringToBean(String str, Class<T> clazz) { Gson gson = new Gson(); return gson.fromJson(str, clazz); } private <T> String beanToString(T value) { Gson gson = new Gson(); return gson.toJson(value); } }
第三步,新建自動裝配類,使用@Configuration
和@Bean
來實現對JedisPool
和RedisComponent
的自動裝配;maven
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; /** * 自動裝配類 **/ @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
文件裏指定自動裝配類的路徑:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.starter.demo.configuration.RedisConfiguration
若須要指定多個自動裝配類的路徑,則使用逗號分隔。以下示例:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.starter.demo.configuration.DemoConfiguration,\ com.example.starter.demo.configuration.RedisConfiguration
Tips:spring.factories
支持配置的key以下:
org.springframework.context.ApplicationContextInitializer org.springframework.context.ApplicationListener org.springframework.boot.autoconfigure.AutoConfigurationImportListener org.springframework.boot.autoconfigure.AutoConfigurationImportFilter org.springframework.boot.autoconfigure.EnableAutoConfiguration org.springframework.boot.diagnostics.FailureAnalyzer org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider org.springframework.boot.env.EnvironmentPostProcessor org.springframework.boot.SpringApplicationRunListener org.springframework.boot.SpringBootExceptionReporter org.springframework.beans.BeanInfoFactory org.springframework.boot.env.PropertySourceLoader org.springframework.data.web.config.SpringDataJacksonModules org.springframework.data.repository.core.support.RepositoryFactorySupport
最後install這個maven項目,命令以下:
mvn clean install
若是使用的開發工具是IDEA的話就比較簡單,只須要雙擊一下install便可:
在任意一個Spring Boot項目的pom.xml
文件中添加以下依賴:
<dependency> <groupId>com.example</groupId> <artifactId>redis-spring-boot-starter</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency>
在項目的application.yml
中添加以下配置項來覆蓋默認配置,若默認配置已符合需求則能夠省略這一步:
demo: redis: host: 172.168.1.198 port: 6379 timeout: 3000 password: max-total: 10 max-wait-millis: 10000 max-idle: 10
編寫一個單元測試類進行測試,代碼以下:
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 = "success!!!!!"; 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); } }