目录
@AutoConfiguration@Import@ConfigurationProperties
@AutoConfiguration
读取所有jar包下的 /META-INF/spring.factories 并追加到一个 LinkedMultiValueMap 中。每一个url中记录的文件路径如下:
file:/C:/Users/wangchao/apache-maven-3.5.0/repo/com/baomidou/mybatis-plus-boot-starter/3.5.1/mybatis-plus-boot-starter-3.5.1.jar!/META-INF/spring.factories
按照如下路径查看 - // 1. @EnableAutoConfiguration
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Inherited
- @AutoConfigurationPackage
- @Import(AutoConfigurationImportSelector.class)
- public @interface EnableAutoConfiguration {
- }
- // 2. AutoConfigurationImportSelector.class#selectImports()
- public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
- ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
- @Override
- public String[] selectImports(AnnotationMetadata annotationMetadata) {
- if (!isEnabled(annotationMetadata)) {
- return NO_IMPORTS;
- }
- AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
- return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
- }
- }
- // 3. AutoConfigurationImportSelector.class#getAutoConfigurationEntry()
- protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
- if (!isEnabled(annotationMetadata)) {
- return EMPTY_ENTRY;
- }
- AnnotationAttributes attributes = getAttributes(annotationMetadata);
- List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
- configurations = removeDuplicates(configurations);
- Set<String> exclusions = getExclusions(annotationMetadata, attributes);
- checkExcludedClasses(configurations, exclusions);
- configurations.removeAll(exclusions);
- configurations = getConfigurationClassFilter().filter(configurations);
- fireAutoConfigurationImportEvents(configurations, exclusions);
- return new AutoConfigurationEntry(configurations, exclusions);
- }
- // 4. AutoConfigurationImportSelector.class#getCandidateConfigurations()
- protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
- List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
- 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;
- }
- // 5. org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames()
- public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
- String factoryTypeName = factoryType.getName();
- return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
- }
复制代码最终使用 loadSpringFactories(@Nullable ClassLoader classLoader) 方法读取所有配置文件。 - // 6. org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories()
- private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
- MultiValueMap<String, String> result = cache.get(classLoader);
- if (result != null) {
- return result;
- }
- try {
- Enumeration<URL> urls = (classLoader != null ?
- classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
- ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
- result = new LinkedMultiValueMap<>();
- while (urls.hasMoreElements()) {
- // 读取所有jar包下的 /META-INF/spring.factories
- URL url = urls.nextElement();
- UrlResource resource = new UrlResource(url);
- Properties properties = PropertiesLoaderUtils.loadProperties(resource);
- for (Map.Entry<?, ?> entry : properties.entrySet()) {
- String factoryTypeName = ((String) entry.getKey()).trim();
- for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
- result.add(factoryTypeName, factoryImplementationName.trim());
- }
- }
- }
- cache.put(classLoader, result);
- return result;
- }
- catch (IOException ex) {
- throw new IllegalArgumentException("Unable to load factories from location [" +
- FACTORIES_RESOURCE_LOCATION + "]", ex);
- }
- }
复制代码tomcat的自动配置内置于springboot的autoconfiguration中。参考tomcat的自动配置:SpringBoot如何实现Tomcat自动配置
mybatis-plus的配置没有被springboot包括。因此mybatis-stater中包含一个包mybatis-spring-boot-autoconfigure,这其中配置了需要自动配置的类。
因此我们也可以在自己的项目下新建 /META-INF/spring.factories ,并配置自动配置类。
@Import
@Import 用于导入配置类或需要前置加载的类。被导入的类会注册为Bean,可直接作为Bean被引用。它的 value 属性可以支持三种类型:
被 @Configuration 修饰的配置类、或普通类(4.2版本之后可以)。ImportSelector 接口的实现。ImportBeanDefinitionRegistrar 接口的实现。
@Import 的配置 - @Configuration
- @Import(value = {TestA.class, TestB.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
- public class ConfigurationTest {
- }
复制代码导入一个普通类 - package com.example.ssmpdemo.entity;
- public class TestA {
- public void fun(){
- System.out.println("testA");
- }
- }
复制代码导入一个配置类 - package com.example.ssmpdemo.entity;
- import org.springframework.context.annotation.Configuration;
- @Configuration
- public class TestB {
- public void fun(){
- System.out.println("testB");
- }
- }
复制代码通过实现 ImportSelector 接口 - import org.springframework.context.annotation.ImportSelector;
- import org.springframework.core.type.AnnotationMetadata;
- public class MyImportSelector implements ImportSelector {
- @Override
- public String[] selectImports(AnnotationMetadata importingClassMetadata) {
- return new String[]{"com.example.ssmpdemo.entity.TestC"};
- }
- }
复制代码通过重写 ImportBeanDefinitionRegistrar 的 registerBeanDefinitions 方法。 - import com.example.ssmpdemo.entity.TestD;
- import org.springframework.beans.factory.support.BeanDefinitionRegistry;
- import org.springframework.beans.factory.support.RootBeanDefinition;
- import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
- import org.springframework.core.type.AnnotationMetadata;
- public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
- @Override
- public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
- RootBeanDefinition root = new RootBeanDefinition(TestD.class);
- registry.registerBeanDefinition("testD", root);
- }
- }
复制代码 @ConfigurationProperties
支持常见的下划线、中划线和驼峰的转换。支持对象引导。比如:user.friend.name 代表的是user对象中的friend对象中的name需要有set()方法只添加 @ConfigurationProperties(prefix = "xxx") 并不会生效,需要配合 @Configuration 让容器识别到。@EnableConfigurationProperties(value = ConfigData.class ) 会将value中指定的类注册为Bean,可直接用 @AutoWired 引用。
1.定义一个类用来记录所有字段,并使用@ConfigurationProperties(prefix = "xxx")将数据注入到ConfigData中。 - package com.example.ssmpdemo.entity;
- import lombok.Data;
- import org.springframework.boot.context.properties.ConfigurationProperties;
- /**
- * 用来记录Configuration的数据
- * @author wangc
- */
- @Data
- @ConfigurationProperties(value = "spring.datasource.druid")
- public class ConfigData {
- private String driverClassName;
- private String url;
- private String username;
- private String password;
- }
- # 对应的yml文件
- spring:
- datasource:
- druid:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:5506/ssmpdemo?serverTimezone=UTC
- username: root
- password: xxxx
复制代码2.使用@EnableConfigurationProperties(JDBCProperties.class) 将 ConfigData 注册为Bean,并提供给ConfigurationTest使用 。可将ConfigData作为参数注入到构造函数和普通函数中。
3.可以用以下方式引用被@ConfigurationProperties(value = "spring.datasource.druid")修饰的ConfigData
可以直接把 ConfigData 当成Bean使用 - /**
- * 可直接被注入
- */
- @Autowired
- private ConfigData configData;
复制代码可以用构造函数传入进来 - @Data
- @Configuration
- @EnableConfigurationProperties(value = ConfigData.class )
- public class ConfigurationTest {
- private ConfigData configData2;
- /**
- * 作为构造函数的参数注入
- * @param data
- */
- ConfigurationTest(ConfigData data){
- this.configData2 = data;
- }
复制代码也可以作为@Bean的方法函数的参数。只有当前类(ConfigurationTest)才可 - /**
- * 直接作为函数的参数
- * @param data
- * @return
- */
- @Bean(name = "configData2")
- HashMap<String, String> getBean(ConfigData data){
- return new HashMap<>(0);
- }
复制代码可以省略ConfigData直接将字段注入到返回结果中。 - @Bean
- @ConfigurationProperties(value = "spring.datasource.druid")
- HashMap<String, String> getBean2(ConfigData data){
- // 会自动为hashMap赋值,或使用set方法为对象赋值
- return new HashMap<>();
- }
复制代码EnableConfigurationProperties注解的内部如下,它导入了一个实现了 ImportBeanDefinitionRegistrar 接口的类。 - @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- @Import(EnableConfigurationPropertiesRegistrar.class)
复制代码- class EnableConfigurationPropertiesRegistrar implements ImportBeanDefinitionRegistrar {
- @Override
- public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
- registerInfrastructureBeans(registry);
- ConfigurationPropertiesBeanRegistrar beanRegistrar = new ConfigurationPropertiesBeanRegistrar(registry);
- // 获得@EnableConfigurationProperties的value指向的对象,并注册。
- getTypes(metadata).forEach(beanRegistrar::register);
- }
复制代码到此这篇关于一文带你了解SpringBoot中常用注解的原理和使用的文章就介绍到这了,更多相关SpringBoot注解内容请搜索中国红客联盟以前的文章或继续浏览下面的相关文章希望大家以后多多支持中国红客联盟! |