2022年3月24日SpringBoot笔记 springboot注解及其自动配置原理

本文详细介绍了SpringBoot中的@Configuration、@Import、@Condition、@ImportResource、@ConfigurationProperties、@EnableConfigurationProperties等注解的用途和作用,并探讨了自动配置原理,包括@EnableAutoConfiguration的工作方式,如通过@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})如何实现按需配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.@Configuration注解

作用:标记此类为一个配置类,类似于bean.xml配置文件

@Bean注解:给容器添加组件,一方法名作为组件id,返回类型为组件类型,返回值为组件在容器中的实例

@Configuration
public class TestConfig {
    
    @Bean
    public TestReactor MyHandler(){
        return new TestReactor();
    }
}

①.配置了里面使用@bean标注在方法上给容器注册组件,默认也是单实例;
②.配置类本身也是组件;
③.注解上proxyBeanMethods属性默认为true,代理bean的方法。SpringBoot总会检查这个组件是否在容器中有,保持单实例;

外部无论对配置类中这个方法调用多少次获取的都是之前注册容器中的单实例对象;
这个属性用来接解决组件依赖问题
当这个依赖不用的时候,可以设为false,可以提高springboot的启动速度。

2.@Import

里面是一个Class数组
作用:给容器中自动创建出这多个类型的组件

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
    Class<?>[] value();
}

默认组件的名字为全类名

3.@Condition

作用:条件装配,满足Condition条件的才会当做组件注入
在这里插入图片描述主启动类run有个containsBean方法,可以查看容器中是否包含这个组件

4.@ImportResource

作用,导入beans.xml文件,使用xml方法导入组件

5.@ConfigurationProperties

作用:将properties的配置绑定到javaBean里面
属性:prefix 配置前缀
只有在容器中,再会有sSpringboot提供的功能
感觉可以作为@Value的升级版,直接配置指定的前缀来替代@Vlue

6.@EnableConfigurationProperties

作用:1.开始属性配置功能 2.把组件注入到容器中
等效于@component+@ConfigurationProperties

7.自动配置原理

@SpringBootApplication等同于

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication {

里面的这三个主要注解@SpringBootConfiguration、
@EnableAutoConfiguration、@ComponentScan

@SpringBootConfiguration:代表当前是一个配置类
@ComponentScan:指定要扫描那些

@EnableAutoConfiguration

最重要的注解

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
的合成注解;

(1)@AutoConfigurationPackage

@Import({Registrar.class})
public @interface AutoConfigurationPackage {
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};
}

@Import({Registrar.class})给容器导入一个Registrar组件
利用Registrar再给容器导入更多的一系列组件

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
        Registrar() {
        }

        public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
            AutoConfigurationPackages.register(registry, (String[])(new AutoConfigurationPackages.PackageImports(metadata)).getPackageNames().toArray(new String[0]));
        }

        public Set<Object> determineImports(AnnotationMetadata metadata) {
            return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
        }
    }

AnnotationMetadata :注解的源信息,标记了注解标在神魔位置,它的属性值是神魔

register方法获取注解的包名,然后封装到数组中进行注册
Registrar就是将指定的一个main包下的所有组件导入进来

(2)@Import({AutoConfigurationImportSelector.class})

1.给容器中批量导入一些组件
AutoConfigurationImportSelector的getAutoConfigurationEntry方法

 protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
            configurations = this.removeDuplicates(configurations);
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
            this.checkExcludedClasses(configurations, exclusions);
            configurations.removeAll(exclusions);
            configurations = this.getConfigurationClassFilter().filter(configurations);
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

在这里插入图片描述configurations 中的组件

List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

获取所有的需要导入到容器中的配置类

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;
    }

利用工厂加载,最后使用下面方法得到所有的组件

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader)

private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);
        if (result != null) {
            return result;
        } else {
            HashMap result = new HashMap();

            try {
                Enumeration urls = classLoader.getResources("META-INF/spring.factories");

                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();

                    while(var6.hasNext()) {
                        Entry<?, ?> entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;

                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }

                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
            }
        }
    }

从META-INF/spring.factories位置来加载一个文件
默认扫描我们当前系统里面所有的META-INF/spring.factories位置的文件
在这里插入图片描述spring-boot-autoconfigure-2.6.4.jar里面也有META-INF/spring.factories

在这里插入图片描述里面加载的什么XXXAutoConfiguration
在这个文件里面写死了SpringBoot里面加载的所有配置类
虽然所有的场景的自动配置启动时默认全部加载,最红会按需配置

在这里插入图片描述打开里面有一个可以看到里面的有配置的@Conditionl注解,是根据这个来实现配置是否生效的(IDEA有点问题,没有显示高亮和红色)
这个是是否导入相关依赖的包来确定是否生效的

按照条件装配规则,最终会按需配置。

@Configuration(
    proxyBeanMethods = false
)
@AutoConfigureAfter({JmxAutoConfiguration.class})
@ConditionalOnProperty(
    prefix = "spring.application.admin",
    value = {"enabled"},
    havingValue = "true",
    matchIfMissing = false
)
public class SpringApplicationAdminJmxAutoConfiguration {
    private static final String JMX_NAME_PROPERTY = "spring.application.admin.jmx-name";
    private static final String DEFAULT_JMX_NAME = "org.springframework.boot:type=Admin,name=SpringApplication";

    public SpringApplicationAdminJmxAutoConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean
    public SpringApplicationAdminMXBeanRegistrar springApplicationAdminRegistrar(ObjectProvider<MBeanExporter> mbeanExporters, Environment environment) throws MalformedObjectNameException {
        String jmxName = environment.getProperty("spring.application.admin.jmx-name", "org.springframework.boot:type=Admin,name=SpringApplication");
        if (mbeanExporters != null) {
            Iterator var4 = mbeanExporters.iterator();

            while(var4.hasNext()) {
                MBeanExporter mbeanExporter = (MBeanExporter)var4.next();
                mbeanExporter.addExcludedBean(jmxName);
            }
        }

        return new SpringApplicationAdminMXBeanRegistrar(jmxName);
    }
}

打开一个配置类,从上往下分析,
@ConditionalOnProperty:当里面有spring.application.admin.enabled前缀且值为true时,下面就生效,matchIfMissing如果为true,就是你没有配置也生效;

@ConditionalOnMissingBean作用:它是修饰bean的一个注解,主要实现的是,当你的bean被注册之后,如果而注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个。(复制来自其他博客)
所以这个类的意思就是你在application配置文件中配置了

spring.application.admin.enabled=true

	spring:
	  application:
    	admin:
      		enabled: true

的时候就会生效
第一行第.properties的配置文件,后面是yml(ymal)配置文件
其他的多看看吧,还有好多操作嘞

后面不记了,真多啊 干

补充点:
①.springboot新家在所有的配置类,xxxAutoConfiguration
②.每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值,所有的值都是从xxxxProperties中拿,xxxxProperties和配置文件进行了绑定
③.生效的配置类就会给容器中装配很多组件
④.只要容器中有这些组件,相当于这些功能就有了
⑤.只要用户有自己配置的额,那么就以用户配置的优先
定制化配置
(1)用户直接自己@bean替换底层的组件
(2)用户去看这个组件获取的是配置文件是神魔值,就去修改
在application(bootstrap)配置文件中改

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值