SpringBoot 自己学习记录
- 自动装配
@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 {
}
1)@SpringBootConfiguration 表名该类是一个Spring的配置类。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
2)@ComponentScan
- @ComponentScan的功能其实就是自动扫描并加载符合条件的组件或bean定义,最终将这些bean定义加载到容器中
3)@EnableAutoConfiguration 代表开启springboot的自动装配
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class<?>[] exclude() default {};
String[] excludeName() default {};
}
其中AutoConfigurationPackage这个注解是自动配置包,主要是使用@import来给spring容器导入一个组件,这里导入的是Registrar.class
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
看下这个类
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]));
//就是通过这个方法获取扫描的包路径
// @SpringBootApplication的所在包及子包里面所有组件扫描加载到Spring容器。所以包名一定要注意。
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImports(metadata));
}
}
@Import({AutoConfigurationImportSelector.class})组件选择器
public AutoConfigurationImportSelector() {
}
// 将所有需要导入的组件以全类名的方式返回。组件就会添加到容器中(待查看为什么会)
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
4)@Configuration:说明Spring的配置类也是Spring的一个组件。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(
annotation = Component.class
)
String value() default "";
boolean proxyBeanMethods() default true;
}
自动装配类会从META-INF/spring.factories中获取资源,然后通过Properties加载资源:
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
private static final Log logger = LogFactory.getLog(SpringFactoriesLoader.class);
static final Map<ClassLoader, Map<String, List<String>>> cache = new ConcurrentReferenceHashMap();
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");
/**
* Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。以前我们需要自己配置的东西,自动配置类都帮我们完成了。
**/
(
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);
}
}
}
5)、@Documented 注解
Documented注解表明这个注释是由 javadoc记录的,在默认情况下也有类似的记录工具。 如果一个类型声明被注释了文档化,它的注释成为公共API的一部分。
6)、@Retention() 注解
RetentionPolicy这个枚举类型的常量描述保留注释的各种策略,它们与元注释(@Retention)一起指定注释要保留多长时间
7)、@Target() 注解
ElementType 这个枚举类型的常量提供了一个简单的分类:注释可能出现在Java程序中的语法位置(这些常量与元注释类型(@Target)一起指定在何处写入注释的合法位置)
- spring-boot-autoconfigure-2.6.1.jar 自动装配jar
- additional-spring-configuration-metadata.json 配置文件
- spring-autoconfigure-metadata.properties 可以查看所有的自动装配配置
加载静态资源文件
WebMvcAutoConfiguration 这个配置类可以配置资源文件
//加载静态资源文件
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");
//可以查找到请求路径
this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
// 可以查看映射路径
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, "/");
registration.addResourceLocations(new Resource[]{resource});
}
});
}
}
查找请求路径
@ConfigurationProperties(
prefix = "spring.mvc"
)
public class WebMvcProperties {
private org.springframework.validation.DefaultMessageCodesResolver.Format messageCodesResolverFormat;
private final WebMvcProperties.Format format = new WebMvcProperties.Format();
private boolean dispatchTraceRequest = false;
private boolean dispatchOptionsRequest = true;
private boolean ignoreDefaultModelOnRedirect = true;
private boolean publishRequestHandledEvents = true;
private boolean throwExceptionIfNoHandlerFound = false;
private boolean logRequestDetails;
private boolean logResolvedException = false;
//请求路径为 /**
private String staticPathPattern = "/**";
private final WebMvcProperties.Async async = new WebMvcProperties.Async();
private final WebMvcProperties.Servlet servlet = new WebMvcProperties.Servlet();
private final WebMvcProperties.View view = new WebMvcProperties.View();
private final WebMvcProperties.Contentnegotiation contentnegotiation = new WebMvcProperties.Contentnegotiation();
private final WebMvcProperties.Pathmatch pathmatch = new WebMvcProperties.Pathmatch();
public WebMvcProperties() {
}
}
资源映射位置 当请求是默认是会从下边四个目录下去找资源文件,优先级分别是:resourse>static>public>META-INF
public static class Resources {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
private String[] staticLocations;
private boolean addMappings;
private boolean customized;
private final WebProperties.Resources.Chain chain;
private final WebProperties.Resources.Cache cache;
public Resources() {
this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
this.addMappings = true;
this.customized = false;
this.chain = new WebProperties.Resources.Chain();
this.cache = new WebProperties.Resources.Cache();
}
public String[] getStaticLocations() {
return this.staticLocations;
}