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

download:Go读书社区web开发与高性能架构优化 @SpringBootApplication注解剖析
以下是注解@SpringBootApplication的源码完成
【Go读书社区web开发与高性能架构优化】@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配置文件中的:,可运用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); } } }

    推荐阅读