动力节点王鹤SpringBoot3笔记—— 第二章 掌控SpringBoot基础篇

发布时间 2023-04-07 16:06:54作者: 企微的biu二球

第二章 掌控SpringBoot基础篇

2.1 Spring Boot ?

Spring Boot 是目前流行的微服务框架 倡导 约定优先于配置” 其设 目的是 用来简化新 Spring 应用的初始化搭建以及开发过程。 Spring Boot 提供了很多核心的功 能,比如自动化配置 starter(启动器) 简化 Maven 配置、内嵌 Servlet 容器、应用监控等功能, 让我们可以快速构建企业级应用程序。

特性: 

  • 创建独立的Spring 应用程序。
  • 嵌入式 Tomcat、 Jetty、 Undertow容器(jar)
  • 提供的 starters 简化构建配置(简化依赖管理和版本控制)
  • 尽可能自动配置 spring应用和第三方库
  • 提供生产指标,例如指标、健壮检查和外部化配置
  • 没有代码生成,无需XML配置

 SpringBoot同时提供 “开箱即用”,“约定优于配置”的特性。

开箱即用:Spring Boot应用无需从0开始,使用脚手架创建项目。基础配置已经完成。 集成大部分第三方库对象,无需配置就能使用。例如在Spring Boot项目中使用MyBatis。可以直接使用XXXMapper对象, 调用方法执行sql语句。

约定优于配置:Spring Boot定义了常用类,包的位置和结构,默认的设置。代码不需要做调整,项目能够按照预期运行。比如启动类在根包的路径下,使用了@SpringBooApplication注解。 创建了默认的测试类。controller, service,dao应该放在根包的子包中。application为默认的配置文件。

脚手架(spring提供的一个web应用,帮助开发人员,创建springboot项目)     SpringBoot3 最小jdk17, 支持17-20.    

Spring Boot理念“约定优于配置”,也可称为按约定编程。

2.1.1 与Spring关系 

Spring框架:
Spring Boot创建的是Spring应用,对于这点非常重要。也就是使用Spring框架创建的应用程序。这里的Spring是指 Spring Framework。 我们常说的Spring,一般指Spring家族,包括Spring Boot、Spring Framework 、Spring Data ,Spring Security,Spring Batch , Spring Shell, Spring for Apache Kafka ....。

2004年3月,Spring Framework1.0发布。2006年10 月,Spring Framework2.0发布。 2006年后开始,国内项目渐渐的开始应用Spring框架,2009年12月,Spring3.0发布。这时国内已经比较注重Spring使用了。项目多数转移到Spring框架了。 我是在2007开始知道渐渐了解Spring框架。 那个时候用Struts或者就是jsp+servlet+jdbc比较多。当时研发项目也没什么烦恼, 就一,两个技术可以用。没什么可选择的。现在的框架,技术太多了。2017 年 09 月,Spring Framework5.0 发布。 2022年11月Spring Framework6.0发布。

第一个版本1.0的blog:https://spring.io/blog/2004/03/24/spring-framework-1-0-final-released Spring的核心功能:IoC , AOP , 事务管理,JDBC,SpringMVC , Spring WebFlux,集成第三方框架MyBatis,Hibernate, Kafka , 消息队列...

Spring包含SpringMVC, SpringMVC作为web开发的强有力框架,是Spring中的一个模块。

首先明确一点,Spring Boot和Spring Framework都是创建的Spring应用程序。Spring Boot 是一个新的框架,看做是Spring 框架的扩展,它消除了设置 Spring 应用程序所需的 XML配置,为更快,更高效的创建Spring应用提供了基础平台。Spring Boot能够快速创建基于Spring ,SpringMVC的普通应用以及Web项目。

SpringBoot是包含了Spring 、SpringMVC的高级的框架,提供了自动功能,短平快。能够更快的创建Spring应用。消除了Spring的XML配置文件,提供了开发效率,消除Spring应用的臃肿。避免了大量的样板代码。

所以学习Spring Boot的建议:了解Spring + SpringMVC核心功能,基本应用是最好的,能够更快的上手Spring Boot。一般的Spring Boot课程中默认听众是会Spring ,SpringMVC的。 

 Spring Boot在现在Java开发人员必须掌握的框架。Spring Boot是掌握Spring Cloud的基础。

 

2.1.2 与SpringCloud关系

