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;@Configurationpublic class BeanConfig {@Beanpublic Order CreateOrder(){return new Order();}@Beanpublic 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;@Configurationpublic 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。