SpringBoot开篇

2021-12-28 12:36:07 浏览数 (1)

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以后开始支持xmljavaConfig的方式

  • @EnableAutoConfiguration

Spring3.1后引入Enable* , e.g. : EnableScheduling, EnableCache EnableAsync ..

代码语言:javascript复制
// 引入@Import({Registrar.class})
@AutoConfigurationPackage
// 相当于xml: `<import resource ="***"/>`, `AutoConfigurationImportSelector`最终继承于ImportSelector 
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
	// ....
}
实现动态注入的方式:

ImportSelectorImportBeanDefinitionRegistrar

代码语言:javascript复制
// 方式①
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	

AutoConfiguration (自动注入, 简化Bean的注入)

@EnableAutoConfiguration中导入了AutoConfigurationImportSelector 通过ImportSelector不难知道其中必定会有selectImports方法,

代码语言:javascript复制
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会考虑到各种各样的场景,所以需要加载的资源会比较多,而有些时候大部分场景我们压根使用不到,所以可以通过条件注解

使用方式:

ConditionalOnXXX e.g. ConditionalOnClass = "com.xxx.A"META-INF下添加 spring-autoconfigure-metadata.properties

代码语言:javascript复制
  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 />

0 人点赞