微服务:微服务(Microservices Architecture)是一种架构和组织方法,微服务是指单个小型的但有业务功能的服务,每个服务都有自己的处理和轻量通讯机制,可以部署在单个或多个服务器上。

将一个大型应用的功能,依据业务功能类型,抽象出相对独立的功能,称为服务。每个服务就上一个应用程序,有自己的业务功能,通过轻量级的通信机制与其他服务通信(通常是基于HTTP的RESTful API),协调其他服务完成业务请求的处理。 这样的服务是独立的,与其他服务是隔离的, 可以独立部署,运行。与其他服务解耦合。 

微服务看做是模块化的应用,将一个大型应用,分成多个独立的服务,通过http或rpc将多个部分联系起来。请求沿着一定的请求路径,完成服务处理。 

项目规模大,服务多。要构建大型的分布式应用,保证应用的稳定,高效,不间断的提供服务。Spring Cloud是对分布式项目提供了,有力的支持。

Spring Cloud是一系列框架的有序的组合,为开发人员提供了快速构建分布式系统中常用工具(例如,配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态)。开发人员使用使用Spring Cloud这套框架和工具的集合可以快速建立实现分布式服务。这些框架需要使用Spring Boot作为基础开发平台。

学好了Spring Boot,才能使用这些框架,创建良好的Spring Cloud应用。分布式应用。

访问:https://spring.io/projects/spring-cloud

Spring Cloud包含的这些框架和工具各负其职,例如Spring Cloud Config提供配置中心的能力,给分布式多个服务提供动态的数据配置,像数据库的url,用户名和密码等,第三方接口数据等。 Spring Cloud Gateway网关,提供服务统一入口,鉴权,路由等功能。

学习Spring Colud难度比较大,里面框架,工具比较多。有多个框架需要学习,在把框架组合起来又是一个难度。 

2.1.3  最新的Spring Boot3 新特性

2022年11月 24日。Spring Boot3发布,里程碑的重大发布。这个版本应该是未来5年的使用主力。Spring官网支持Spring Boot3.0.X版本到2025年。

SpringBoot3中的重大变化:

  1. JDK最小Java 17,能够支持17-20.
  2. Spring Boot 3.0 已将所有底层依赖项从 Java EE 迁移到了 Jakarta EE API。原来javax开头的包名,修改为jakarta。 例如 jakarta.servlet.http.HttpServlet 原来javax.servlet.http.HttpServlet
  3. 支持 GraalVM 原生镜像。将Java应用编译为本机代码,提供显著的内存和启动性能改进。
  4. 对第三方库,更新了版本支持。
  5. 自动配置文件的修改。
  6. 提供新的声明式Http服务, 在接口方法上声明@HttpExchange获取http远程访问的能力。代替OpenFeign
  7. Spring HTTP 客户端提供基于 Micrometer 的可观察性. 跟踪服务,记录服务运行状态等
  8. AOT(预先编译) 支持Ahead Of Time,指运行前编译
  9. Servlet6.0规范
  10. 支持 Jackson 2.14。
  11. Spring MVC :默认情况下使用的 PathPatternParser。删除过时的文件和 FreeMarker 、JSP 支持。

伴随着Spring Boot3的发布,还有 Spring Framework 6.0的发布(2022-11-16),先于Spring Boot发布。 

2.1.4  如何学好框架

学习框架:我的建议无基础,先看视频,照着例子做;有基础后自己做点程序。 之后看图书,最好是官网文档。不建议开始就看源代码。

有基础的:看图书,最好是官网文档,边看文档边实践。可以看框架此处功能的源代码。不建议通篇看源代码(在巨人身上是看不到全貌的)。提高部分看开源项目的代码,最后写项目。 

2.2 脚手架 

脚手架是一种用在建筑领域的辅助工具,是为了保证建筑施工过程顺利进行而搭设的工作平台。软件工程中的脚手架是用来快速搭建一个小的可用的应用程序的骨架,将开发过程中要用到的工具、环境都配置好,同时生成必要的模板代码。

脚手架辅助创建程序的工具,Spring Initializr是创建Spring Boot项目的脚手架。快速建立 Spring Boot项目的最好方式。他是一个web应用,能够在浏览器中使用。IDEA中继承了此工具,用来快速创建Spring Boot项目以及Spring Cloud项目。

Spring Initializr脚手架的web地址: https://start.spring.io/

