SpringBoot学习

111 阅读3分钟

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