目标
自定义redis-starter。要求当导入redis坐标时,SpringBoot自动创建Jedis的Bean。
先参考Mybatis坐标
SpringBoot官方提供(如spring-boot-starter-test)的功能(test)在最后,而Mybatis提供的功能在前面。
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
继续查看坐标详情,包含很多依赖,主要看mybatis-spring-boot-autoconfigure
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
</dependency>
</dependencies>
spring-boot-starter-test主要是将依赖整合到一起,方便导入(见截图中没有代码)。
主要的还是mybatis-spring-boot-autoconfigure
代码中包含MybatisAutoConfiguration配置类,此类需要被Spring所识别,从而加载配置类中所定义的Bean
就需要在META-INF中配置spring.factories
文件中写的是EnableAutoConfiguration,同时提供了刚才说的MybatisAutoConfiguration
因此:
- 创建redis-spring-boot-autoconfigure模块(写对应配置类)
- 创建redis-spring-boot-starter模块,依赖redis-spring-boot-autoconfigure模块
- 在redis-spring-boot-autoconfigure模块中初始化Jedis的Bean。并定义META-INF/spring.factories文件
- 在测试模块中引入自定义的redis-starter依赖,测试获取Jedis的Bean,操作redis
创建redis-spring-boot-autoconfigure模块与redis-spring-boot-start模块,清理不需要的文件,删除掉两个模块的引入类和测试类
redis-spring-boot-autoconfigure模块
pom文件中引入jedis文件
<?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.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yy</groupId>
<artifactId>redis-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-spring-boot-autoconfigure</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 引入jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
</dependencies>
</project>
创建RedisAutoConfiguration配置类,用于指定Bean
package com.example.redis.config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
//启用定义的RedisProperties类启用,以达到被Spring所识别
public class RedisAutoConfiguration {
/**
*
* 提供Jedis的Bean
*/
//此处的形参是因为上面被放到了Spring中,所以能够以参数形式注入
@Bean
public Jedis jedis(RedisProperties redisProperties) {
// return new Jedis("192.168.0.105",6379);
return new Jedis(redisProperties.getHost(),redisProperties.getPort());
}
}
创建RedisProperties.java用于绑定配置文件中的属性
package com.example.redis.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
//用于将一个实体类与配置文件相绑定
//通过前缀,以以redis开头的配置都会和当前实体类的属性对应起来
@ConfigurationProperties(prefix = "redis")
public class RedisProperties {
private String host = "192.168.0.105";
//如果配置文件中没有配置就使用默认值
private int port=6379;
//如果配置文件中没有配置就使用默认值
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}
创建spring.factories,并将@SpringBootConfiguration下的EnableAutoConfiguration复制路径到spring.factories中,作为键
redis-spring-boot-start模块
pom文件引入configure,并去掉test和plugins
<?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.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yy</groupId>
<artifactId>redis-spring-boot-start</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redis-spring-boot-start</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 引入configure-->
<dependency>
<groupId>com.yy</groupId>
<artifactId>redis-spring-boot-autoconfigure</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
使用之前创建的springboot_enable模块测试
修改pom文件,添加redis-spring-boot-start坐标
<?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.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.yy</groupId>
<artifactId>springboot_enable</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_enable</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</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-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.yy</groupId>
<artifactId>springboot_enable_other</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<!-- 自己定义的redis的starter-->
<dependency>
<groupId>com.yy</groupId>
<artifactId>redis-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
修改引导类,并测试
package com.yy.springboot_enable;
import com.yy.config.EnableUser;
import com.yy.config.MyImportBeanDefinitionRegistrar;
import com.yy.config.MyImportSelector;
import com.yy.config.UserConfig;
import com.yy.domain.Role;
import com.yy.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import redis.clients.jedis.Jedis;
import java.util.Map;
@SpringBootApplication
//@ComponentScan("com.yy.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(UserConfig.class)
//@Import(MyImportSelector.class)
@Import(MyImportBeanDefinitionRegistrar.class)
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
//
//获取另一个模块中的Bean
Object user = context.getBean("user");
System.out.println(user);
// Object user = context.getBean("user");
// System.out.println(user);
// Role role = context.getBean(Role.class);
// System.out.println(role);
Jedis jedis = context.getBean(Jedis.class);
System.out.println(jedis);
jedis.set("name","zhangyy");
String name = jedis.get("name");
}
}
进一步验证RedisProperties类
在springboot_enable模块中application.properties文件中配置port
redis.port=6666
#此处的redis前缀和配置类的定义的前缀相匹配上才会进行绑定
启动测试时报错,说明配置文件生效
redis-spring-boot-autoconfigure模块
修改配置类RedisAutoConfiguration ,添加当Jedis坐标在的时候,才加载此配置类;如果用户自己也定义了Jedis,就不提供此bean,而使用用户自定义的
package com.example.redis.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
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.Conditional;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.Jedis;
@Configuration
@EnableConfigurationProperties(RedisProperties.class)
//启用定义的RedisProperties类启用,以达到被Spring所识别
@ConditionalOnClass(Jedis.class)
//当Jedis坐标在的时候,才加载此配置类
public class RedisAutoConfiguration {
/**
*
* 提供Jedis的Bean
*/
//此处的形参是因为上面被放到了Spring中,所以能够以参数形式注入
@Bean
@ConditionalOnMissingBean(name = "jedis")
//如果用户自己也定义了Jedis,就不提供此bean,而使用用户自定义的
public Jedis jedis(RedisProperties redisProperties) {
// return new Jedis("192.168.0.105",6379);
System.out.println("RedisAutoConfiguration........");
return new Jedis(redisProperties.getHost(),redisProperties.getPort());
}
}
springboot_enable模块,测试有自定义类后,引导类中的@ConditionalOnMissingBean是否不生效
package com.yy.springboot_enable;
import com.yy.config.EnableUser;
import com.yy.config.MyImportBeanDefinitionRegistrar;
import com.yy.config.MyImportSelector;
import com.yy.config.UserConfig;
import com.yy.domain.Role;
import com.yy.domain.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import redis.clients.jedis.Jedis;
import java.util.Map;
@SpringBootApplication
//@ComponentScan("com.yy.config")
//@Import(UserConfig.class)
//@EnableUser
//@Import(UserConfig.class)
//@Import(MyImportSelector.class)
@Import(MyImportBeanDefinitionRegistrar.class)
public class SpringbootEnableApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(SpringbootEnableApplication.class, args);
//
//获取另一个模块中的Bean
Object user = context.getBean("user");
System.out.println(user);
// Object user = context.getBean("user");
// System.out.println(user);
// Role role = context.getBean(Role.class);
// System.out.println(role);
Jedis jedis = context.getBean(Jedis.class);
System.out.println(jedis);
jedis.set("name","zhangyy");
String name = jedis.get("name");
System.out.println(name);
}
@Bean
public Jedis jedis(){
return new Jedis("192.168.0.105",6379);
}
}
执行后不会打印配置类的 System.out.println(“RedisAutoConfiguration…”);反之则会打印。