当前位置: 首页 > news >正文

做网贷中介网站赚钱吗/百度seo排名优

做网贷中介网站赚钱吗,百度seo排名优,wordpress开启菜单,虚拟主机 网站镜像文章目录一、SpringBoot的自动配置原理简介自动配置流程图自动配置原理二、SpringBoot自动配置原理源码解析SpringBootApplication注解EnableAutoConfiguration注解深入理解**AutoConfigurationPackage**Import(AutoConfigurationImportSelector.class)1、**理解ImportSelector…

文章目录

  • 一、SpringBoot的自动配置原理
    • 简介
    • 自动配置流程图
  • 自动配置原理
  • 二、SpringBoot自动配置原理源码解析
    • @SpringBootApplication注解
    • @EnableAutoConfiguration注解深入理解
    • **@AutoConfigurationPackage**
    • @Import(AutoConfigurationImportSelector.class)
      • 1、**理解ImportSelector**
      • 2、 **理解DeferredImportSelector**
      • 3、**理解AutoConfigurationImportSelector**
        • 3.1 selectImports中getAutoConfigurationEntry的方法1
        • 3.2 理解SpringBoot是如何按需注册自动配置类到容器中的呢?
  • 三、总结

一、SpringBoot的自动配置原理

简介

我们都知道SpringBoot使用起来非常方便,简单的一个@SpringBootApplication注解和一个applicatin.yml文件就能使一个web项目运行起来。那么我们有没有思考过这其中的原理呢?它是如何做到的呢?

我们知道,一些常用的配置如RestTemplate等,我们竟然可以直接使用@Autowired注解,从Spring容器中拿来使用。那么SpringBoot中又是如何实现自动配置的呢?

所以今天来我们来了解一下SpringBoot是如何实现自动配置的。

自动配置流程图

https://www.processon.com/view/link/5fc0abf67d9c082f447ce49b

自动配置原理

。。。

二、SpringBoot自动配置原理源码解析

我们知道,SpringBoot中最终要的注解应该就是@SpringBootApplication注解,接下来我们通过源码详细的了解一下这个注解。

@SpringBootApplication注解

@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 {......
}
  • @Target(ElementType.TYPE):用于描述注解的使用范围,TYPE表示用于描述类、接口(包括注解类型) 或enum声明
  • @Retention(RetentionPolicy.RUNTIME):当注解标注的类编译以什么方式保留,RetentionPolicy.RUNTIME表明注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
  • @Documented:java doc 会生成注解信息
  • @Inherited:@Inherited
  • @SpringBootConfiguration:Spring Boot的配置类,标注在某个类上,表示这是一个Spring Boot的配置类
  • @EnableAutoConfiguration开启自动配置功能。以前我们需要配置的东西,Spring Boot帮我们自动配置。@EnableAutoConfiguration告诉SpringBoot开启自动配置,会帮我们自动去加载自动配置类
  • @ComponentScan:扫描包 。相当于在spring.xml 配置中< context:comonent-scan> 但是并没有指定basepackage,如果没有指定spring底层会自动扫描当前配置类所有在的包

TypeExcludeFilter:springboot对外提供的扩展类, 可以供我们去按照我们的方式进行排除
AutoConfigurationExcludeFilter:排除所有配置类并且是自动配置类中里面的其中一个

这里比较重要的是@SpringBootConfiguration注解和@EnableAutoConfiguration注解。下面我们来重点看一下这两个注解。

@EnableAutoConfiguration注解深入理解

@EnableAutoConfiguration注解从字面意思可以看出来,这是一个开启自动配置的注解。我们打开这个注解会发现该该注解也是一个复合注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";/*** Exclude specific auto-configuration classes such that they will never be applied.* @return the classes to exclude*/Class<?>[] exclude() default {};/*** Exclude specific auto-configuration class names such that they will never be* applied.* @return the class names to exclude* @since 1.3.0*/String[] excludeName() default {};}

@AutoConfigurationPackage

