关于golang:Go读书社区web开发与高性能架构优化

8次阅读

共计 3930 个字符,预计需要花费 10 分钟才能阅读完成。

download:Go 读书社区 web 开发与高性能架构优化

@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 Target 通过 ElementType 来指定注解可使用范畴的枚举会合(FIELD/METHOD/PARAMETER…)
@Retention Retention(保留)注解说明, 这种类型的注解会被保留到那个阶段. 有三个值:

RetentionPolicy.SOURCE —— 这种类型的 Annotations 只在源代码级别保留, 编译时就会被忽略
RetentionPolicy.CLASS —— 这种类型的 Annotations 编译时被保留, 在 class 文件中存在, 但 JVM 将会忽略
RetentionPolicy.RUNTIME —— 这种类型的 Annotations 将被 JVM 保留, 所以他们能在运行时被 JVM 或其余使
@Documented 注解表明这个注解应该被 javadoc 工具记录. 默认情况下,javadoc 是不包含注解的. 但如果申明注解时指定了 @Documented, 则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包含在生成的文档中
@Inherited 容许子类继承父类的注解,仅限于类注解有用,对于方法和属性有效。
@SpringBootConfiguration 注解实际上和 @Configuration 有雷同的作用,配备了该注解的类就能够以 JavaConfig 的形式实现一些配置,可能不再使用 XML 配置。
@ComponentScan 这个注解实现的是主动扫描的功能,相当于 Spring XML 配置文件中的:<context:component-scan>, 可使用 basePackages 属性指定要扫描的包,及扫描的条件。如果不设置则默认扫描 @ComponentScan 注解所在类的同级类和同级目录下的所有类,所以咱们的 Spring Boot 我的项目,一般会把入口类放在顶层目录中,这样就能够保障源码目录下的所有类都能够被扫描到。
@EnableAutoConfiguration 这个注解是让 Spring Boot 的配置能够如此简化的关键性注解。我把 EnableAutoConfiguration 的实现端上来了,大家来鉴赏一下!

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage 注解用于保存主动配置类以供之后的使用,比如给 JPA entity 扫描器,用来扫描开发人员通过注解 @Entity 定义的 entity 类。通俗的讲就是,注册 bean 定义到容器中。
@Import(AutoConfigurationImportSelector.class)是 EnableAutoConfiguration 注解中最要害的来,它借助 AutoConfigurationImportSelector,可能帮助 SpringBoot 利用将所有符合条件的 @Configuration 配置都加载到以后 SpringBoot 创建并使用的 IoC 容器中。对于 @Import 注解要说的内容还比较多,改天再聊。
对于注解的话题就先谈到这里,上面开启撸代码环节。

3 剖析代码
查看 SpringApplication 的源代码可能发现 SpringApplication 的启动由两部分组成:

new SpringApplication(primarySources):创建 SpringApplication 对象
run(args):调用 run 方法
3.1 实例化 SpringApplication 对象
源码如下:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;//1、初始化资源加载器
    Assert.notNull(primarySources, "PrimarySources must not be null");//2、断言资源加载类不能为 null
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//3、初始化加载资源类会合并去重
    this.webApplicationType = deduceWebApplicationType();//4、推断利用类型是 Standard 还是 Web
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//5、设置利用上下文初始化器
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//6、设置监听器 
    this.mainApplicationClass = deduceMainApplicationClass();//7、推断利用入口类}

上面将针对源码中的重要实现进行粗疏的分析。

3.1.1 初始化资源加载器
ResourceLoader 接口,在 Spring 中用于加载资源,通过它可能获取一个 Resouce 对象。使用 spring 的敌人都知道它加载资源的形式由多种,上面就挑两个罕用的继承 ResourceLoader 的接口与实现类说起。

DefaultResourceLoader:作为 ResourceLoader 接口的间接实现类,该类实现了基本的资源加载功能,可能实现对单个资源的加载。
ResourcePatternResolver:该接口继承了 ResourceLoader,定义了加载多个资源的方法,可能实现对多个资源的加载。
1、DefaultResourceLoader
下面介绍过该类通过实现 ResourceLoader 接口实现了加载单个资源的功能。它的子类通过继承它来实现具体的资源拜访策略。上面来探究下该类如何加载单个资源:

public Resource getResource(String location) {// 这里是三种识别 location 加载出 Resource 的形式。Assert.notNull(location, "Location must not be null");
    //1. 先看有没有自定义的 ProtocolResolver,如果有则先根据自定义的 ProtocolResolver 解析 location 失去 Resource
    for (ProtocolResolver protocolResolver : this.protocolResolvers) {Resource resource = protocolResolver.resolve(location, this);
        if (resource != null) {return resource;}
    }
    //2. 根据路径是否匹配 "/" 或 "classpath:" 来解析失去 ClassPathResource
    if (location.startsWith("/")) {return getResourceByPath(location);
    }else if (location.startsWith(CLASSPATH_URL_PREFIX)) {//classpath
        return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
    }else {
        try {
            // 默认传入的 location 是一个 URL 路径,加载失去一个 UrlResource
            URL url = new URL(location);
            return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
        }
        catch (MalformedURLException ex) {
            // 如果以上三种情况都不满足,则按照“/”来处理
            return getResourceByPath(location);
        }
    }
}
正文完
 0