SpringBoot学习笔记

Posted new一个对象777

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot学习笔记相关的知识,希望对你有一定的参考价值。

SpringBoot学习

核心思想:约定大于配置!!

you can just run

springboot的主要优点:

  • 开箱即用,提供各种配置来简化项目配置
  • 基于spring
  • 内嵌式容器简化web开发
  • 没有冗余代码生成和xml配置的要求

什么是微服务?

微服务是一种风格,原来是all in one(单体架构),完美的阐述了高内聚,低耦合的意思。

即微服务是一种利用分治法的思想,去把一整套非常复杂的业务逻辑给切分成多个简单的业务问题,并采用模块化方法去实现组合的一种架构方法。

它们是相互独立的,这意味着它们可以采用不同的编程语言和数据存储。微服务中几乎不存在集中管理,它使用轻量级的HTTP、REST或Thrift API来进行内部通信。

微服务风格(microservice style)

它用于描述一种设计应用程序的特别方式,作为一套独立可部署的服务。

简而言之,微服务架构风格就像是把一个单独的应用程序开发为一套小服务,每个小服务运行在自己的进程中,并使用轻量级机制通信,通常是 HTTP API。

整体应用程序(Monolithic applications)相当成功,但是越来越多的人感觉到有点不妥,特别是在云中部署时。变更发布周期被绑定了——只是变更应用程序的一小部分,却要求整个重新构建和部署。随着时间的推移,很难再保持一个好的模块化结构,使得一个模块的变更很难不影响到其它模块。扩展就需要整个应用程序的扩展,而不能进行部分扩展。

这导致了微服务架构风格(microservice architectural style)的出现:把应用程序构建为一套服务。事实是,服务可以独立部署和扩展,每个服务提供了一个坚实的模块边界,甚至不同的服务可以用不同的编程语言编写。它们可以被不同的团队管理。

组件化(Componentization )与服务(Services),组件(component)是一个可独立替换和升级的软件单元。

当寻找把一个大的应用程序拆分成小的部分时,通常管理都会集中在技术层面,UI团队、服务端业务逻辑团队和数据库团队。当使用这种标准对团队进行划分时,甚至小小的更变都将导致跨团队项目协作,从而消耗时间和预算审批。一个高效的团队会针对这种情况进行改善,两权相害取其轻。业务逻辑无处不在。实践中,这就是 Conway’s Law 的一个例子。

设计一个系统的任何组织(广义上)都会产生这样一种设计,其结构是组织交流结构的复制。

——Melvyn Conway, 1967

Melvyn Conway 的意思是,像下图所展示的,设计一个系统时,将人员划分为 UI 团队,中间件团队,DBA 团队,那么相应地,软件系统也就会自然地被划分为 UI 界面,中间件系统,数据库。

微服务(microservice )的划分方法不同,它倾向围绕业务功能的组织来分割服务。这些服务实现商业领域的软件,包括用户界面,持久化存储,任何的外部协作。因此,团队是跨职能的(cross-functional),包含开发过程所要求的所有技能:用户体验(user-experience)、数据库(database)和项目管理(project management)。

Amazon 理念是“你构建,你运维(you build, you run it)”.

Guardian网站就是这方面的一个优秀的例子,它初期被设计和构建成一个整体架构,但它已经向微服务的发展了。整体构架仍然是它网站的核心,但是他们使用微服务来增加那些使用整体架构API的新特性。这种方法增加这些临时的特性非常方便,比如运动新闻的特稿。这样站点的一个部分可以使用快速的开发语言迅速整合起来,当它过时后可以一次性移除。我们发现一家金融机构用相似的方法增加新的市场营销活动,数周或者几个月后把它撤销。

微服务的优缺点?

微服务的优缺点:https://www.zhihu.com/question/65502802

用springboot的感想

通过springboot进行开发真的很方便,我们只需要新建一个项目,然后新建一个controller别的我们都不需要管,我们事先已经导入了很多依赖,其中就包括springboot内置的tomcat,我们也不需要配置配置文件和tomcat直接run就可以了,就像是我们一开始说的**”you can just run“!!**,springboot相比ssm简化了很多配置,更重要是的springboot是前后端分离的,我们后端写好的项目,打成jar然后前端就直接可以用了,很方便,便于开发。

