SpringBoot-@EnableAutoConfiguration项目应用
这个注解在我们做项目中,为了让对象得到统一化的管理的时候,用这个注解的特性是非常的ok的。这个注解可以在springBoot项目run之前进行初始化一系列的配置,比如当我们引入starter-web的时候:会把下面的一个autoconfig的自动配置的包引入进来。在spring中用的一些框架在这里统统都有,比如:amqp(rabbitMQ),Gson等等的对象。
只要我们在run的时候只要在类上面标上这个注解的时候,统统的会把这些配置装配到spriing容器中去。
每一个配置通常都会有三个部分组成:属性的配置文件:
还有一个函数式的接口
最后一个是配置项,在配置项里面有一个注解@ConditionalOnClass(Gson.class):按照条件去装配的注解,当这个Gson.class文件在classpath下存在的话才会把这个配置类的对象装载到spring容器中去,在装配的过程中会把一个Gson的对象装配进来。
@ConditionalOnMissingBean:
在装配Gson对象的时候先去判断容器中是否有Gson类型的对象,如果有的话就不装配,如果没有就去装配。
思考一个问题:在装配的过程中,上面的配置是怎么装配进去的呢?它怎么知道装配的就是这个呢?
在META-INF的文件夹下:有一个spring.factories这个文件内有自动装配类的全路径:这就是配置了进去,这也就是我们什么都不用配置就可以用redisTemplate等等。
而在@EnableAutoConfiguratiion这个注解里面:
package org.springframework.boot.autoconfigure;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
在AutoConfigurationImportSelector这个类里面有一个方法的实现:
selectImports这个方法里做的事是把META-INF里面配置的自动装配类的全路径
统统的装配进来从而返回一个数组出来。
上边的源代码解析:
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader):带有注解的类就把它加载进来。
AnnotationAttributes attributes =this.getAttributes(annotationMetadata):加载进来后得到所有的属性。Listconfigurations = this.getCandidateConfigurations(annotationMetadata, attributes):
然后通过这个方法getCandidateConfigurations去到META-INF下的spring.factories文件下去获取自动装配的类到这个List集合中去。
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
然后把这个集合中重复的东西给排除掉。
configurations =this.removeDuplicates(configurations); Setexclusions = this.getExclusions(annotationMetadata, attributes);
最后返回的数组中的实例对象统统的交给Spring容器管理。
基于上面的特征:完成自己的对象装载:通过@Enable的特征加载第三方的配置类到主类的项目中去。
1、首先创建一个bean-core:对象的配置中心
1.1、创建两个实体类:
1.2、创建一个BeanConfig类:代表第三方的bean的配置类
package org.example.config;
import org.example.domain.Order;
import org.example.domain.Product;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class BeanConfig {
@Bean
public Order CreateOrder(){
return new Order();
}
@Bean
public Product CreateProduct(){
return new Product();
}
}
2、数据源的配置中心:
2.1、创建一个数据源的类:
package org.example;
/**
* 数据源的属性类
*/
public class DataSourceProperties {
private String username;
private String password;
private String url;
private String driverClassName;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDriverClassName() {
return driverClassName;
}
public void setDriverClassName(String driverClassName) {
this.driverClassName = driverClassName;
}
}
2.2、数据源的配置类:
package org.example;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "jdbc")
public DataSourceProperties dataSourceProperties(){
return new DataSourceProperties();
}
- }
3:如何在springBoot的项目中去使用这两个配置的核心类呢,在run的时候就把这两个模块给引入过来呢?
3.1、先把两个模块的依赖加入到boot-auto的里面:
<dependency>
<groupId>org.example</groupId>
<artifactId>untitled</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>config-core</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
3.2、根据@EnableAutoConfiguration的特性,可以自己在两个模块中去创建分别去创建META-INF/spring.factories文件:
这两个配置文件spring.factories会合并成一个然后做排除重复的。然后交给Spring容器去管理。
4:运行下主函数:这就把bean-core中的Order对象的实例在boot-auto项目中给拿了出来。
4.1:也可以通过context对象把配置类拿出来:
4.2、在boot-auto的工程里面配置的属性配置文件里面配置数据源的drvicerClassName配置信息如下:
在主类中就可以拿到driverClassName的信息。
上面的就是很灵活的方式。
上面的功能在cloud中的config中已经存在了。
所以说一般好的架构都是在第三方的工程里配置比如:redis,mongdb,mysql。