社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
前面我们已经写了个小项目,包括编写了controller和service,发现springboot应用确实简单,但是为什么呢,接下来我们从它的pom文件分析一下,一探究竟。
pom文件深究
我们可以看到项目为我们导入这么多的jar包
查看导入的父项目依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version>
</parent>
而他的父项目又是:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
而他的就是:
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.1.RELEASE</version>
然后可以看到他定义的各种依赖的版本:
可以看到他真正管理spring boot应用里面的所有依赖版本,相当于Spring Boot的版本仲裁中心,以后我们导入依赖默认是不需要写版本,
没有在dependencies里面管理的依赖自然需要我们来声明版本号。
既然父项目只是作为版本仲裁,那么这些jar包是由谁导入进来的呢?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
看到这个依赖,我们可以拆开来理解spring-boot-starter 和 web;
我们可以点击进入spring-boot-starter-web,可以看到:
<!-- 依赖于spring-boot-starter基础项目 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.1.1.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
<version>2.1.1.RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 依赖于spring-boot-starter中的Tomcat -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.1.RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 依赖于hibernate-validator,来做数据检验用的 -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.13.Final</version>
<scope>compile</scope>
</dependency>
<!-- 支持springMVC的jar包1 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 支持springMVC的jar包2 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.3.RELEASE</version>
<scope>compile</scope>
</dependency>
spring-boot-starter:spring-boot场景启动器,帮我导入了web模块正常运行所依赖的组件,所依赖的版本都受父项目版本仲裁。
可以参考一下spring boot的官方文档:https://spring.io
点击Reference Doc,可以搜索下starter,点击进入starters
看见官方的解释:Starters are a set of convenient dependency descriptors that you can include in your application,意识就是Starters就是一系列依赖描述的组合,我们可以导入相关的starter,就可以有相应的依赖了。
spring boot将所有的功能都抽取出来一个个场景:
如果要web开发就导入:
等等。。。。
Spring Boot将所有的功能场景都抽取出来,做成一个个的starters(启动器),我们只需要在项目里面引入这些starter相关场景的所有依赖就会导入进来,要用什么功能就导入什么场景的启动器即可。
我们可以将此注解注释掉,然后启动查看控制台输出,这时候就会报错
@SpringBootApplication:Spring Boot应用标注在某个类上,说明这个类是是Spring Boot的主配置类,SpringBoot就应该运行这个类的main方法启动SpringBoot应用;
接下来我们可以点击进入此注解一探究竟@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 {
可以看到这么多注解,接下来我们可以解读一下:
spring boot的配置类,标注在某一个类上,表示这是一个spring boot的配置类;可以点进入这个注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
可以看到这个注解@Configuration,这个注解就是我们之前使用spring时候定义的一个注解,@Configuration是标注配置类上的一个注解。
配置类和配置文件,像以前我们开发的时候会编写配置文件,文件一多就太麻烦了,可以将配置文件一个个替换成配置类,主要标注了@Configuration这个注解,spring boot就会知道这是个配置类,包括你如果标注@SpringBootConfiguration 和 @Configuration效果是一样的,只不过@Configuration是spring定义的注解,而@SpringBootConfiguration 是spring boot定义的注解。
而这个配置注解@Configuration 点进去他其实就是一个组件:
可以看到配置类其实也是容易中的一个组件@Component
我们可以看到整个应用中没有做任何配置,springMVC启动起来了,整个应用也能用了,controller控制的包扫描也扫进去了,这些功能都是怎么做的呢?就是用的这个注解@EnableAutoConfiguration ,告诉SpringBoot开启自动配置功能,这样自动配置才能生效, 以前我们需要配置的东西,现在我们都不需要配置了,SpringBoot帮我们配置。
接下来,我们还是点进源码,一探究竟:(点击进入@EnableAutoConfiguration)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
首先我们先解读@AutoConfigurationPackage,根据字面意识是:自动配置包,然后我们点击进入看到
@Import({Registrar.class}) 是spring的底层注解,他的作用就是给容器中导入一个组件,就是导入这个组件括号中的这个类:
import org.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar;
导入的组件都是源于这个类Registrar,然后我们进入这个类中查看:
可以看到这个方法registerBeanDefinitions,注册Bean定义信息,主要是这边new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()这个metadata可以拿到注解的源信息,接下来我们以debug的方式启动查看matadata的信息
主要是这个new AutoConfigurationPackages.PackageImport(metadata)).getPackageName()我们算一下包名
到此可以看出@EnableAutoConfiguration注解本身的含义就是将我们主配置类所在的包下及下面所有的子包里面的所有的组件都扫描到Spring容器内;
接下来我们测试验证一下,也创建一个HelloController,通过页面访问一下,但是创建此类的位置我们放在启动类(SpringBootDomeApplication)的外面
可以看到放到外面的包无法扫描,报404
给容器中导入组件?
AutoConfigurationImportSelector:导入那些组件的选择器;接下来我们点击进去看一下:
selectImports这个方法返回Stinrg[] ,这个方法的作用就是告诉spring容器要导入那些组件,这些组件都是以string数组的方式返回全类名,这些组件就会被添加到容器中,我们打上断点,来debug运行一下
可以看到都是XXConfiguration,听着名字是XX的自动配置;
最终这个注解会给容器中导入非常多的自动配置类(xxAutoConfiguration),就是给容器中导入这个场景需要的所有组件,并配置好这些组件
例如我们想做Aop功能的会把Aop相关的组件配置好,有了自动配置类,免去了我们手动编写配置注入功能组件等的工作;
这些自动配置类是怎么得到的呢?他从哪扫描的呢?
这些都是有据可查:他调用了这个方法getCandidateConfigurations
然后又调用了这个方法SpringFactoriesLoader.loadFactoryNames
看到这个方法需要传两个参数,第一个参数的值我们点进去this.getSpringFactoriesLoaderFactoryClass()
第二个参数是 this.getBeanClassLoader()类加载器机制;
他的作用是什么?我们可以点进去这个方法
然后再点击入此方法
可以看到类加载器会回去这个资源:META-INF/spring.factories,获取资源以后,会从这个资源中当成一个properties配置文件,然后从文件中获取到factoryClassName工厂的名字,我们可以看下spring.factories中的配置
这里的配置就是刚才debug中configurations集合中的配置类
一句话总结:SpringBoot在启动的时候从类路径下META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,然后自动配置就生效了,就可以帮我们进行自动配置工作了,然后我们就不用写那么多代码了
其实我们可以看一下,点击进入
先记住这些注解,@Bean就是给容器添加一个组件,之后的文章会再做介绍
添加前端的视图解析器
所以说以前我们需要自己配置的东西,自动配置类都帮我们做了;然后我们看下这张图:
可以看到autoconfigure包下,这是SpringBoot对我们J2EE的大整合,J2EE的整体整合解决方法和自动配置都在spring-boot-autoconfigure-2.1.1.RELEASE.jar这个包下;
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!