目录
一、@SpringBootApplication
二、@EnableAutoConfiguration
1.AutoConfigurationPackages.Registrar.class 批量注册组件
2.AutoConfigurationimportSelector.class
三、按需开启自动配置
1.得益于按条件装配@Conditional
2.例如AOP:
四、总结
五、springboot快速配置
一、@SpringBootApplication
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@SpringBootConfiguration // 就是@Configuration。代表当前是一个配置类
@EnableAutoConfiguration // 开启自动配置
// 指定扫描哪些,Spring注解
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
二、@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@AutoConfigurationPackage //
@import(AutoConfigurationimportSelector.class) // 给容器中导入一个组件
public @interface EnableAutoConfiguration {
1.AutoConfigurationPackages.Registrar.class 批量注册组件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@import(AutoConfigurationPackages.Registrar.class) //给容器中导入一个组件
public @interface AutoConfigurationPackage {
static class Registrar implements importBeanDefinitionRegistrar, Determinableimports {
@Override
public void registerBeanDefinitions(Annotationmetadata metadata, BeanDefinitionRegistry registry) {
// 注册注解包名下面所有的组件
register(registry, new Packageimports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set
2.AutoConfigurationimportSelector.class
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@AutoConfigurationPackage //
@import(AutoConfigurationimportSelector.class) // 给容器中导入一个组件
public @interface EnableAutoConfiguration {
1.AutoConfigurationPackages.Registrar.class 批量注册组件
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@import(AutoConfigurationPackages.Registrar.class) //给容器中导入一个组件
public @interface AutoConfigurationPackage {
static class Registrar implements importBeanDefinitionRegistrar, Determinableimports {
@Override
public void registerBeanDefinitions(Annotationmetadata metadata, BeanDefinitionRegistry registry) {
// 注册注解包名下面所有的组件
register(registry, new Packageimports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set
2.AutoConfigurationimportSelector.class
(1)、利用getAutoConfigurationEntry(annotationmetadata);给容器中批量导入一些组件
(2)、调用List
(3)、利用工厂加载 Map
(4)、从meta-INF/spring.factories位置来加载一个文件。
默认扫描我们当前系统里面所有meta-INF/spring.factories位置的文件
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有meta-INF/spring.factories
虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置。
// org.springframework.boot.autoconfigure.AutoConfigurationimportSelector#getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(Annotationmetadata annotationmetadata) {
if (!isEnabled(annotationmetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationmetadata);
List configurations = getCandidateConfigurations(annotationmetadata, attributes);
configurations = removeDuplicates(configurations);
Set exclusions = getExclusions(annotationmetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationimportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
三、按需开启自动配置
1.得益于按条件装配@Conditional
可修饰在类、方法上。 @ConditionalOnBean // 当容器中存在指定的组件时才。。。 @ConditionalOnMissingBean // 当容器中不存在指定的组件时才。。。 @ConditionalOnClass // 当容器中有某一个类时才。。。 @ConditionalOnMissingClass // 当容器中没有某一个类时才。。。 @ConditionalOnResource // 当项目类路径存在某个资源时才。。。 @ConditionalOnJava // 当项目环境是指定的java版本号时才。。。 @ConditionalOnWebApplication // 当应用是一个web应用时才。。。 @ConditionalOnSingleCandidate // 当容器中只有一个实例或者有用@Primary修饰的默认bean。 @ConditionalOnProperty // 当配置文件中配置了某个属性时才。。。 @ConditionalOnBean(name = "tom") @ConditionalOnMissingBean(name = "tom")
2.例如AOP:
假如说配置文件没有spring.aop.auto=true,matchIfMissing默认就是true,默认就是开启AOP。
我们可以看到里面有大量使用@Conditional判断。
package org.springframework.boot.autoconfigure.aop;
import org.aspectj.weaver.Advice;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class CglibAutoProxyConfiguration {
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
static class ClassProxyingConfiguration {
ClassProxyingConfiguration(BeanFactory beanFactory) {
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
}
}
}
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {
public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";
public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";
@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
protected static class DispatcherServletConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
return dispatcherServlet;
}
//给容器中加入了文件上传解析器
@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;
}
}
@Configuration(proxyBeanMethods = false)
@Conditional(DispatcherServletRegistrationCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
@import(DispatcherServletConfiguration.class)
protected static class DispatcherServletRegistrationConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
WebMvcProperties webMvcProperties, ObjectProvider multipartConfig) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
webMvcProperties.getServlet().getPath());
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadonStartup(webMvcProperties.getServlet().getLoadonStartup());
multipartConfig.ifAvailable(registration::setMultipartConfig);
return registration;
}
}
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
private final Encoding properties;
public HttpEncodingAutoConfiguration(ServerProperties properties) {
this.properties = properties.getServlet().getEncoding();
}
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
return filter;
}
@Bean
public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
return new LocaleCharsetMappingsCustomizer(this.properties);
}
static class LocaleCharsetMappingsCustomizer
implements WebServerFactoryCustomizer, Ordered {
private final Encoding properties;
LocaleCharsetMappingsCustomizer(Encoding properties) {
this.properties = properties;
}
@Override
public void customize(ConfigurableServletWebServerFactory factory) {
if (this.properties.getMapping() != null) {
factory.setLocaleCharsetMappings(this.properties.getMapping());
}
}
@Override
public int getOrder() {
return 0;
}
}
}
四、总结
* SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
* 每个自动配置类按照条件进行生效(@Conditionalxxxx),默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
* 生效的配置类就会给容器中装配很多组件
* 只要容器中有这些组件,相当于这些功能就有了
* SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先(@ConditionalOnMissingBean)
*定制化配置:① 用户直接自己@Bean替换底层的组件② 用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration ---> 组件 ---> xxxxProperties里面拿值 ----> application.properties
五、springboot快速配置
1.引入场景依赖
https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-starter
2.查看自动配置了哪些(选做)
自己分析,引入场景对应的自动配置一般都生效了
配置文件中debug=true开启自动配置报告。Negative(不生效)Positive(生效)
3.修改配置项
(1)参照文档修改配置项
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html#common-application-properties
(2)自己分析。xxxxProperties绑定了配置文件的哪些。
4.自定义加入或者替换组件
@Bean、@Component。。。
5.自定义器 XXXXXCustomizer



