一个quickstart程序仅仅让我们初步了解一个框架,我们还需要透过现象看本质才能学好一个框架。所以这篇文章分析一下我上次写的springboot的入门程序。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/>
</parent>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
<properties>
<activemq.version>5.15.9</activemq.version>
<antlr2.version>2.7.7</antlr2.version>
...
<commons-pool.version>1.6</commons-pool.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
...
</dependencies>
</dependencyManagement>
在spring-boot-dependencies中对大部分的jar包进行版本管理,再点进去每一个所引用到的starter里面就能看见每个jar包具体的版本。在spring-boot-dependencies已经定义了版本号的jar包,在其他地方引用就不需再写版本号了,而在spring-boot-dependencies没有被依赖的jar包,自行引入的时候就需要写版本号。 特别之处就是spring-boot-dependencies中使用了< dependencyManagement >,dependencyManagement 用于版本管理,声明jar,并不实际引入jar,子模块默认不继承,子模块需要的jar需要在子模块引入,并不需重新写版本号,若子模块定义了新的版本号,则优先使用子模块中的版本。而使用 < dependencies >就是直接引入jar。
(我的入门程序只引用到了spring-boot-starter-web和spring-boot-starter-test)
以往的spring程序都需要把项目发布在Tomcat中,然后手动启动Tomcat服务器进行测试。Springboot的入门程序只需要Run启动类就可以访问url了。这是为什么呢?
我们先点进去spring-boot-starter-web(这里没有写版本号)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
再点进去spring-boot-starter-tomcat
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.21</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>tomcat-annotations-api</artifactId>
<groupId>org.apache.tomcat</groupId>
</exclusion>
</exclusions>
</dependency>
...
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
<version>9.0.21</version>
<scope>compile</scope>
</dependency>
Springboot内嵌了一个Tomcat ! Springboot2.1.6内嵌的Tomcat版本号为9.0.21。
@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 {
}
三个重点注解:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan。下面来分析一下这三个注解。
Springboot配置类。标注在某个类上,表示这是一个Springboot的配置类。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
用了Spring的@Configuration,表明这是一个配置类,相当于配置文件。
自动配置
visual basic @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { }
两个关键注解:@AutoConfigurationPackage、@Import。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
}
@Import({Registrar.class}) 引入了Registrar组件。一个很关键的步骤:将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器。 就是由这一句注解完成的。
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
Registrar() {
}
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
AutoConfigurationPackages.register(registry, (new AutoConfigurationPackages.PackageImport(metadata)).getPackageName());
}
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new AutoConfigurationPackages.PackageImport(metadata));
}
}
将一些快速地导入到Spring容器中
我们可以看getCandidateConfigurations方法中引用的SpringFactoriesLoader.loadFactoryNames方法。
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
Springboot在启动的时候从类路径下的META-INF/spring.factories
中获取EnableAutoConfiguration
指定的值,根据这些值将自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。
相当于Spring配置文件中的,作用就是将不需要扫描的组件在这里声明。
<context:component-scan base-package="xxx">
<context:exclude-filter type="annotation" expression="xxxx"/>
</context:component-scan>
知所以然才能知其所以。学习原理非常重要。
springboot笔记03——quickstart程序原理
原文:https://www.cnblogs.com/Jotal/p/11194432.html