运行jar的命令“java -jar 包名”。



自动配置原理

pom.xml

  • spring-boot-dependencies 核心依赖在父工程中
  • 我们在引入一些springboot核心依赖的时候不需要指定版本

启动器:

  • <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
       <scope>test</scope>
    </dependency>
    
  • 如果我们要使用什么功能,我们只需要找到对应的启动器就可以了,即“starter”,因为核心依赖都已经配置好了在父工程里面

  • /**标注这是一个springboot的应用*/
    @SpringBootApplication
    //通过反射启动run方法 使其springboot启动
    SpringApplication.run(HelloworldApplication.class, args);
    
  • @SpringBootConfiguration  springboot配置
        @Configuration spring配置类
        @Component 说明这是spring的组件
    
    @EnableAutoConfiguration  自动配置
        @AutoConfigurationPackage 自动配置包
        	@Import(Registrar.class)  导入自动配置 包注册
        @Import(AutoConfigurationImportSelector.class) 自动导入选择
    
  • META-INF/spring.factories 自动配置的核心文件
    


拆分来看:

  • @SpringBootApplication 标记这是一个springboot的应用

    • @SpringBootConfiguration 核心

      • @Configuration spring的配置类
        • @Component 说明这是一个spring的组件
    • @EnableAutoConfiguration 核心 自动配置

      • @AutoConfigurationPackage 自动配置包

        • @Import(AutoConfigurationPackages.Registrar.class) 自动注册包 自动导包的核心
          • AutoConfigurationPackages.Registrar
      • @Import(AutoConfigurationImportSelector.class) 自动导入选择 选择了什么东西

        • getAutoConfigurationEntry 获取自动配置的实体

        • getCandidateConfigurations 获取候选的配置

          • protected Class<?> getSpringFactoriesLoaderFactoryClass() 
               return EnableAutoConfiguration.class;
            
            
      @ComponentScan(excludeFilters =  @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) )
      

获取候选位置:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) 
		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;
	



这个文件里面放着所有的自动配置的类,当我们用了某个类的时候 springboot的注解会识别出来你用的是哪个类,然后进一步调用这个文件里面响应的类。

  • 核心注解:@ConditionalOnClass 那么多自动配置,为什么有的类没有生效,必须导入start才生效,这是因为springboot很智能,在他的自动配置的文件里的每一个类都有一个注解,通过判断注解里面的内容是否全部都满足,都满足的话才会生效。爆红,所以不满足。

结论

springboot所有的自动配置都是在启动的时候扫描并加载的,扫描的文件就是上面说的spring.factories,所有的配置类都在这里面,但是不一定会生效,先要判断条件是否成立,只要导入了对应的start就有对应的启动器了,有了启动器我们的自动装配就会生效,然后就配置成功了!

自动配置真正实现是从classpath中搜寻所有的META-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。

spring.factories全路径名:E:\\Maven\\repository\\org\\springframework\\boot\\spring-boot-autoconfigure\\2.4.3\\spring-boot-autoconfigure-2.4.3.jar!\\META-INF\\spring.factories

步骤:

  1. springboot启动的时候从类路径下的\\META-INF\\spring.factories获取指定的值
  2. 将这些自动配置的类导入到容器,自动配置类就会生效,帮我们进行自动配置
  3. 以前我们自动配置的东西 现在springboot帮我们自动配置了
  4. 整合javaee中所有的自动配置的包都在包spring-boot-autoconfigure-2.4.3.jar
  5. 他会根据类名把这个组件导入容器,这也是自动装配的最核心的部分
  6. 容器中也会出现非常多的XXXAutoConfiguration的文件,就是这些类给容器导入了某个场景所需要的所有的组件,@Bean–组件
  7. 有了自动配置类,免去了我们手动编写配置文件的工作