阿里云脚手架:https://start.aliyun.com/

2.2.1 使用脚手架创建项目

  1. 浏览器访问脚手架,创建项目
  2. IDEA中使用脚手架。

创建Spring Boot工程 Lesssion02-Project , Lession03-Project。

脚手架使用需要联网。

2.2.2 IDEA创建SpringBoot项目 

2.3 代码结构 

2.3.1.1 单一模块

一个工程一个模块的完整功实现。创建学生模块功能的Spring Boot项目Lession04-single com.example.模块名称

               
+----Application.java 启动类              
+----controller  控制器包                      
            ---StudentController.java                      
    ---ScoreController.java                
+----service 业务层包                      
          --inter 业务层接口                      
---impl 接口实现包                
+----repository 持久层包                

+----model 模型包                      
               ---entity 实体类包                      
                         ---dto   数据传输包                          
---vo    视图数据包 

 2.3.1.2 多个模块

一个Spring Boot中多个模块。在根包下创建每个模块的子包, 子包中可以按“单一模块”包结构定义。 创建包含多个功能的单体Spring Boot。 Lession05-crm (activity, sale, customer等模块) 

2.3.1.3 包和主类 

我们通常建议您将主应用程序类定位在其他类之上的根包中。@SpringBootApplication注释通常放在主类上,它隐式地为某些项定义了一个基本的“搜索包”。例如,如果您正在编写一个JPA应用程序,则使用@SpringBootApplication注释类的包来搜索@Entity项。使用根包还允许组件扫描只应用于您的项目。

Spring Boot支持基于java的配置。尽管可以将SpringApplication与XML源一起使用,但我们通常建议您的主源是单个@Configuration类。通常,定义主方法的类可以作为主@Configuration类。

2.3.1.4 spring-boot-starter-parent

pom.xml中的<parent>指定spring-boot-starter-parent作为坐标,表示继承Spring Boot提供的父项目。从 spring-boot-starter-parent 继承以获得合理的默认值和完整的依赖树,以便快速建立一个Spring Boot项目。 父项目提供以下功能:

  • JDK的基准版本,比如<java.version>17</java.version>
  • 源码使用UTF-8 格式编码
  • 公共依赖的版本
  • 自动化的资源过滤:默认把src/main/resources目录下的文件进行资源打包
  • maven的占位符为‘@’
  • 对多个Maven插件做了默认配置,如maven-compile-plugin,maven-jar-plugin 

快速创建Spring Boot项目,同时能够使用父项目带来的便利性,可以采用如下两种方式:

  1. 在项目中,继承spring-boot-starter-parent
  2. pom.xml不继承,单独加入spring-boot-dependencies依赖。<dependencyManagement>  
    <dependencies>    
    <dependency>      
    <groupId>org.springframework.boot</groupId>      
    <artifactId>spring-boot-dependencies</artifactId>      
    <version>3.0.1</version>     
    <type>pom</type>      
    <scope>import</scope>    
    </dependency>  
    </dependencies>
    </dependencyManagement>

     

     

2.4  运行Spring Boot项目方式

  • 开发工具,例如IDEA 执行main方法 
  • Maven插件 mvn spring-boot:run 
  • java -jar jar文件的路径

Spring Boot项目可以打包为jar或者war文件。 因为Spring Boot内嵌了web服务器,例如tomcat。能够以jar方式运行web应用。 无需安装tomcat程序。

创建Lession06-package演示打包jar应用。

更进一步
普通的jar与Spring Boot jar区别:

项目 spring boot jar 普通的jar
目录 BOOT-INF : 应用的class和依赖jar META-INF: 清单 org.springframework.boot.loader: spring-boot-loader模块类

META-INF:清单

class的文件夹:jar中的所有类

BOOT-INF

class:应用的类

lib:应用的依赖

没有BOOT-INF
spring-boot-loader 执行jar的spring boot类 没有此部分
可执行

命令:powershell中 tree  /F

Spring Boot jar文件的结构:

 

2.5  starter

starter是一组依赖描述,应用中包含starter,可以获取spring相关技术的一站式的依赖和版本。不必复制、粘粘代码。通过starter能够快速启动并运行项目。

starter包含:

  • 依赖坐标、版本
  • 传递依赖的坐标、版本
  • 配置类,配置项 

pom.xml 加入mybatis依赖 