我们继续跟进去,打开该注解的源码实现:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {/*** Base packages that should be registered with {@link AutoConfigurationPackages}.* <p>* Use {@link #basePackageClasses} for a type-safe alternative to String-based package* names.* @return the back package names* @since 2.3.0*/String[] basePackages() default {};/*** Type-safe alternative to {@link #basePackages} for specifying the packages to be* registered with {@link AutoConfigurationPackages}.* <p>* Consider creating a special no-op marker class or interface in each package that* serves no purpose other than being referenced by this attribute.* @return the base package classes* @since 2.3.0*/Class<?>[] basePackageClasses() default {};}

可以看到,@AutoConfigurationPackage注解的主要作用是扫描配置的包路径(如果不写,默认是扫描该注解所在包路径),并将其中加了Spring相关注解的类解析注入成对应的Bean。

就是注册了一个保存当前配置类所在包的一个Bean。

@Import(AutoConfigurationImportSelector.class)

在了解这个注解整体作用之前,我们先来了解一下AutoConfigurationImportSelector这个类。

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {......	 

可以看到AutoConfigurationImportSelector这个类实现了接口DeferredImportSelector接口(延迟导入选择器)。我们再来看一下这个DeferredImportSelector接口究竟是什么:

public interface DeferredImportSelector extends ImportSelector {@Nullabledefault Class<? extends DeferredImportSelector.Group> getImportGroup() {return null;}public interface Group {void process(AnnotationMetadata var1, DeferredImportSelector var2);Iterable<DeferredImportSelector.Group.Entry> selectImports();......

可以看到,DeferredImportSelector 也是一个接口,而且这个接口也实现了ImportSelector接口。

现在接口有点多,我们先理清关系:

AutoConfigurationImportSelector <— DeferredImportSelector <— ImportSelector

所以说我们现在要先搞清楚这个ImportSelector的作用。

1、理解ImportSelector

public interface ImportSelector {String[] selectImports(AnnotationMetadata var1);@Nullabledefault Predicate<String> getExclusionFilter() {return null;}
}

可以看到,ImportSelector接口中定义有一个selectImports方法和getExclusionFilter方法。从方法名上我们先猜测一下他们的作用。

selectImports 方法返回结果为一个String数组,很有可能是返回要选择注册成为Bean的类全限定名称数组。
getExclusionFilter 方法感觉像是获取排除过滤器,即某些特定类可以通过这种过滤的方式不被注册到Spring容器中。

接下来我们看看DeferredImportSelector 这个接口具体是怎么实现这两个方法的。

2、 理解DeferredImportSelector

DeferredImportSelector从接口名称可以知道这是一个延迟导入选择器。下面的实现内容有点多,可以先简单过一下,不必都搞清楚每一个点。

public interface DeferredImportSelector extends ImportSelector {@Nullabledefault Class<? extends DeferredImportSelector.Group> getImportGroup() {return null;}// 这里又定义了一个Group接口,public interface Group {.....}    
}

简单看来,首先是内部又自己定义了一个Group接口,外面还有一个getImportGroup方法。

我们继续再来研究最终的AutoConfigurationImportSelector类。

3、理解AutoConfigurationImportSelector

AutoConfigurationImportSelector,从名称看来就是自动配置导入器的意思。下面来看看它是如何实现上面的DeferredImportSelector接口的:

由于内容较多,我们只看重点方法。

3.1 selectImports中getAutoConfigurationEntry的方法1

@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}

selectImports我们上面说到可能是返回一些需要引入的类的全限定名集合:[com.test.entity, com.test.service…]。我们来验证一下是否正确。

我们来看一下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);
}<==============================================================================================>
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;
}public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse = classLoader;if (classLoader == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName = factoryType.getName();// 这里loadSpringFactories方法就会从"META-INF/spring.factories"这个配置文件中获取写好的候选配置类return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}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 {// 解析META-INF/spring.factories中的配置,解析key=value的形式。最终将其封装成一个Map<String, List<String>>// 即一个key可能对应多个valueEnumeration urls = classLoader.getResources("META-INF/spring.factories");while(urls.hasMoreElements()) {........}
}                
<==============================================================================================>

总结来看,AutoConfigurationImportSelector的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames() 方法 将 META-INF/spring.factories 中的配置信息扫描解析成一个Map<key, List> 。

