SpringBoot自动配置原理

自动配置原理入门

1.引导加载自动配置类

自动配置因为是在:主程序类中添加了@SpringBootApplication注解

由于@SpringBootApplication注解是由下面三个注解组成的

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}
A.@SpringBootConfiguration注解

@SpringBootConfiguration注解本质就是一个@Configuration注解,说明:@SpringBootConfiguration标识的类就是一个配置类

@Configuration
@Indexed
public @interface SpringBootConfiguration {}
B.@ComponentScan注解

@ComponentScan是用于包扫描的

C.@EnableAutoConfiguration注解【重点】

@EnableAutoConfiguration注解作用是:一个是加载指定包中所有组件,一个是加载系统文件"META-INF/spring.factories"中的组件【注意是:在"META-INF/spring.factories"中的组件是按照条件装配规则(@Conditional)】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-znF0F6XT-1655554093021)(img\1654261673485.png)]

@EnableAutoConfiguration@SpringBootApplication注解的组合注解中的其中一个,也是最重要的一个

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}

1》@AutoConfigurationPackage:自动配置包?指定了默认的包规则

@AutoConfigurationPackage注解说明了指定导入那个包及其子包的所有组件

@Import(AutoConfigurationPackages.Registrar.class)// 给`@Import`注解是导入一个组件 
public @interface AutoConfigurationPackage {}

// 利用Registrar给容器中导入一系组件
// 将指定的一个包下的所有组件导入进行:就是`主程序类`所在包下及其子包

Registrar类:该类是用来注册主程序类下所在包下及其子包的组件 【就是利用Registrar给容器创建一系列对象】

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {

		@Override
		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
			register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
            // new PackageImports(metadata).getPackageNames()是获取当前`主程序类`所有在的包
            
            //register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));是注册`主程序类`所有在包及其子包
		}
		
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-epeqLLeE-1655554093023)(img\1654261323306.png)]

2》@Import(AutoConfigurationImportSelector.class)

@Import(AutoConfigurationImportSelector.class)是加载默认扫描我们当前系统里面所有META-INF/spring.factories位置中的文件

1.利用getAutoConfigurationEntry(annotationMetadata);方法给容器中批量导入一些组件

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



2.调用public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {}获取到所有需要导入到容器中的配置类

    
3.private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
        Map<String, List<String>> result = (Map)cache.get(classLoader);得到所有组件
            
4.从`META-INF/spring.factories`位置来加载一个文件
     默认扫描我们当前系统所有META-INF/spring.factories位置文件
     Enumeration urls = classLoader.getResources("META-INF/spring.factories");

总结:@Import(AutoConfigurationImportSelector.class)是从当前系统的"META-INF/spring.factories"位置扫描需要加载的组件【注意是:在"META-INF/spring.factories"中的组件是按照条件装配规则(@Conditional),不是一下子全部加载是按照条件装配规则加载】

2.修改SpringBoot底层默认配置

例如:

		@Bean
		@ConditionalOnBean(MultipartResolver.class)  //容器中有这个类型组件
		@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
		public MultipartResolver multipartResolver(MultipartResolver resolver) {
            //给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
            //SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
			// Detect if the user has created a MultipartResolver but named it incorrectly
			return resolver;
		}

给容器中加入了文件上传解析器;

说明了:SpringBoot默认会在底层配好所有的组件,但是如果用户自己配置了以用户的优先

总结:【非常重要】

  • SpringBoot先加载所有的自动配置类xxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会绑定文件指定的值。xxxProperties里面拿,xxxProperties和配置文件进行了绑定
  • 生效的配置类就会给容器中装配很多组件【原因是有了这个组件,才能进行指定的装配】
  • 根据上面说明:我们可以定制化配置两种方式
    • 用户直接自动定义一个配置类使用@Bean创建一个Bean对象替换底层的组件【因为底层做了判断用户有自己定义组件,则用用户的】
    • 用户去看这个组件是获取的配置文件什么值就去修改核心配置文件即可【开发推荐使用,如下面示例】

**示例一:**有:@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)注解直接从该注解获取前缀

例如:下面SpringMVC字符编码:解决中文乱码问题

第一步:查看底层config包中找到指定类

@Configuration(proxyBeanMethods = false)  // 这是一个配置类
@EnableConfigurationProperties(ServerProperties.class)  // 与ServerProperties.class类,表示开启配置绑定
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) //是否是原生态Servlet
@ConditionalOnClass(CharacterEncodingFilter.class) //在容器中是否有CharacterEncodingFilter组件,有才进行下面自动装配
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) //是否包含该配置文件:前缀是:`server.servlet.encoding`,如果没有也默认有了
public class HttpEncodingAutoConfiguration {}

第二步:@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)注解【有@ConditionalOnProperty注解直接从这个注解中获取前缀,没有再找@EnableConfigurationProperties(ServerProperties.class)中获取前缀】:获取前缀:server.servlet.encoding

第三步:在application.properties核心配置文件中修改:

#修改字符编码
server.servlet.encoding.charset=GBK

注意是:示例一本质就是示例的方式

示例二:@EnableConfigurationProperties(CacheProperties.class)中获取前缀

第一步:查看底层源码

@Configuration(proxyBeanMethods = false)表示配置类
@ConditionalOnClass(CacheManager.class)是否包含该CacheManager.class类在容器中
@ConditionalOnBean(CacheAspectSupport.class)是否包含该Bean在容器中CacheAspectSupport.class
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")不包含该Bean在容器中
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureAfter({ CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class,
		HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
public class CacheAutoConfiguration {}

第二步:@EnableConfigurationProperties(CacheProperties.class)定位到该注解的CacheProperties类上

@ConfigurationProperties(prefix = "spring.cache")
public class CacheProperties {}

第三步:获取前缀 :spring.cache

第四步:在核心配置文件application.properties中修改默认配置

#配置缓冲
spring.cache.ehcache.config=bean.xml

非常重要:xxxAutoConfiguration —> 组件 ----> xxxProperties里面拿值 ----> application.properties,由于组件和核心配置文件application.properties存在上述关系,我们只需要修改核心配置文件,就是修改掉底层默认的值

3.开发SpringBoot实践步骤

A.引入场景依赖

参考下面官方地址

[Developing with Spring Boot](https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters)

B.查看自动配置了哪些是否生效了

方式一:自动分析,引入场景对应的自动配置

方式二:在核心配置文件application.properties中开启debug=true自动配置报告

  • Positive表示是生效的

  • Negative表示是不生效的

C.是否需要修改配置文件

方式一:和上述修改SpringBoot底层默认配置一样

方式二:参考官方文档:

(https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#appendix.application-properties)

D.自定义加入或者替换组件

@Bean@Component

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值