<dependency>   
<groupId>org.mybatis.spring.boot</groupId>   
<artifactId>mybatis-spring-boot-starter</artifactId>   
<version>2.2.2</version> 
</dependency> 

查看Maven依赖

 

 MyBatis 配置类

2.6  外部化配置

外部化配置 应用程序 =  代码  + 数据(数据库,文件,url)

应用程序的配置文件:Spring Boot允许在代码之外,提供应用程序运行的数据,以便在不同的环境中使用相同的应用程序代码。避免硬编码,提供系统的灵活性。可使用各种外部配置源,包括Java属性文件、YAML文件、环境变量和命令行参数。

项目中经常使用properties与yaml文件,其次是命令行参数。2.6.1

2.6.1  配置文件基础 

2.6.1.1 配置文件格式 

配置文件有两种格式分别:properies 和yaml(yml)。properties是Java中的常用的一种配置文件格式,key=value。key是唯一的,文件扩展名为properties。

yaml(YAML Ain't Markup Language)也看做是yml,是一种做配置文件的数据格式,基本的语法 key:[空格]值。yml文件文件扩展名是yaml或yml(常用)。 

yml格式特点:

YAML基本语法规则:

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进只可以使用空格,不允许使用Tab键
  • 缩进的空格数目不重要,相同层级的元素左侧对齐即可
  • #字符表示注释,只支持单行注释。#放在注释行的第一个字符

YAML缩进必须使用空格,而且区分大小写,建议编写YAML文件只用小写和空格。

YAML支持三种数据结构

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 标量(scalars):单个的、不可再分的值,例如数字、字符串、true|false等

需要掌握数据结构完整内容,可从https://yaml.org/type/index.html获取详细介绍。 

2.6.1.2  application文件 

Spring Boot同时支持properties和yml格式的配置文件。 配置文件名称默认是application。我们可以使用application.properties , application.yml。

读取配置文件的key值,注入到Bean的属性可用@Value,@Value一次注入一个key的值。将多个key值绑定到Bean的多个属性要用到@ConfigurationProperties注解。在代码中访问属性除了注解,Spring提供了外部化配置的抽象对象Environment。Environment包含了几乎所有外部配置文件,环境变量,命令行参数等的所有key和value。需要使用Environment的注入此对象,调用它的getProperty(String key)方法即可。

创建新的Spring Boot练习配置文件的使用,项目名称 Lession07-config。Maven作为构建工具,JDK19。包名com.bjpowernode.config 。不需要其他依赖。

Spring Boot建议使用一种格式的配置文件,如果properties和yml都存在。properties文件优先。推荐使用yml文件。 application配置文件的名称和位置都可以修改。约定名称为application,位置为resources目录。 

2.6.1.3  application.properties

需求:在application.properties 提供应用程序的name,owner, port基本信息,程序读取这些数据,显示给用户。

step1:在application.properties自定义配置项目 

 

step2: 创建SomeService类读取app.name, app.owner,app.port配置key。

注解@Value读取单个值,语法${key:默认值}

step3:单元测试

在test目录下创建测试类,注入SomeService对象,调用它的printValue()方法。 

@SpringBootTest
public class TestPropConfig {

  @Autowired
  private SomeService service;

@Test  
void test01() {
    service.printValue();  
}

}

 

输出:

result = Lession07;changming;8001

2.6.1.4 application.yml 

需求:同上面一样的需求,配置为application.yml。

首先修改application.properties名称为其他的任意名称,比如1appliction.properties。在创建application.yml文件。 SomeService类不用修改。

step1:编写application.yml 

step2: 运行单元测试TestPropConfig#test01()

输出:result = Lession07-yml;bjpowernode;8002

Spring Boot对yml文件的内容进行扁平化处理。将yml中的内容看做和properties中的格式一样处理。也就是 app: name 看做是app.name。 所以在程序中Spring Boot认为properties和yml是一样的。

2.6.1.5 Environment 

Environment是外部化的抽象,是多种数据来源的集合。从中可以读取application配置文件,环境变量,系统属性。使用方式在Bean中注入Environment。调用它的getProperty(key)方法。

step1:创建ReadConfig类,注入Environment

@Service

public class ReadConfig {  
@Autowired  
private Environment environment;

  public void print(){
    String name = environment.getProperty("app.name");
//key是否存在    
if (environment.containsProperty("app.owner")) {
      System.out.println("有app.owner配置项");
    }
//读取key转为需要的类型,提供默认值8000    
Integer port = environment.getProperty("app.port", Integer.class, 8000);

String result = String.format("读取的name:%s,端口port:%d", name,port);
    System.out.println("result = " + result);
  }
}

 

step2:单元测试

@SpringBootTest
class ReadConfigTest {

  @Autowired
 private ReadConfig readConfig;

  @Test  void test01() {
    readConfig.print();
  }
}

 

输出:

有app.owner配置项

result = 读取的name:Lession07-yml,端口port:8002

2.6.1.6 组织多文件 

大型集成的第三方框架,中间件比较多。每个框架的配置细节相对复杂。如果都将配置集中到一个application文件,导致文件内容多,不易于阅读。我们将每个框架独立一个配置文件,最后将多个文件集中到application。我们使用导入文件的功能。 

需求:项目集成redis,数据库mysql。 将redis,数据库单独放到独立的配置文件。

step1:在resources创建自定义conf目录,在conf中创建redis.yml, db.yml 

step2: application.yml导入多个配置

 step3:创建类,读取两个文件的配置项

@Service
public class MultiConfigService {

  @Value("${spring.redis.host}")
  private String redisHost;

  @Value("${spring.datasource.url}")
  private String dbUrl;

  public void printConfig(){
    System.out.println("redis的ip:"+redisHost+",数据库url;"+dbUrl);
 }
}

step4: 单元测试

@SpringBootTest
class MultiConfigServiceTest {

  @Autowired
  private MultiConfigService multiConfigService;

  @Test
  void test01() {
    multiConfigService.printConfig();
 }
}

 

输出:

redis的ip:192.168.1.10,数据库url;jdbc:mysql://192.168.1.21/db?serverTime=Asia/Shanghai

2.6.1.7 多环境配置

软件开发中经常提到环境这个概念,与日常生活中的环境概念一样。环境影响居住体验。影响软件运行的也叫做环境,例如应用中访问数据库的ip,用户名和密码,Redis的端口,配置文件的路径,windows,linux系统,tomcat服务器等等。围绕着程序周围的都是环境。环境影响软件的运行。

Spring Profiles表示环境,Profiles有助于隔离应用程序配置,并使它们仅在某些环境中可用。常说开发环境,测试环境,生产环境等等。一个环境就是一组相关的配置数据, 支撑我们的应用在这些配置下运行。应用启动时指定适合的环境。开发环境下每个开发人员使用自己的数据库ip,用户,redis端口。 同一个程序现在要测试了。需要把数据库ip,redis的改变为测试服务器上的信息。 此时使用多环境能够方便解决这个问题。

Spring Boot规定环境文件的名称 application-{profile}.properties(yml)。其中profile为自定义的环境名称,推荐使用dev表示开发 ,test表示测试。 prod表示生产,feature表示特性。总是profile名称是自定义的。Spring Boot会加载application 以及 application-{profile}两类文件,不是只单独加载application-{profile}。

需求: 项目使用多环境配置,准备一个开发环境,一个测试环境.。

step1:在resources创建环境配置文件 

 step2: 激活环境

spring:
  config:
#导入多个配置文件,“,”作为分隔符
    import: conf/db.yml,conf/redis.yml
#激活环境,与on-profile名称保持一致
  profiles:
    active: dev

spring.profiles.active: 环境名称

step3: 创建读取配置项的类

@Service
public class MulitEnvService {
  @Value("${myapp.memo}")
  private String memo;
  public void print(){
    System.out.println(memo);
  }
}

step4: 单元测试

@SpringBootTest
class MulitEnvServiceTest {
  @Autowired
  private MulitEnvService service;
  @Test
  void test01() {
    service.print();
  }
}

2.6.2 绑定Bean

@Value绑定单个属性,当属性较多时不方便,Spring Boot提供了另一种属性的方法。将多个配置项绑定到Bean的属性,提供强类型的Bean。Bean能够访问到配置数据。

基本原则:标准的Java Bean有无参数构造方法,包含属性的访问器。配合@ConfigurationProperties 注解一起使用。Bean的static属性不支持。

Spring Boot自动配置中大量使用了绑定Bean与@ConfigurationProperties,提供对框架的定制参数。项目中要使用的数据如果是可变的,推荐在yml或properties中提供。项目代码具有较大的灵活性。

@ConfigurationProperties能够配置多个简单类型属性,同时支持Map,List,数组类型。对属性还能验证基本格式。 

2.6.2.1 简单的属性绑定 

使用之前的app开头的配置内容。yml,properties配置格式都可以,绑定Bean的效果都一样。 step1:查看application配置。目前使用的是application.yml 

 step2: 创建Bean,定义name,owner, port属性

@Configuration(proxyBeanMethods = false)
@ConfigurationProperties(prefix = "app")
public class AppBean {
  private String name;
  private String owner;
  private Integer port;
 // set | get方法 ,toString()
}

@ConfigurationProperties声明在类上,表示绑定属性到此类。prefix表示前缀,是配置文件中多个key的公共前缀。这些key以“.”作为分隔符。例如app.name, app: name等。 prefix=”app”, 将文件中app开始的key都找到,调用与key相同名称的setXXX方法。如果有给属性赋值成功。没有的忽略。

step3:单元测试 

@SpringBootTest
class AppBeanTest {

  @Autowired
  private AppBean appBean;


  @Test
  void test01() {
    System.out.println("appBean.toString() = " + appBean.toString());
  }
}

输出: AppBean的所有属性值。

2.6.2.2 嵌套Bean 

需求:Bean中包含其他Bean作为属性,将配置文件中的配置项绑定到Bean以及引用类型的成员。Bean的定义无特殊要求。

在原来的app的配置中,增加security相关配置,包含username,password两个属性。 

step1: 定义两个Bean 

public class Security {
  private String username;
 private String password;
  // set | get方法 ,toString()
}

@Configuration(proxyBeanMethods = false)
@ConfigurationProperties(prefix = "app")
public class NestAppBean {
  private String name;
  private String owner;
  private Integer port;
  private Security security;
  // set | get方法 ,toString()
}

 

step2: 定义application.yml

#yml配置文件  key: 值
app:
  name: Lession07-yml
  owner: bjpowernode
  port: 8002
#  app.security.username=root
#  app.security.password=123456
  security:
    username: root
    password: 123456

 

step3: 单元测试

@SpringBootTest
class NestAppBeanTest {

  @Autowired
  private NestAppBean appBean;

  @Test
  void test01() {
    System.out.println("appBean.toString() = " + appBean.toString());
 }
}

 

输出:

appBean.toString() = NestAppBean{name='Lession07-yml', owner='bjpowernode', port=8002, security=Security{username='root', password='123456'}}

2.6.2.3 扫描注解 

@ConfigurationProperties注解起作用,还需要@EnableConfigurationProperties或@ConfigurationPropertiesScan。 这个注解是专门寻找@ConfigurationProperties注解的,将他的对象注入到Spring容器。在启动类上使用扫描注解。 

/**
 * 扫描@ConfigurationProperties所在的包名
 * 不扫描@Component
 */
@ConfigurationPropertiesScan({"com.bjpowernode.config.pk4"})
@SpringBootApplication
public class Lession07ConfigApplication {

  public static void main(String[] args) {
    SpringApplication.run(Lession07ConfigApplication.class, args);
  }
}

 

2.6.2.4 处理第三方库对象

上面的例子都是在源代码中使用@ConfigurationProperties注解,如果某个类需要在配置文件中提供数据,但是没有源代码。此时@ConfigurationProperties结合@Bean一起在方法上面使用。

比如现在有一个Security类是第三方库中的类,现在要提供它的username,password属性值。

step1: application.yml添加新的配置 

security:
  username: common
  password: abc123

step2:创建配置类

@Configuration
public class ApplicationConfig {

  @ConfigurationProperties(prefix = "security")
  @Bean
  public Security createSecurity(){
    return new Security();
  }
}

step3: 单元测试

@SpringBootTest
public class BeanMethodTest {

  @Autowired
  private Security security;
  @Test
  void test01() {
    System.out.println("security = " + security);
  }
}

输出:

security = Security{username='common', password='abc123'}

2.6.2.5 集合Map,List以及Array 

Map,List以及Array都能提供配置数据, 下面通过一个示例配置集合属性。 

step1:创建保存数据的Bean 

public class User {
  private String name;
  private String sex;
  private Integer age;
  //set | get ,toString
}

public class MyServer {
  private String title;
  private String ip;
  //set | get ,toString
}

@ConfigurationProperties
public class CollectionConfig {

  private List<MyServer> servers;
  private Map<String,User> users;
  private String [] names;
  //set | get ,toString
}

step2: 修改application.yml, 配置数据

#集合以及数组
#List<String> names
names:
  - lisi
  - zhangsan

#List<MyServer> servers
servers:
  - title: 华北服务器
    ip: 202.12.39.1
  - title: 西南服务器
    ip: 106.90.23.229  - title: 南方服务器
    ip: 100.21.56.23

#Map<String,User> users
users:
  user1:
      name: 张三
      sex: 男
      age: 22
  user2:
      name: 李四
      sex: 男
      age: 26

“-”表示集合一个成员,因为成员是对象,需要属性名称指定属性值。List与数组前面加入“-”表示一个成员。 Map直接指定key和value,无需“-”。

step3: 启动类,增加扫描包

/**
 * 扫描@ConfigurationProperties所在的包名
 * 不扫描@Component
 */
@ConfigurationPropertiesScan({"其他包","com.bjpowernode.config.pk5"})
@SpringBootApplication
public class Lession07ConfigApplication {

  public static void main(String[] args) {
    SpringApplication.run(Lession07ConfigApplication.class, args);
  }
}

输出Bean的属性值

str = CollectionConfig{servers=[MyServer{title='华北服务器', ip='202.12.39.1'}, MyServer{title='西南服务器',
ip='106.90.23.229'}, MyServer{title='南方服务器', ip='100.21.56.23'}],
users={user1=User{name='张三', sex='男', age=22}, user2=User{name='李四', sex='男', age=26}}, names=[lisi, zhangsan]}

2.6.2.6 指定数据源文件 

application做配置是经常使用的,除以以外我们能够指定某个文件作为数据来源。@PropertySource是注解,用以加载指定的properties文件。也可以是XML文件(无需了解)。@PropertySource与@Configuration一同使用,其他注解还有@Value,@ConfigurationProperties。

需求:一个组织信息,在单独的properties文件提供组织的名称,管理者和成员数量

step1: 创建Group类,表示组织 

@Configuration
@ConfigurationProperties(prefix = "group")
@PropertySource(value = "classpath:/group-info.properties")
public class Group {


  private String name;
 private String leader;
  private Integer members;
  //set | get ,toString
}

step2:在resources目录下的任意位置创建properties文件,我们创建group-info.properties,放在resources根目录。

 step3: 单元测试

@SpringBootTest
class GroupTest {

  @Autowired
  private Group group;
  @Test
  void test01() {
    System.out.println("group = " + group.toString());
  }
}

控制台输出:

group = Group{name='IT学习专栏', leader='无名', members=500}

总结:

@ConfigurationProperties绑定Bean对于使用配置文件的数据是十分方便,灵活的。也支持对数据的校验,校验是JSR303规范中的注解。
Bean定义结合Lombok会更加方便。如果团队都接受Lombok。 推荐使用。

2.7 创建对象三种方式 

  • 将对象注入到Sprin容器,可以通过如下方式:
  • 传统的XML配置文件
  • Java Config技术, @Configuration与@Bean
  • 创建对象的注解,@Controller ,@Service , @Repository ,@Component

Spring Boot不建议使用xml文件的方式, 自动配置已经解决了大部分xml中的工作了。如果需要xml提供bean的声明,@ImportResource加载xml注册Bean。

需求:XML配置Spring容器。声明Bean

step1: 创建Person类,对象由容器管理 

public class Person {
  private String name;
  private Integer age;
  //set | get ,toString
}

step2:resources目录下创建XML配置文件

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
  <bean id="myPerson" class="com.bjpowernode.config.pk7.Person">
    <property name="name" value="李四" />
    <property name="age" value="20" />
  </bean>
</beans>

step3: 启动类,从容器中获取Person对象

@ImportResource(locations = "classpath:/applicationContext.xml")
@ConfigurationPropertiesScan({"com.bjpowernode.config.pk4",
"com.bjpowernode.config.pk5"})
@SpringBootApplicationpublic class Lession07ConfigApplication {

  public static void main(String[] args) {
    ApplicationContext ctx = 
SpringApplication.run(Lession07ConfigApplication.class, args);
    Person myPerson = (Person) ctx.getBean("myPerson");
    System.out.println("myPerson = " + myPerson);
  }
}

@ImportResource(locations = "classpath:/applicationContext.xml"), 加载类路径下的applicationContext.xml文件。location或者value属性都能指定文件路径。2.8

2.8  AOP 

AOP(Aspect Oriented Programming):面向切面编程,保持原有代码不变,能够给原有的业务逻辑增加二维的功能。AOP增加的功能是开发人员自己编写的,底层是动态代理实现功能的增强。对于扩展功能十分有利。Spring的事务功能就是在AOP基础上实现的, 业务方法在执行前【开启事务】,在执行业务方法,最后【提交或回滚失败】。

  • Aspect:表示切面,开发自己编写功能增强代码的地方,这些代码会通过动态代理加入到原有的业务方法中。 @Aspect注解表示当前类是切面类。 切面类是一个普通类。
  • Joinpoint:表示连接点,连接切面和目标对象。或是一个方法名称,一个包名,类名。在这个特定的位置执行切面中的功能代码。
  • 切入点(Pointcut):其实就是筛选出的连接点。一个类中的所有方法都可以是JoinPoint, 具体的那个方法要增加功能,这个方法就是Pointcut。
  • Advice:翻译是通知,也叫做增强。表示增强的功能执行时间。 Java代码执行的单位是方法,方法是业务逻辑代码,在方法之前增加新的功能,还是方法之后增加功能。 表示在方法前,后等的就是通知。 

主要包括5个注解:@Before,@After,@AfterReturning,@AfterThrowing,@Around。注解来自aspectj框架。

@Before:在切点方法之前执行。

@After:在切点方法之后执行

@AfterReturning:切点方法返回后执行

@AfterThrowing:切点方法抛异常执行

@Around:属于环绕增强,能控制切点执行前,执行后。功能最强的注解。 

  • Target Object: 目标对象。 在A类的print()方法执行前, 输出方法的执行时间。 也就是给A这个对象增加了“输出执行时间的功能”。 

AOP技术主要的实现一个是Spring框架,Spring Boot当然支持AOP;另一个是功能全面的AspectJ框架。Spring Boot执行AspectJ框架。使用@Before,@After,@AfterReturning,@AfterThrowing,@Around注解的方式就来自AspectJ框架的功能。 

需求:项目中的业务方法都需要在日志中输出方法调用的时间以及参数明细。业务方法多,使用AOP最合适。 新建Spring Boot项目Lession08-aop , Maven管理项目,无需选择依赖。包名称。com.bjpowernode.aop 

step1:Maven添加aop依赖 

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

包含了aop和aspectj依赖

step2:创建业务类SomeService在aop的service子包 

package com.bjpowernode.aop.service;

public interface SomeService {

  void query(Integer id);
  void save(String name, String code);
}

实现类:
import org.springframework.stereotype.Service;
@Service
public class SomeServiceImpl implements SomeService {

  @Override
  public void query(Integer id) {
    System.out.println("SomeService业务方法query执行了");
  }

  @Override
  public void save(String name, String code) {
    System.out.println("SomeService业务方法save执行了");
  }
}

 

step3:创建切面类

@Component
@Aspect
public class LogAspect {


  //前置通知 execution是切入点表达式
  @Before("execution(* com.bjpowernode.aop.service..*.*(..))")
  public void sysLog(JoinPoint jp){
    StringJoiner log = new StringJoiner("|", "{", "}");
    DateTimeFormatter formatter = DateTimeFormatter
.ofPattern("yyyy-MM-dd HH:mm:ss");

    log.add(formatter.format(LocalDateTime.now()));
    //目标方法参数列表
    Object[] args = jp.getArgs();
    for (Object arg : args) {
      log.add( arg == null ? "-" : arg.toString());
    }
    System.out.println("方法执行日志:" + log.toString());

  }
}

@Aspect说明当前类是切面类,包含了功能增强的代码和通知注解。

@Component 将切面类对象注入到spring容器。spring会根据目标类和切面类创建代理对象,织入切面功能。

step4:单元测试 

@SpringBootTest
public class AspectTest {

  @Autowired
  private SomeService service;


  @Test
  void testLog() {
    service.query(1001);
    service.save("订单业务", "B01256");
  }
}

 

输出执行结果:

方法执行日志:{2023-01-22 13:52:43|1001}

SomeService业务方法query执行了

方法执行日志:{2023-01-22 13:52:43|订单业务|B01256}

SomeService业务方法save执行了

结论:在业务方法前,先执行了切面类中sysLog()的功能增强代码。