SpringBoot
前言:
SpringBoot是一个服务于Spring框架的框架,用来简化对于bean的获取, 快速构建一个web服务, 它的基础依然是Spring。
在SpringBoot还未出来以前使用的最多的架构体系可能是SpringMVC Mybatis or Spring Struts2 Hibernate ,甚至是最早期的JSP Servlet. 以上框架搭建起来过于繁琐,而且需要进行大量的配置,每次搭建一个web项目可能会遇到各种各样的问题,所以一般公司都会生成相应的脚手架,以便于能够提升开发效率。
随着互联网的发展,最开始的单体架构可能难以支撑大流量的场景, 那么架构演进的一个必然的结果是需要对于系统架构拆分,由最开始的单体架构拆分成N个业务系统,那么服务与服务之间的调用就需要提供相应的通信方式与协议等,例如HTTP 或者RPC(dubbo的底层通信方式是通过Netty实现,即暴露服务的端口供远程调用)的方式进行调用。
1.什么是SpringBoot
1.1. Spring基础,IOC 控制反转
包含以下两部分:
- DI 依赖注入
- DL 依赖查找
1.2. SpringBoot实现快速开发的基础来源于 约定优于配置
什么是约定优于配置:例如A和B两个人刚认识,为了升华一下双方的友谊,于是约定某天某一时刻在某地喝茶, 那么第二次可能只需要说老地方见就知道该去哪里,那么到了后来可能只需要一个眼神交流即可。
1.2.1 约定优于配置的体现
maven的目录结构(默认以jar的形式打包,默认会有resources目录)
springboot-starter-xxx的方式, e.g. springboot-starter(内置了tomcat, resource/{template,static} )
1.2.2. 为什么说SpringBoot里没有新技术
1.2.2.1. 自动装配
@SpringBootApplication 是由以下三个注解组成的
@SpringBootConfiguration
由
@Configuration
注解标注。 --> 本质上还是由@Component
标注。 Spring最开始采用XML的方式 e.g. :<bean id="xxx" class ="com.xxxx.A"/>
Spring3开始支持
javaConfig
的方式(始于JDK5), Spring3以后开始支持xml
和javaConfig
的方式
@EnableAutoConfiguration
代码语言:javascript复制Spring3.1后引入Enable* , e.g. :
EnableScheduling
,EnableCache
EnableAsync
..
// 引入@Import({Registrar.class})
@AutoConfigurationPackage
// 相当于xml: `<import resource ="***"/>`, `AutoConfigurationImportSelector`最终继承于ImportSelector
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
// ....
}
实现动态注入的方式:
代码语言:javascript复制
ImportSelector
、ImportBeanDefinitionRegistrar
// 方式①
public class CachedRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(DiskPersistent.class);
String beanName = StringUtils.uncapitalize(DiskPersistent.class.getName());
// beanName相當於<bean name ="beanName"></bean>
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
}
// 方式②
public class ProviderSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
return new String[]{CachedService.class.getName(),HealthManagerService.class.getName()};
}
}
// 控制台打印,可以获取到如下内容,这只是个简单的演示,可以在这里做一些其他的事情(加深自己的印象)
//HealthManagerService@57a4d5ee
//DiskPersistent@5af5def9
代码语言:javascript复制
AutoConfiguration
(自动注入, 简化Bean的注入)
@EnableAutoConfiguration中导入了AutoConfigurationImportSelector
通过ImportSelector不难知道其中必定会有selectImports
方法,
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return NO_IMPORTS;
} else {
// 这里在加载META-INF/spring-autoconfigure-metadata.properties文件
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
//看这里
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
}
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
// 看这里
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
// 去重
configurations = this.removeDuplicates(configurations);
//过滤注解属性exlude={}
Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.filter(configurations, autoConfigurationMetadata);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
// `SpringFactoriesLoader` (`spring SPI机制`),这里会加载所有的 `META-INF/spring.factories`文件里的数据
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
spi(service provider interface)
是什么? --> 提供扩展点供开发人员使用 e.g.java ,spring,dubbo
都提供了相应的spi在META-INF下创建:
spring.factories
添加自己的类即可加载: e.g.:org.springframework.boot.autoconfigure.EnableAutoConfiguration= xxx.xxx.A
如下是spring自带的的:
代码语言:javascript复制 # `AutoConfiguration`
`org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.cloud.client.CommonsClientAutoConfiguration,
org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClientAutoConfiguration,`
// 略...
条件注册:**
NOTE:
因为SpringBoot会考虑到各种各样的场景,所以需要加载的资源会比较多,而有些时候大部分场景我们压根使用不到,所以可以通过条件注解
使用方式:
代码语言:javascript复制
ConditionalOnXXX
e.g.ConditionalOnClass = "com.xxx.A"
在META-INF
下添加spring-autoconfigure-metadata.properties
com.a.AConfig.ConditionalOnClass = com.xxx.A
// spring中的
org.springframework.boot.autoconfigure.influx.InfluxDbAutoConfiguration.ConditionalOnClass=org.influxdb.InfluxDB
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
@ComponentScan
扫描
@Component, @Service, @Controller, @Configuration
等(注解具有派生性,@Component及派生注解都将被扫描) 然后被IOC托管。 等价于 : Spring XML的方式<context-componet-scan />