在开发过程中,我们需要根据不同的应用场景添加不同的模块,比如jdbc操作,我们除了添加基础的接口模块外,还需要根据不同的数据库添加针对该数据库的模块,在这样的场景下,就需要用到自动配置模块。
实现一个简单的自动配置模块的步骤:
1.构建一个配置类,用于读取配置文件
本例子直接读取application.properties,若有自定义的配置文件,可以单独进行配置
@ConfigurationProperties(prefix = "custom")
public class AuthorProperties {
private static final String DEFAULT_AUTHOR = "Hello World";
private String author = DEFAULT_AUTHOR;
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
2.构建一个服务类,用于提供服务
本例子服务类实现了读取配置文件中的信息
public class AuthorServer {
private String author;
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
3.构建自动配置类
springboot在启动的时候,会读取spring.factories文件,自动实例化该类并加入到spring容器中
@Configuration
/**
* springboot通过判断是否有AuthorServer这个类,来判断该Configuration是否有效
* 若有AuthorServer这个类,则Configuration有效
* 若无AuthorServer这个类,则Configuration无效
*/
@ConditionalOnClass({AuthorServer.class})
/**
* @EnableConfigurationProperties 注解的作用是使配置了@ConfigurationProperties 注解的类生效
* 1.一个配置类只配置了@ConfigurationProperties,而没有配置@Component,那么spring容器中无法获取配置类,即没有实例化
* 配置了@ConfigurationProperties的类
* 2.@EnableConfigurationProperties 相当于将只配置了@ConfigurationProperties的配置类进行了一次注入
*/
@EnableConfigurationProperties(AuthorProperties.class)
public class AuthorAutoConfiguration {
@Autowired
private AuthorProperties authorProperties;
@Bean(name = "authorServer")
/**
* springboot通过@ConditionalOnProperty来判断@Bean是否有效
* 通过name和havingValue来实现,其中name表示从application.properties中读取的key
* 1.若application.properties中不存在custom.author.enable,若matchIfMissing = true,则@Bean有效
* 2.若application.properties中custom.author.enable有值,将该值与havingValue进行比较
* ①若custom.author.enable的值与havingValue的值一样,则返回true,@Bean有效
* ①若custom.author.enable的值与havingValue的值不一样,则返回false,@Bean无效
*/
@ConditionalOnProperty(name = "custom.author.enable", havingValue = "true", matchIfMissing = true)
public AuthorServer authorServer() {
AuthorServer authorServer = new AuthorServer();
authorServer.setAuthor(authorProperties.getAuthor());
return authorServer;
}
@Bean(name = "authorServer")
/**
* 当spring容器中存在AuthorServer实例时,不进行下述方法的实例化
* 当spring容器中不存在AuthorServer实例时,进行下述方法的实例化
*/
@ConditionalOnMissingBean(AuthorServer.class)
public AuthorServer authorServerDefault() {
AuthorServer authorServer = new AuthorServer();
authorServer.setAuthor("default name");
return authorServer;
}
}
4.不要忘记spring.factories文件,springboot根据该文件的内容,决定哪些类需要实例化,并且加入到spring容器中
在resources目录下创建META-INF目录,然后创建spring.factories文件
spring.factories文件内容如下:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.navinfo.had.factories.AuthorAutoConfiguration
5.将该工程打成一个jar包,用于其他工程引用
<dependency> <groupId>com.navinfo.springcloud</groupId> <artifactId>spring-cloud-factories</artifactId> <version>0.0.1</version> </dependency>
6.测试:
application.properties如下:
custom.author=aaa
custom.author.enable=false
@RunWith(SpringRunner.class)
@SpringBootTest
public class FactoriesTest {
@SpringBootApplication(scanBasePackages = "com.test")
static class InnerConfig { }
@Autowired
private AuthorServer authorServer;
@Test
public void test() {
System.out.println(authorServer.getAuthor());
}
}
返回结果:
1.当custom.author.enable不存在时,打印aaa
2.当custom.author.enable=true,打印aaa
3.当custom.author.enable=false,打印default name
思维发散:
在开发工程中,我们会针对类似的场景,开发不同的模块,比如ORM框架,我们会开发oracle模块,mysql模块,postgres模块等等,当我们引入其中一个模块后,如何进行注册,当取消一个模块后,如何进行剔除