总结来说就是获取到了spring.factories这个配置文件中的所有自动配置类的信息。

这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示:
在这里插入图片描述

META-INF/spring.factories文件中列出了常用的自动配置类。这样我们引入第三方starter之后,即使自己没有配置相关的Bean,也可以直接使用@Autowired注解来使用一些Bean。

比如下面的这一段配置:key就是org.springframework.boot.autoconfigure.EnableAutoConfiguration,List就是等于号后面的所有自动配置类。


org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\



我们可以看到有一个RabbitMQ的自动配置类。也就是说我们只要引入amqp这个starer之后,不需要自己配置就可以直接使用@Autowired注入一个RabbitTemplate来直接使用。因为SpringBoot已经帮助我们自动注入了一个默认的配置。我们可以进入到org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration配置类中验证:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {@Configuration(proxyBeanMethods = false)@ConditionalOnMissingBean(ConnectionFactory.class)protected static class RabbitConnectionFactoryCreator {@Beanpublic CachingConnectionFactory rabbitConnectionFactory(RabbitProperties properties,ResourceLoader resourceLoader, ObjectProvider<CredentialsProvider> credentialsProvider,ObjectProvider<CredentialsRefreshService> credentialsRefreshService,ObjectProvider<ConnectionNameStrategy> connectionNameStrategy) throws Exception {CachingConnectionFactory factory = new CachingConnectionFactory(getRabbitConnectionFactoryBean(properties,resourceLoader, credentialsProvider, credentialsRefreshService).getObject());PropertyMapper map = PropertyMapper.get();map.from(properties::determineAddresses).to(factory::setAddresses);map.from(properties::getAddressShuffleMode).whenNonNull().to(factory::setAddressShuffleMode);map.from(properties::isPublisherReturns).to(factory::setPublisherReturns);map.from(properties::getPublisherConfirmType).whenNonNull().to(factory::setPublisherConfirmType);RabbitProperties.Cache.Channel channel = properties.getCache().getChannel();map.from(channel::getSize).whenNonNull().to(factory::setChannelCacheSize);map.from(channel::getCheckoutTimeout).whenNonNull().as(Duration::toMillis).to(factory::setChannelCheckoutTimeout);RabbitProperties.Cache.Connection connection = properties.getCache().getConnection();map.from(connection::getMode).whenNonNull().to(factory::setCacheMode);map.from(connection::getSize).whenNonNull().to(factory::setConnectionCacheSize);map.from(connectionNameStrategy::getIfUnique).whenNonNull().to(factory::setConnectionNameStrategy);return factory;}private RabbitConnectionFactoryBean getRabbitConnectionFactoryBean(RabbitProperties properties,ResourceLoader resourceLoader, ObjectProvider<CredentialsProvider> credentialsProvider,ObjectProvider<CredentialsRefreshService> credentialsRefreshService) {RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean();factory.setResourceLoader(resourceLoader);PropertyMapper map = PropertyMapper.get();map.from(properties::determineHost).whenNonNull().to(factory::setHost);map.from(properties::determinePort).to(factory::setPort);map.from(properties::determineUsername).whenNonNull().to(factory::setUsername);map.from(properties::determinePassword).whenNonNull().to(factory::setPassword);map.from(properties::determineVirtualHost).whenNonNull().to(factory::setVirtualHost);map.from(properties::getRequestedHeartbeat).whenNonNull().asInt(Duration::getSeconds).to(factory::setRequestedHeartbeat);map.from(properties::getRequestedChannelMax).to(factory::setRequestedChannelMax);RabbitProperties.Ssl ssl = properties.getSsl();if (ssl.determineEnabled()) {factory.setUseSSL(true);map.from(ssl::getAlgorithm).whenNonNull().to(factory::setSslAlgorithm);map.from(ssl::getKeyStoreType).to(factory::setKeyStoreType);map.from(ssl::getKeyStore).to(factory::setKeyStore);map.from(ssl::getKeyStorePassword).to(factory::setKeyStorePassphrase);map.from(ssl::getTrustStoreType).to(factory::setTrustStoreType);map.from(ssl::getTrustStore).to(factory::setTrustStore);map.from(ssl::getTrustStorePassword).to(factory::setTrustStorePassphrase);map.from(ssl::isValidateServerCertificate).to((validate) -> factory.setSkipServerCertificateValidation(!validate));map.from(ssl::getVerifyHostname).to(factory::setEnableHostnameVerification);}map.from(properties::getConnectionTimeout).whenNonNull().asInt(Duration::toMillis).to(factory::setConnectionTimeout);map.from(properties::getChannelRpcTimeout).whenNonNull().asInt(Duration::toMillis).to(factory::setChannelRpcTimeout);map.from(credentialsProvider::getIfUnique).whenNonNull().to(factory::setCredentialsProvider);map.from(credentialsRefreshService::getIfUnique).whenNonNull().to(factory::setCredentialsRefreshService);factory.afterPropertiesSet();return factory;}}@Configuration(proxyBeanMethods = false)@Import(RabbitConnectionFactoryCreator.class)protected static class RabbitTemplateConfiguration {@Bean@ConditionalOnMissingBeanpublic RabbitTemplateConfigurer rabbitTemplateConfigurer(RabbitProperties properties,ObjectProvider<MessageConverter> messageConverter,ObjectProvider<RabbitRetryTemplateCustomizer> retryTemplateCustomizers) {RabbitTemplateConfigurer configurer = new RabbitTemplateConfigurer();configurer.setMessageConverter(messageConverter.getIfUnique());configurer.setRetryTemplateCustomizers(retryTemplateCustomizers.orderedStream().collect(Collectors.toList()));configurer.setRabbitProperties(properties);return configurer;}// 可以看到,SpringBoot帮我们自动配置好了一个rabbitTemplate!!!@Bean@ConditionalOnSingleCandidate(ConnectionFactory.class)@ConditionalOnMissingBean(RabbitOperations.class)public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory) {RabbitTemplate template = new RabbitTemplate();configurer.configure(template, connectionFactory);return template;}}
.......	

可以看到,SpringBoot帮我们自动配置好了一个rabbitTemplate!!!

总结:

至此为止,我们应该弄清楚了,SpringBoot是如何实现自动配置的,也搞清楚了整个过程。现在我们可以明确,所有的自动配置类的信息都是存储在/META-INFO/spring.factories这个配置文件中的。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。其实其他很多的starter中都是存在这个spring.factories配置文件的。

这个@EnableAutoConfiguration注解通过@SpringBootApplication被间接的标记在了Spring Boot的启动类上。在SpringApplication.run(…)的内部就会执行selectImports()方法,找到所有JavaConfig自动配置类的全限定名对应的class,然后将所有自动配置类加载到Spring容器中。

我想有一点需要再次阐明一下:我们此时只是解析到了所有的配置类信息到一个Map<key,List> 中,并没有将这些类都注入到Spring容器中去。

我们自己其实也可以思考到,这里足足有127个自动配置类,SpringBoot也不会一股脑的将所有配置类都注册成一个Bean吧。而且,我们实际在项目中使用的时候,根本也不会使用到这么多的配置类。我们一般只会使用我们在maven的pom文件中引入的starter依赖的配置类才对。 比如我的项目中此时除了SpringBoot只引入了一个rabbitMQ的starter,那么SpringBoot应当只帮助我们创建一个rabbitMQ对应的自动配置类即可!

事实上,SpringBoot就是这样做的,那我们就好奇了,它是如何实现的这个功能呢?

3.2 理解SpringBoot是如何按需注册自动配置类到容器中的呢?

不知道大家有没有注意到上面RabbitAutoConfiguration 这个类中有一些特殊的注解:

@ConditionalOnClass({ RabbitTemplate.class, Channel.class })

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
....

@ConditionalOnMissingBean(ConnectionFactory.class)

@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnMissingBean(RabbitOperations.class)
public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory) {RabbitTemplate template = new RabbitTemplate();configurer.configure(template, connectionFactory);return template;
}

每一个XxxxAutoConfiguration自动配置类都是在某些条件之下才会生效的,这些条件的限制在Spring Boot中以注解的形式体现,常见的条件注解有如下几项:

@ConditionalOnBean:当容器里有指定的bean的条件下。

@ConditionalOnMissingBean:当容器里不存在指定bean的条件下。

@ConditionalOnClass:当类路径下有指定类的条件下。

@ConditionalOnMissingClass:当类路径下不存在指定类的条件下。

@ConditionalOnProperty:指定的属性是否有指定的值,比如@ConditionalOnProperties(prefix=”xxx.xxx”, value=”enable”, matchIfMissing=true),代表当xxx.xxx为enable时条件的布尔值为true,如果没有设置的情况下也为true。

这些注解会在Spring处理完用户自定义的@Component、@Service、@Controller、@Configuration等注解后再生效,这里体现了延迟的特点,所以使用的是DeferredImportSelector,而不是默认的ImportSelector。

< ========================== 思路理解 ================================== >
SpringBoot中为何要定义一些这样的注解呢?

不知道大家有没有思考过这样一个问题:SpringBoot帮助我们添加了很多的自动配置类到容器中去,我们的确是可以直接拿来使用的!但是往往的情况是,我们都需要自己配置一个定制的配置类,可能并不会使用SpringBoot中提供的这个自动配置类。那么也就是说,我们自己实现的配置类应当要覆盖掉SpringBoot中存在的自动配置类,或者说当Spring容器中已经存在了一个我们自己配置的配置类之后,SpringBoot就不需要再将自己的自动配置类注册到容器中去了!!!

所以说SpringBoot是需要一些类似于判断容器中是否已有开发者配置的某个Bean、项目中是否已存在某个类(开发者在pom中是否引入了依赖)等这样的约束,所以Spring创建了一些这样条件判断的注解来帮助实现这个功能!!!

这个具体实现我们后面在源码中再来探究!

======================================================================>

那么以上面的RabbitMQ的自动配置类RabbitAutoConfiguration 为例。

类上加了 @ConditionalOnClass({ RabbitTemplate.class, Channel.class }) 注解,说明只有类路径下存在RabbitTemplate.class和Channel.class的时候,这个自动配置类才会生效!

思考这个意思,类路径下何时才会有RabbitTemplate.class呢?SpringBoot下默认肯定是没有整个类的,也就是说只有我们引入了rabbitMQ的starter第三方依赖,才有可能在类路径下存在RabbitTemplate.class这个类。
也就是说,这个RabbitAutoConfiguration自动配置类,只有当我们的pom文件中引入了amqp这个依赖的时候才会生效!

这也正好复合我们上面的问题猜想,SpringBoot按需加载自动配置类才是正确合理的!!!而不是直接加载所有,因为那时候项目中根本就没有一些类存在,所以也根本不可能完成加载。除非是一个必须要用到的类,SpringBoot自己会实现这些类,可以直接注入到容器中。

我们继续分析,RabbitAutoConfiguration类上还有一个 @EnableConfigurationProperties(RabbitProperties.class) 注解,这又是什么意思?

@EnableConfigurationProperties表示开启配置属性,而它后面的参数是一个RabbitProperties类:

@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitProperties {private static final int DEFAULT_PORT = 5672;private static final int DEFAULT_PORT_SECURE = 5671;/*** RabbitMQ host. Ignored if an address is set.*/private String host = "localhost";/*** RabbitMQ port. Ignored if an address is set. Default to 5672, or 5671 if SSL is* enabled.*/private Integer port;/*** Login user to authenticate to the broker.*/private String username = "guest";/*** Login to authenticate against the broker.*/private String password = "guest";......

这个类中我们看到了一个非常熟悉的注解:@ConfigurationProperties(prefix = “spring.rabbitmq”)。我想我们都应该知道这个注解的意思:从配置文件中获取前缀为spring.rabbitmq的配置信息。看到这里是不是感觉一下子就明白了,原来我们在配置文件中的配置属性其实都是对应一个配置类的。比如我们要配置的rabbitMQ的host,port等都对应类中的一个属性。而且,当我们不再配置文件中配置的时候,它们还都有一个默认值!

@ConfigurationProperties,它的作用就是从配置文件中绑定属性到对应的bean上,而@EnableConfigurationProperties负责导入这个已经绑定了属性的bean到spring容器中。那么所有其他的和这个类相关的属性都可以在全局配置文件中定义,也就是说,真正“限制”我们可以在全局配置文件中配置哪些属性的类就是这些XxxxProperties类,它与配置文件中定义的prefix关键字开头的一组属性是唯一对应的。

至此,我们大致可以了解。在全局配置的属性如:rabbitmq.host等,通过 @ConfigurationProperties 注解,绑定到对应的XxxxProperties配置实体类上封装为一个bean,然后再通过 @EnableConfigurationProperties 注解导入到Spring容器中。

而诸多的XxxxAutoConfiguration自动配置类,就是Spring容器的JavaConfig形式,作用就是为Spring 容器导入bean,而所有导入的bean所需要的属性都通过xxxxProperties的bean来获得。


我们继续分析RabbitAutoConfiguration中RabbitTemplate上的注解:

@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnMissingBean(RabbitOperations.class)
public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory) {RabbitTemplate template = new RabbitTemplate();configurer.configure(template, connectionFactory);return template;
}
  • @ConditionalOnSingleCandidate(ConnectionFactory.class):表明spring容器中要有一个单例的ConnectionFactory类。
  • @ConditionalOnMissingBean(RabbitOperations.class):表明spring容器中要没有RabbitOperations.class对应的Bean的时候,这个javaConfig类型的Bean才会生效!

思考:为何要有@ConditionalOnMissingBean这个注解?

因为当我们开发者已经配置了并注册了一个配置Bean到容器中的时候,SpringBoot就不需要再将自己默认的自动配置类再注册到容器中去了!

三、总结

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

参考文章:https://blog.csdn.net/u014745069/article/details/83820511

http://www.lbrq.cn/news/1103599.html

相关文章:

  • 绿色国外网站/网站建设与管理就业前景
  • 网站语言切换前端可以做么/广州头条今日头条新闻
  • 漳州专业做网站/公司网站建设平台
  • 个人做排行网站/关键词挖掘长尾词工具
  • 无锡b2b网站建设/如何快速收录一个网站的信息
  • 凡科建的网站怎么做seo/市场调研报告包括哪些内容
  • 网站空间备案/中国第一营销网
  • 微信怎样制作网站/seo技术服务外包公司
  • 厦门入夏网站建设公司/chatgpt 网址
  • 网站制作金华公司电话/线上推广的方式
  • 理财网站方案建设/北京排名seo
  • 英德市建设局网站/360优化大师官方下载手机
  • 帮熟人做网站如何收费/营销型网站建设策划书
  • 需要手机注册网站/友情链接英语
  • 网站设计要求 优帮云/人民日报今日新闻
  • 深圳 微网站建设ydgcm/软文推广文案
  • 光明新区做网站/百度竞价点击软件
  • 网页设计 做网站的代码/唐山建站公司模板
  • 外贸网站制作哪家快/优化内容
  • 网站建设服务中企动力/怎样创建网站或者网址
  • 日用品企业网站建设/百度网页链接
  • 网站建设费用的会计/东莞seo推广
  • 张家港网站开发制作/济南百度
  • 在线做六级阅读网站/启动互联全网营销推广
  • 潍坊做网站的网络公司/线上seo关键词优化软件工具
  • 昆明网站推广/谷歌浏览器app下载
  • 武汉网站建设可以吗/正规网络教育培训机构
  • 免费域名解析网站建设/seo主管招聘
  • 公司网站建设价位/最佳磁力吧cili8
  • 云南昆明网站建设/seo专业培训学费多少钱
  • 基于FPGA的多级流水线加法器verilog实现,包含testbench测试文件
  • 2.组合式API知识点(1)
  • EXPLAIN:你的SQL性能优化透视镜
  • 零基础学习性能测试第二章-linux服务器监控:网络iftop
  • 异步解决一切问题 |消息队列 |减少嵌套 |hadoop |rabbitmq |postsql
  • 云端成本治理利器:亚马逊云科技智能仪表盘(AWS Cost Intelligence Dashboard)深度解析