面试:谈谈你对springboot的理解

  • 自动装配
  • 主类是怎么运行的,做了哪些事情
    • 推断应用的类型是普通的项目还是web项目
    • 查找并加载所有的可用初始化容器,设置到initalizers属性中
    • 找出所有的应用程序监听器,设置到listeners属性中
    • 推断并设置main方法的定义类,找到并运行主类

yaml语法学习

yaml是properties的代替者,功能比properties强大,可以存取数组,对象,字符串,相比propertis更快捷,所以springboot推荐使用yaml,空格很重要。

配置文件

SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的

  • application.properties

    • 语法结构 :key=value
  • application.yml

    • 语法结构 :key:空格 value

**配置文件的作用 :**修改SpringBoot自动配置的默认值,因为SpringBoot在底层都给我们自动配置好了;

比如我们可以在配置文件中修改Tomcat 默认启动的端口号!测试一下!

server.port=8081

YAML是 “YAML Ain’t a Markup Language” (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:“Yet Another Markup Language”(仍是一种标记语言)

这种语言以数据作为中心,而不是以标记语言为重点!

以前的配置文件,大多数都是使用xml来配置;比如一个简单的端口配置,我们来对比下yaml和xml

传统xml配置:

<server>
    <port>8081<port>
</server>

yaml配置:

server:
  prot: 8080

yaml基础语法

说明:语法要求严格!

1、空格不能省略

2、以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。

3、属性和值的大小写都是十分敏感的。

字面量:普通的值 [ 数字,布尔值,字符串 ]

字面量直接写在后面就可以 , 字符串默认不用加上双引号或者单引号;

注意:

  • “ ” 双引号,不会转义字符串里面的特殊字符 , 特殊字符会作为本身想表示的意思;

    比如 :name: “kuang \\n shen” 输出 :kuang 换行 shen

  • ‘’ 单引号,会转义特殊字符 , 特殊字符最终会变成和普通字符一样输出

    比如 :name: ‘kuang \\n shen’ 输出 :kuang \\n shen

#key: value
name: qin

# 数组
arrays: [one,two,three]

arrays:
  - one
  - two
  - three

# 对象
student:
  name: wang
  age: nv

注入配置文件

yaml文件更强大的地方在于,他可以给我们的实体类直接注入匹配值!

首先来一个实例,用狗狗测试一下

@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
public class Dog 
    @Value("旺财") //通过注解注入内容
    private String name;
    @Value("3")
    private Integer age;

然后我们测试一下

@SpringBootTest
class HelloworldApplicationTests 

   @Autowired
   private Dog dog;

   @Test
   void contextLoads() 
      System.out.println(dog);
   

但是当我们编写一个很复杂类的时候这样做显然很麻烦,所以我们用yaml注入的方式来解决。

首先我们需要一个实体类就叫person吧

/*
@ConfigurationProperties作用:
将配置文件中配置的每一个属性的值,映射到这个组件中;
告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定
参数 prefix = “person” : 将配置文件中的person下面的所有属性一一对应
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Component
@ConfigurationProperties(prefix = "person")
@PropertySource(value = "classpath:kuang.properties")
public class Person 
    private String name;
    private Integer age;
    private Boolean happy;
    private Date birthday;
    private Map<String,Object> maps;
    private List<Object> list;
    private Dog dog;

然后我们需要一个application.yaml文件

person:
  name: wanghu
  age: 13
  happy: true
  birthday: 2020/05/20
  maps: k1: v1,k2: v2
  list:
    - code
    - music
    - gril
  dog:
    name: kuanghua
    age: 3

我们在person实体类中已经实现了匹配了,直接运行就可以了。

我们还可以加载指定的配置文件:@PropertySource(value = "classpath:kuang.properties")

@PropertySource :加载指定的配置文件;

@configurationProperties:默认从全局配置文件中获取值;

配置文件占位符

配置文件还可以编写占位符生成随机数

person:
    name: qinjiang$random.uuid # 随机uuid
    age: $random.int  # 随机int
    happy: false
    birth: 2000/01/01
    maps: k1: v1,k2: v2
    lists:
      - code
      - girl
      - music
    dog:
      name: $person.hello:other_旺财
      age: 1

我们上面采用的yaml方法都是最简单的方式,开发中最常用的;也是springboot所推荐的!那我们来唠唠其他的实现方式,道理都是相同的;写还是那样写;配置文件除了yml还有我们之前常用的properties , 我们没有讲,我们来唠唠!

【注意】properties配置文件在写中文的时候,会有乱码 , 我们需要去IDEA中设置编码格式为UTF-8;

settings–>FileEncodings 中配置;

测试步骤:

1、新建一个实体类User

@Component //注册bean
public class User 
    private String name;
    private int age;
    private String sex;

2、编辑配置文件 user.properties

user1.name=kuangshen
user1.age=18
user1.sex=男

3、我们在User类上使用@Value来进行注入!

@Component //注册bean
@PropertySource(value = "classpath:user.properties")
public class User 
    //直接使用@value
    @Value("$user.name") //从配置文件中取值
    private String name;
    @Value("#9*2")  // #SPEL Spring表达式
    private int age;
    @Value("男")  // 字面量
    private String sex;

4、Springboot测试

@SpringBootTest
class DemoApplicationTests 

    @Autowired
    User user;

    @Test
    public void contextLoads() 
        System.out.println(user);
    

@Value这个使用起来并不友好!我们需要为每个属性单独注解赋值,比较麻烦;我们来看个功能对比图

1、@ConfigurationProperties只需要写一次即可 , @Value则需要每个字段都添加

2、松散绑定:这个什么意思呢? 比如我的yml中写的last-name,这个和lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定。可以测试一下

3、JSR303数据校验 , 这个就是我们可以在字段是增加一层过滤器验证 , 可以保证数据的合法性

4、复杂类型封装,yml中可以封装对象 , 使用value就不支持

结论:

配置yml和配置properties都可以获取到值 , 强烈推荐 yml;

如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下 @value;

如果说,我们专门编写了一个JavaBean来和配置文件进行一一映射,就直接@configurationProperties,不要犹豫!

JSR303数据校验

Springboot中可以用@validated来校验数据,如果数据异常则会统一抛出异常,方便异常中心统一处理。我们这里来写个注解让我们的name只能支持Email格式;

@Component //注册bean
@ConfigurationProperties(prefix = "person")
@Validated  //数据校验
public class Person 

    @Email(message="邮箱格式错误") //name必须是邮箱格式
    private String name;

常见参数

@NotNull(message="名字不能为空")
private String userName;
@Max(value=120,message="年龄最大不能查过120")
private int age;
@Email(message="邮箱格式错误")
private String email;

空检查
@Null       验证对象是否为null
@NotNull    验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank   检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty   检查约束元素是否为NULL或者是EMPTY.
    
Booelan检查
@AssertTrue     验证 Boolean 对象是否为 true  
@AssertFalse    验证 Boolean 对象是否为 false  
    
长度检查
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  
@Length(min=, max=) string is between min and max included.

日期检查
@Past       验证 DateCalendar 对象是否在当前时间之前  
@Future     验证 DateCalendar 对象是否在当前时间之后  
@Pattern    验证 String 对象是否符合正则表达式的规则

.......等等
除此以外,我们还可以自定义一些数据校验规则

多环境切换

springboot支持多环境随时切换,为什么要切换环境呢?因为你有可能是开发环境,也有可能是测试环境,所以我们要随时切换。

我们在主配置文件编写的时候,文件名可以是 application-profile.properties/yml , 用来指定多个环境版本;

例如:

application-test.properties 代表测试环境配置

application-dev.properties 代表开发环境配置

但是Springboot并不会直接启动这些配置文件,它默认使用application.properties主配置文件

我们需要通过一个配置来选择需要激活的环境:

#比如在配置文件中指定使用dev环境,我们可以通过设置不同的端口号进行测试;
#我们启动SpringBoot,就可以看到已经切换到dev下的配置了;
spring.profiles.active=dev
server :
  port: 8081
spring:
  profiles:
    active: dev
---
server:
  port: 8082
spring:
  profiles: dev

---
server:
  port: 8083
spring:
  profiles: test

注意:如果yml和properties同时都配置了端口,并且没有激活其他环境 , 默认会使用properties配置文件的!

配置文件加载位置

外部加载配置文件的方式十分多,我们选择最常用的即可,在开发的资源文件中进行配置!

官方外部配置文件说明参考文档


springboot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件:

优先级1:项目路径下的config文件夹配置文件
优先级2:项目路径下配置文件
优先级3:资源路径下的config文件夹配置文件
优先级4:资源路径下配置文件

优先级由高到底,高优先级的配置会覆盖低优先级的配置;

再谈自动装配

配置文件application.yaml到底能写什么?该怎么写呢?

我们以**HttpEncodingAutoConfiguration(Http编码自动配置)**为例解释自动配置原理;

//表示这是一个配置类 也可以给容器添加组件
@Configuration(proxyBeanMethods = false)

//启动指定类的ConfigurationProperties功能;
	//进入这个ServerProperties查看,将配置文件中对应的值和ServerProperties绑定起来;
	//并把ServerProperties加入到ioc容器中
@EnableConfigurationProperties(ServerProperties.class)

//Spring底层@Conditional注解
	//根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
	//这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)

//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnClass(CharacterEncodingFilter.class)

//判断配置文件中是否存在某个配置:server.servlet.encoding.enabled;
	//如果不存在,判断也是成立的
	//即使我们配置文件中不配置 server.servlet.encoding.enabled=true,也是默认生效的;
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)

public class HttpEncodingAutoConfiguration 
	//他已经和SpringBoot的配置文件映射了
	private final Encoding properties;
	//只有一个有参构造器的情况下,参数的值就会从容器中拿
	public HttpEncodingAutoConfiguration(ServerProperties properties) 
		this.properties = properties.getServlet().getEncoding();
	

	//给容器中添加一个组件,这个组件的某些值需要从properties中获取
	@Bean
	@ConditionalOnMissingBean  //判断容器没有这个组件?
	public CharacterEncodingFilter characterEncodingFilter() 
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
		return filter;
	

一句话总结:我们在application.yaml中配置的内容对应的就是我们的spring.factories文件中定义好的类的属性和方法,且都是通过注解@ConfigurationProperties(prefix = "spring.data.mongodb")来实现的,我们在配置文件中配置的内容最后就是由此注解调用。



根据当前不同的条件判断,决定这个配置类是否生效!

  • 一但这个配置类生效;这个配置类就会给容器中添加各种组件;
  • 这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
  • 所有在配置文件中能配置的属性都是在xxxxProperties类中封装着
  • 配置文件能配置什么就可以参照某个功能对应的这个属性类
  • 在配置文件中如何绑定就取决于那个类的注解是如何写的 @ConfigurationProperties(prefix = "spring.redis")

这就是自动装配的原理!

在这里贴一个我认为的比较容易理解的过程:

  • SpringBoot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值
  • 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;
  • 以前我们需要自己配置的东西 , 自动配置类都帮我们解决了
  • 整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;
  • 它将所有需要导入的组件以全类名的方式返回 , 这些组件就会被添加到容器中 ;
  • 它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration), 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 ;
  • 有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作;

精髓

1、SpringBoot启动会加载大量的自动配置类

2、我们看我们需要的功能有没有在SpringBoot默认写好的自动配置类当中;

3、我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)

4、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;

**xxxxAutoConfigurartion:自动配置类;**给容器中添加组件

xxxxProperties:封装配置文件中相关属性;

了解:@Conditional

了解完自动装配的原理后,我们来关注一个细节问题,自动配置类必须在一定的条件下才能生效;

@Conditional派生注解(Spring注解版原生的@Conditional作用)

作用:必须是@

以上是关于SpringBoot学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

业界良心!Github热榜第七的SpringBoot笔记(阿里内测版)终于开源

博弈论

SpringBoot学习笔记——Thymeleaf

SpringBoot学习笔记——Web开发探究

SpringBoot学习笔记——自动配置原理

Springboot学习笔记