赞
踩
什么是SpringBoot?
引用Spring官网的话说就是:SpringBoot是所有基于spring开发的项目的起点。SpringBoot的设计就是为了让你尽可能快的跑起来spring应用程序,并且尽可能的减少你的配置文件。
它的核心理念就是约定大于配置
SpringBoot的两个主要功能分别是起步依赖和自动配置
我们使用idea随便新建两个SpringBoot程序,在pom文件中几乎都有两个核心依赖,分别是是spring-boot-starterparent和spring-boot-starter-web
为什么SpringBoot导入dependency时,不需要指定版本?
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
点击spring-boot-starter-parent查看他的底层源文件
继续往下点,查看底层源文件
那么我们从这里就可以看出,该文件对一些常用技术框架的依赖文件进行了统一版本号管理,例如activemq、aspectj、db2等等,都是与当前springboot相匹配的版本,这也就是我们在pom文件中引入常用框架不需要写版本号的原因
spring-boot-starterparent是对常用项目依赖版本的统一管理,那么项目运行依赖的jar包是从何而来?
和上面一样,我们点进spring-boot-starter-web来看看它的底层源文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
源文件代码
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.5.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-json</artifactId> <version>2.5.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <version>2.5.0</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.3.7</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.7</version> <scope>compile</scope> </dependency> </dependencies>
通过代码我们就可以看出来,在spring-boot-starter-web这个文件中就对web开发所需要的所有依赖进行了封装打包,例如json、Tomcat、web,mvc等等。
因此,我们使用SpringBoot项目的时候只需要在pom文件中引入spring-boot-starter-web这个依赖启动器,就不需要再额外配置Tomcat,springmvc等。
SpringBoot除了提供了web依赖启动器以外,还提供了很多其他的依赖启动器,通常我们只需要在springboot官方文档中搜索starter关键字即可
列出了Spring Boot官方提供的部分场景依赖启动器,这些依赖启动器适用于不同的场景开发,使用时只需要在pox.xml文件中导入对应的依赖启动器即可。
需要说明的是,Spring Boot官方并不是针对所有场景开发的技术框架都提供了场景启动器,例如数据库操作框架MyBatis、阿里巴巴的Druid数据源等,Spring Boot官方就没有提供对应的依赖启动器。为
了充分利用Spring Boot框架的优势,在Spring Boot官方没有整合这些技术框架的情况下,MyBatis、Druid等技术框架所在的开发团队主动与Spring Boot框架进行了整合,实现了各自的依赖启动器,例如
mybatis-spring-boot-starter、druid-spring-boot-starter等。我们在pom.xml文件中引入这些第三方的依赖启动器时,切记要配置对应的版本号
什么是自动配置?
自动配置就是在我们加载jar包依赖的时候,自动为我们配置一些组件的相关配置,我们无需或只需少许的配置就能够运行编写的项目
如何进行自动配置
SpringBoot的项目应用启动入口是@SpringBootApplication注解标注类的main方法
@SpringBootApplication注解能够扫描Spring组件并且自动配置SpringBoot
@Target({ElementType.TYPE}) //注解的适用范围,Type表示注解可以描述在类、接口、注解或枚举 中 @Retention(RetentionPolicy.RUNTIME) //表示注解的生命周期,Runtime运行时 @Documented //表示注解可以记录在javadoc中 @Inherited //表示可以被子类继承该注解 @SpringBootConfiguration // 标明该类为配置类 @EnableAutoConfiguration // 启动自动配置功能 @ComponentScan( // 包扫描器 excludeFilters = {@Filter( type = FilterType.CUSTOM, classes = {TypeExcludeFilter.class} ), @Filter( type = FilterType.CUSTOM, classes = {AutoConfigurationExcludeFilter.class} )} ) public @interface SpringBootApplication { ... }
在这段代码我们可以看出,@SpringBootApplication是一个组合注解,其中@Target、@Retention、@Document、@Inherited这些都是元注解信息,这里于我们所要研究的问题关系不大, 不在这里讨论,主要看@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan这三个注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
@AliasFor(
annotation = Configuration.class
)
boolean proxyBeanMethods() default true;
}
@SpringBootConfiguration注解刨除元注解以外,只剩一个@Configuration注解,这个注解常用Spring的小伙伴应该比较熟悉,就是用来表明当前类是一个配置文件类,并且可以被扫描到。
那么由此可见@SpringBootApplication和@Configuration作用相同,只不过是SpringBoot对其进行从新分装命名而已
@EnableAutoConfiguration注解表示开启自动配置功能,是实现自动化配置的注解。
@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 {};
}
从源文件代码中,可以看出@EnableAutoConfiguration也是一个组合注解,它由@AutoConfigurationPackage和@Import({AutoConfigurationImportSelector.class})这个两个组合而成。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({Registrar.class})
public @interface AutoConfigurationPackage {
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
@AutoconfigurationPackage主要是由Import({Registrar.class})实现的,@Import注解的作用就是用来给容器导入某个组件,那么@Import({Registrar.class})就是讲Registrar这个组件导入到容器中。
然后我们通过代码可以看到有一个registerBeanDefinition方法,通过debug可以知道图中选中部分返回值就是主程序类所在的包路径。也就是说@AutoConfigurationPackage就是将主程序和其子包下的组件扫描到容器中。
所以我们在定义项目架构的时候,主程序启动类也就是注解@SpringBootApplication所在的类要放在项目最外层,根目录的位置,这样才能保证所有的组件都能被扫描到
同样Import({AutoConfigurationImportSelector.class})是将AutoConfigurationImportSelector这个组件导入到spring容器中,AutoConfigurationImportSelector可以帮助Springboot将所有符合条件的@Configation配置都加载到当前创建的spring ioc容器中
它通过selectImport方法来告诉springboot需要导入哪些组件
// 这个方法告诉springboot都需要导入那些组件
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
//判断 enableautoconfiguration注解有没有开启,默认开启(是否进行自动装配)
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
//1. 加载配置文件META-INF/spring-autoconfigure-metadata.properties,从中获取所有支持自动配置类的条件
//作用:SpringBoot使用一个Annotation的处理器来收集一些自动装配的条件,那么这些条件可以在META-INF/spring-autoconfigure-metadata.properties进行配置。
// SpringBoot会将收集好的@Configuration进行一次过滤进而剔除不满足条件的配置类
// 自动配置的类全名.条件=值
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
查看loadMetadata方法
protected static final String PATH = "META-INF/" + "spring-autoconfigure-metadata.properties";//文件中为需要加载的配置类的类路径 private AutoConfigurationMetadataLoader() { } public static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) { //重载方法 return loadMetadata(classLoader, PATH); } static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) { try { //1.读取spring-boot-autoconfigure.jar包中spring-autoconfigure-metadata.properties的信息生成urls枚举对象 // 获得 PATH 对应的 URL 们 Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path) : ClassLoader.getSystemResources(path); // 遍历 URL 数组,读取到 properties 中 Properties properties = new Properties(); //2.解析urls枚举对象中的信息封装成properties对象并加载 while (urls.hasMoreElements()) { properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement()))); } // 将 properties 转换成 PropertiesAutoConfigurationMetadata 对象 //根据封装好的properties对象生成AutoConfigurationMetadata对象返回 return loadMetadata(properties); } catch (IOException ex) { throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex); } }
深入getCandidateConfigurations方法
getCandidateConfigurations()用来获取默认支持的自动配置类名列表,spring Boot在启动的时候,使用内部工具类SpringFactoriesLoader,查找classpath上所有jar包中的META-INF/spring.factories,找出其中key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的属性定义的工厂类名称,将这些值作为自动配置类导入到容器中,自动配置类就生效了
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// 让SpringFactoryLoader去加载一些组件的名字
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
// 断言,非空
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you " + "are using a custom packaging, make sure that file is correct.");
return configurations;
}
那么@EnableAutoConfiguration就是从classpath中搜索META-INF/spring.factories配置文件,并将其中的org.springframework.boot.autoconfigure.EnableutoConfiguration对应的配置项通过反射实例化对应的标注了@configuration的Java形式的配置类,并加载到ioc容器中
我们以上面说到的spring-boot-starter-web为例,在项目启动的时候,对应的WebMvcAutoConfiguration自动配置类就会生效,这个配置类对SpringMVC运行所需要的环境进行了配置,包括默认前缀,默认后缀,视图解析器等等,而这些配置本质上就是spring的xml配置文件,只不过springboot是在自动配置类的形式进行了预先的默认配置,所以springboot在加入相关依赖启动器以后就不需要任何配置就可以启动程序,当然我们也可以对其默认配置进行修改。
上面的一堆很乱,这里有必要进行一个小结:
Springboot自动配置的步骤是:
1、SpringBoot启动
2、@SpringbootApplication起作用
3、@AutoConfigurationPackage
他通过import将Registrar类导入到容器中,而Registrar类的作用是扫描主配置类同级目录和其子包,并将其组件导入到springboot容器中
4、@Import({AutoConfigurationImportSelector.class})
AutoConfigurationImportSelector的作用是通过selectorimports方法执行过程中,会使用内部工具类SpringFactoriesLoader查找classpath上所有jar包的META-INF/spring.factories进行加载,实现将配置类信息交给
SpringFactory加载器进行一系列的容器创建过程
这个注解的作用就是包扫描和spring中的<context:component-scan base-package=“xxxx” />作用相同,通过@AutoConfigurationPackage注解返回的值确定主程序路径,扫描其同目录及其子包
那么到此为止,@SpringBootApplication 的注解的功能就分析差不多了, 简单来说就是 3 个注解的组合注解:
@SpringBootConfiguration
@Configuration 通过Javacongif的方式将组件添加到容器中
@EnableAutoConfiguration
@AutoConfigurationPackage //自动配置包,与@ComponentScan扫描到的添加到IOC
@Import(AutoConfigurationImportSelector.class) //到METAINF/spring.factories中定义的bean添加到IOC容器中
@ComponentScan //包扫描
SpringBoot Starter机制:
SpringBoot是由众多的Starter构成的(一系列自动化配置的starter插件),SpringBoot之所以流行就是因为Starter
Starter是SpringBoot非常重要的组成部分,可以理解为是一个可插拔的插件,由于Starter的使用,某个功能的开发者,不需要关注各个依赖库的处理,不需要具体的配置信息,由SpringBoot自动通过classpath路径下的类发现需要的bean,并且载入到spring的容器中
例如,你想要使用redis插件,那么只要在pom文件中引入spring-boot-starter-redis就可以
为什么要自定义starter
在开发过程中,经常会遇到一些独立于业务之外的配置模块,如果我们将这些可独立于业务代码之外的模块分装成一个starter,复用的时候,只需要将其在pom文件中引入即可,springboot自动为我们完成自动装配
自定义starter的命名规则
SpringBoot提供的starter以spring-boot-starter-xxx的方式命名,而我们自定义的starter,官方推荐以xxx-spring-boot-starter的方式命名,这样有助于区分哪些是spring官方提供的starter,哪些是自定义的starter
自定义starter
1、新建一个maven jar工程,命名为zdy-spring-boot-starter,并且引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
</dependencies>
2、编写Javabean
@EnableConfigurationProperties(SimpleBean.class)
@ConfigurationProperties(prefix = "simplebean")
public class SimpleBean {
private int id;
private String name;
..................
}
3、编写配置类MyAutoConfiguration
@Configuration
@ConditionalOnClass //@ConditionalOnClass:当类路径classpath下有指定的类的情况下进行
自动配置
public class MyAutoConfiguration {
static {
System.out.println("MyAutoConfiguration init....");
}
@Bean
public SimpleBean simpleBean(){
return new SimpleBean();
}
}
4、resources目录下创建/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
yhy.project.MyAutoConfiguration
使用自定义starter
1、在demo的pom文件中引入自定义starter
<dependency>
<groupId>org.example</groupId>
<artifactId>zdy-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
2、在全局配置文件中设置默认值
simplebean.id=1
simplebean.name=自定义starter
3、编写测试方法
//测试自定义starter
@Autowired
private SimpleBean simpleBean;
@Test
public void zdyStarterTest(){
System.out.println(simpleBean);
}
测试结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。