初识SpringBoot

1. Spring Boot特性:

  1. 快速创建独立的Spring应用程序。(Spring支持的SpringBoot都支持,也就是说SpringBoot全方位支持IoC,AOP等)
  2. 嵌入式的Tomcat、Jetty、Undertow容器。(web服务器本身就是几个jar包,Spring Boot框架自动嵌入了。)
  3. 需要什么功能时只需要引入对应的starter启动器即可。(启动器可以自动管理这个功能相关的依赖,自动管理依赖版本的控制)
  4. 尽最大努力,最大可能的自动配置Spring应用和第三方库。(例如:如果要进行事务的控制,不用做任何事务相关的配置,只需要在service类上添加@Transactional注解即可。)
  5. 没有代码生成,没有XML配置。(Spring Boot的应用程序在启动后不会动态地创建新的Java类,所有逻辑都是在编译期就已经确定好的)
  6. 提供了生产监控的支持,例如健康检查,度量信息,跟踪信息,审计信息等。也支持集成外部监控系统。

1.1 第一个SpringBoot程序

XML 复制代码
<!--使用SpringBoot框架,首先要继承SpringBoot这个父工程。-->
<!--这里为什么不是直接引入springboot依赖,而是继承SpringBoot父工程的方式??????-->
<!--确保所有Spring Boot项目使用相同版本的依赖-->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.5</version>
</parent>

<!--依赖-->
<dependencies>
    <!--引入web启动器,这样的话自动会将web开发相关的所有依赖全部引入,例如:json、tomcat、springmvc等,包括这些依赖的版本也不需要我们管理,自动管理。-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

1.2 Spring Boot主入口程序

java 复制代码
@SpringBootApplication
public class MyApplication {
	public static void main(String[] args) {
		SpringApplication.run(MyApplication.class, args);
	}
}

1.3 打jar包运行

Spring Boot提供了打包插件,可以将Spring Boot项目打包为可执行 jar 包

Web服务器(Tomcat)也会连同一块打入jar包中。

XML 复制代码
<!--这是一个能够创建可执行jar包的springboot插件。-->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

执行package打包命令,生成可执行jar包:

单独的将这个 jar 包可以拷贝到任何位置运行,通过

java 复制代码
java -jar sb3-01-first-web-1.0-SNAPSHOT.jar

命令来启动 Spring Boot 项目:

Spring Boot框架提供了非常灵活的配置,在可执行jar包的同级目录下新建配置文件:application.properties,并配置以下信息:

java 复制代码
server.port=8888

1.4 SpringBoot的jar包和普通jar包的区别

Spring Boot 打包成的 JAR 文件与传统的 Java 应用程序中的 JAR 文件相比确实有一些显著的区别,主要体现在依赖管理可执行性上。

依赖管理

  1. Spring Boot 的 JAR 包通常包含了应用程序运行所需的所有依赖项,也就是说它是一个"fat jar"(胖 JAR 包),这种打包方式使得应用可以独立运行,而不需要外部的类路径或应用服务器上的其他依赖。

  2. 普通的 JAR 文件一般只包含一个类库的功能,并且需要依赖于特定的类路径来找到其他的类库或者框架,这些依赖项通常在部署环境中已经存在,比如在一个应用服务器中。

可执行性

  1. Spring Boot 的 JAR 文件可以通过直接执行这个 JAR 文件来启动应用程序,也就是说它是一个可执行的 JAR 文件。通过 java -jar your-application.jar 命令就可以直接运行应用程序。

  2. 普通的 JAR 文件通常是不可直接执行的,需要通过指定主类(main class)的方式或者其他方式来启动一个应用程序,例如使用 -cp-classpath 加上类路径以及主类名来执行。

2. Spring Boot启动器

2.1. 启动器实现原理

依赖聚合

每个启动器通常对应一个特定的功能集或者一个完整的应用模块,如 spring-boot-starter-web 就包含了构建 Web 应用所需的所有基本依赖项,如 Spring MVC, Tomcat 嵌入式容器等。

依赖传递

当在项目中引入一个启动器时,它不仅会把自身作为依赖加入到你的项目中,还会把它的所有直接依赖项(transitive dependencies)也加入进来。这意味着你不需要单独声明这些依赖项,它们会自动成为项目的一部分。

版本管理

启动器内部已经指定了所有依赖项的具体版本,这些版本信息存储在一个公共的 BOM(Bill of Materials,物料清单)文件中,通常是 spring-boot-dependencies。当引入启动器时,实际上也间接引用了这个 BOM,从而确保了所有依赖项版本的一致性。

自动配置

许多启动器还提供了自动配置(Auto-configuration),这是一种机制,允许 Spring Boot 根据类路径上的可用组件自动设置应用程序。例如,如果类路径上有 Spring MVC 和嵌入式 Tomcat,则 Spring Boot 会自动配置它们,并准备好一个 web 应用程序。

2.2 Springboot的启动器

2.2.1. 官方提供的启动器

启动器命名特点:spring-boot-starter-*

2.2.2. 非官方的启动器

启动器命名特点:*-spring-boot-starter

3. @SpringBootApplication注解

3.1 @SpringBootConfiguration

java 复制代码
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
@Indexed
public @interface SpringBootConfiguration {
      @AliasFor(
            annotation = Configuration.class
      )
      boolean proxyBeanMethods() default true;
}

注解被@Configuration标注,说明主入口程序是一个配置类。也就是说主入口中的方法可以被@Bean注解标注,@Bean注解的标注的方法会被Spring容器自动调用,并且将该方法的返回对象纳入IoC容器的管理

  1. Bean是Spring管理的对象,可以是任何Java类(如Service、Repository、Controller等)

  2. Spring容器会自动创建这些Bean,并管理它们的生命周期(初始化、销毁)

  3. Bean之间可以通过依赖注入相互调用

SpringBoot主入口类实际上就是一个配置类

这个配置类也可以称为,起源的意思,SpringBoot从这个配置类开始加载项目中所有的bean。

3.2 @EnableAutoConfiguration注解

该注解表示启用自动配置;

Spring Boot 会根据你引入的依赖自动配置好一系列的 Bean,无需手动编写复杂的配置代码。

例如:在SpringBoot项目中进行了如下配置:

java 复制代码
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot
spring.datasource.username=root
spring.datasource.password=1234

在依赖中引入了mybatis依赖/mybatis启动器,那么SpringBoot框架将为你自动化配置以下bean:

  • SqlSessionFactory: MyBatis的核心工厂SqlSessionFactory会被自动配置。这个工厂负责创建SqlSession实例,后者用来执行映射文件中的SQL语句。
  • TransactionManager: DataSourceTransactionManager会被自动配置来管理与数据源相关的事务。

3.3 @ComponentScan注解

启动组件扫描功能,代替spring框架xml文件中这个配置:

XML 复制代码
<context:component-scan base-package="com.powernode.sb305core"/>

@SpringBootApplication注解标注之后,会启动组件扫描功能,扫描的包是主入口程序所在包及子包,因此如果一个bean要纳入IoC容器的管理则必须放到主入口程序所在包及子包下。

4. Spring Boot的单元测试

4.1 不使用单元测试

java 复制代码
public class User {
	private String username;
	private String password;
    
    // 全参构造器
    
    // toString
    // getter
    // setter
}
java 复制代码
public interface UserService {

	User findUser();
}

@Service("userService")
public class UserServiceImpl implements UserService {
	@Override
	public User findUser() {
		return new User("jackson", "123456");
	}
}

主入口程序

手动获取Spring上下文对象ConfigurableApplicationContext,然后调用getBean方法从Spring容器中获取service对象,然后调用方法。

java 复制代码
@SpringBootApplication
public class Springboot305JunitApplication {
	public static void main(String[] args) {
		ConfigurableApplicationContext applicationContext = SpringApplication.run(Springboot305JunitApplication.class, args);
		UserService userService = applicationContext.getBean("userService", UserService.class);
		User user = userService.findUser();
		System.out.println(user);	// User{username='jackson', password='123456'}
		applicationContext.close();
	}
}

4.2 使用单元测试

引入单元测试启动器

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
java 复制代码
// springboot项目中使用单元测试junit,那么单元测试类必须使用这个注解进行标注。
@SpringBootTest
class Springboot305JunitApplicationTests {

	@Autowired
	private UserService userService;

	// 单元测试方法,单元测试方法使用 @Test 注解标注。
	@Test
	void test01() {
		User user = userService.findUser();
		System.out.println(user);
	}
}

4.2.1 @SpringBootTest注解

@SpringBootTest 会创建一个完整的 Spring 应用程序上下文(Application Context),这个上下文包含了应用程序的所有组件和服务。以下是 @SpringBootTest 做的一些主要工作:

创建 ApplicationContext

  • @SpringBootTest 使用 SpringApplicationrun() 方法来启动一个 Spring Boot 应用程序上下文。这意味着它会加载应用程序的主配置类和其他相关的配置类。

加载配置文件

  • 它会查找并加载默认的配置文件,如 application.properties

自动配置

  • 如果应用程序依赖于 Spring Boot 的自动配置特性,@SpringBootTest 会确保这些自动配置生效。这意味着它会根据可用的类和bean来自动配置一些组件,如数据库连接、消息队列等。

注入依赖

  • 使用 @SpringBootTest 创建的应用程序上下文允许你在测试类中使用 @Autowired 注入需要的 bean,就像在一个真实的 Spring Boot 应用程序中一样。

5. 外部化配置

外部化配置是指:将配置信息存储在应用程序代码之外的地方。这样配置信息可以独立于代码进行管理。这样方便了配置的修改,并且修改后不需要重新编译代码,也不需要重新部署项目。

5.1 外部化配置的方式

SpringBoot支持多种外部化配置方式,包括但不限于:

  • properties文件
  • YAML文件
  • 系统环境变量
  • 命令行参数

5.1.1 外部化配置的优势

灵活性:配置文件可以独立于应用程序部署,这使得可以根据运行环境的不同来调整配置,而无需修改代码。

易于维护:配置变更不需要重新构建和部署应用程序,降低了维护成本。

安全性:敏感信息如数据库密码、API密钥等可以存储在外部,并且可以限制谁有权限访问这些配置信息。

共享性:多实例或多服务可以共享相同的配置信息,减少重复配置的工作量。

版本控制:配置文件可以存放在版本控制系统中,便于跟踪历史版本和回滚配置。

5.2 application.properties

Spring Boot 框架在启动时会尝试从以下位置加载 application.properties 配置文件:


1. file:./config/ :首先在Spring Boot 当前工作目录下的 config 文件夹中查找。

注意:如果没有找到 application.properties****会继续找 application.yml**,如果这两个都没有找到,才会进入以下位置查找,以此类推。**

2. file:./ :如果在当前工作目录下config目录中找不到时,再从当前工作目录中查找。

3. classpath:/config/ :如果从工作目录中找不到,会从类路径中找,先从类路径的 /config/ 目录下寻找配置文件。

4. classpath:/ :如果在 /config/ 下没有找到,它会在类路径的根目录下查找。

Spring Boot 会按照这个顺序来加载配置文件,如果在多个位置有相同的属性定义,那么最先检查的位置中的属性值将优先使用。


java 复制代码
// 使用这个也是可以的。因为这样也可以纳入IoC容器的管理
// 并且还有另一个作用,就是表示以下的类是一个配置类。
//@Configuration
// 纳入IoC容器的管理
@Component
public class AppConfig {

    @Value("${myapp.path}")
    private String appPath;

    public void printInfo(){
        System.out.println(appPath);
    }
}

@SpringBootApplication
public class Springboot306PropertiesLocationApplication {

    // args 就是接收命令行参数的。
    public static void main(String[] args) {
        // 打印命令行参数。
        for (String arg : args) {
            System.out.println(arg);    // 输出内容就是上面最后配置的路径
        }

        ConfigurableApplicationContext applicationContext = SpringApplication.run(Springboot306PropertiesLocationApplication.class, args);
        AppConfig appConfig = applicationContext.getBean(AppConfig.class);
        appConfig.printInfo();
        applicationContext.close();
    }
}

如果想要指定其他的配置文件位置或者改变默认的行为,可以通过 --spring.config.location= 后跟路径的方式来指定配置文件的具体位置。

java 复制代码
java -jar sb3-01-first-web-1.0-SNAPSHOT.jar --spring.config.location=file:///E:\a\b\application.properties

Spring Boot 将会首先从 E:\a\b\ 这个路径加载配置文件。

5.3 @Value注解

@Value注解可以将application.properties/application.yml文件中的配置信息注入/绑定到java对象的属性上。

语法格式:@Value("${key}")

java 复制代码
myapp.username=jackson
myapp.email=jackson@123.com

#myapp.age=20
java 复制代码
@Service
public class SystemService {
    @Value("${myapp.username}")
    private String username;

    @Value("${myapp.email}")
    private String email;

    // 注意:当使用 @Value注解的时候,如果这个key不存在,并且没有指定默认值,则报错。
    // key存在,但没有指定默认值,那么赋值为null
    //@Value("${myapp.age}")
    @Value("${myapp.age:50}")
    private Integer age;

    public void printInfo(){
        System.out.println(username);
        System.out.println(email);
        System.out.println(age);
    }
}

5.4 YAML

YAML文件的扩展名可以是 .yaml****或 .yml**。**

5.4.1 常见的数据存储和交换格式

propertiesXMLJSONYAML这几种格式确实是用来存储和交换数据的常见方式,但它们各有特点和适用场景:

Properties

  • 这种格式主要用于Java应用程序中的配置文件。它是键值对的形式,每一行是一个键值对,使用等号或冒号分隔键和值。
  • 特点是简单易懂,但在处理复杂结构的数据时显得力不从心。

XML (eXtensible Markup Language)

  • XML是一种标记语言,用来描述数据的格式。它支持复杂的数据结构,包括嵌套和属性。
  • XML文档具有良好的结构化特性,适合传输和存储结构化的数据。但是,XML文档通常体积较大,解析起来也比较耗资源。

JSON (JavaScript Object Notation)

  • JSON是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。它基于JavaScript的一个子集,支持多种数据类型,如数字、字符串、布尔值、数组和对象。
  • JSON因为简洁和高效而广泛应用于Web应用程序之间进行数据交换。

YAML (YAML Ain't Markup Language)

  • YAML设计的目标之一就是让人类更容易阅读。它支持类似JSON的数据序列化,但提供了更多的灵活性,例如缩进来表示数据结构。
  • YAML非常适合用来编写配置文件,因为它允许以一种自然的方式组织数据,并且可以包含注释和其他人类可读的元素。

5.4.2 YAML的语法规则

YAML的语法规则如下:

  1. 数据结构:YAML支持多种数据类型,包括:
  • 字符串、数字、布尔值
  • 数组、list集合
  • map键值对 等。
  1. YAML使用一个空格来分隔属性名属性值,例如:
  • properties文件中这样的配置:name=jack
  • yaml文件中需要这样配置:name: jack
  1. YAML用换行+空格来表示层级关系。注意不能使用tab,必须是空格,空格数量无要求,大部分建议2个或4个空格。
  1. 同级元素左对齐。
  1. 键必须是唯一的:在一个映射中,键必须是唯一的。

  2. 注释:使用#进行注释。

  3. 大小写敏感

5.4.3 YAML的小细节

第一:普通文本 可以 使用单引号或双引号括起来:

  • 单引号括起来:单引号内所有的内容都被当做普通文本,不转义(例如字符串中有\n,则\n被当做普通的字符串)
  • 双引号括起来:双引号中有 \n 则会被转义为换行符

第二:保留文本格式

  • | 将文本写到这个符号的下层,会自动保留格式。

第三:文档切割

  • --- 这个符号下面的配置可以认为是一个独立的yaml文件。便于庞大文件的阅读。

5.4.4. application.yml

Spring Boot框架同时支持propertiesyaml

在同一个目录下同时存在 application.properties****和 application.yml****时,SpringBoot优先解析 application.properties****文件。

resources/config目录下application.properties名字修改为application2.properties,这样Spring Boot才会解析resources/config/application.yml;

5.5 配置文件合并

application-mysql.properties

java 复制代码
spring.datasource.username=root
spring.datasource.password=123456

application-redis.properties

java 复制代码
spring.data.redis.host=localhost
spring.data.redis.port=6379

application.properties

java 复制代码
spring.config.import=classpath:application-mysql.properties,classpath:application-redis.properties

application.yml

java 复制代码
spring:
  config:
    import:
      - classpath:/config/application-mysql.yml
      - classpath:/config/application-redis.yml

    import: [classpath:/config/application-mysql.yml, classpath:/config/application-redis.yml]

5.6 多环境切换

在Spring Boot中,多环境切换是指在一个应用程序中支持多种运行环境配置的能力。这通常用于区分开发(development)、测试(testing)、预生产(staging)和生产(production)等不同阶段的环境。

这种功能使得开发者能够在不同的环境中使用不同的配置,比如数据库连接信息、服务器端口、环境变量等,而不需要更改代码。这对于维护一个可移植且易于管理的应用程序非常重要。

如果希望该项目使用生产环境的配置,可以这样做:

  • 第一种方式:在application.properties文件中添加这个配置:spring.profiles.active=prod
  • 第二种方式:在命令行参数上添加:--spring.profiles.active=prod

5.7 将配置绑定到bean

5.7.1 绑定简单bean

将配置信息一次性赋值给Bean对象的属性;

XML 复制代码
# 将这里的配置信息一次性的绑定到bean对象的属性上。比 @Value 注解好用,方便。
myapp.a.username=jackson
myapp.a.password=123456
myapp.a.age=20
myapp.a.gender=true

myapp:
  a:
    username: jacksonyml
    password: 123456yml
    age: 30
    gender: false

这样的bean需要使用@Component注解进行标注,纳入IoC容器的管理。

@Component注解负责创建Bean对象;

@ConfigurationProperties(prefix = "app")注解负责给bean对象的属性赋值。

bean的属性需要是非static的属性

java 复制代码
// 纳入IoC容器的管理。
//@Component
// 这个注解标注的类一定会被纳入IoC容器的管理,同时这个类也表示是一个配置类。
@Configuration
// 将配置文件中的属性值一次性的绑定到bean对象的属性上。
@ConfigurationProperties(prefix = "myapp.a")
public class AppConfig {
	// 强调:要实现这种一次性的绑定功能,配置文件中的属性名和bean对象的属性名要一致。
	private String username;
	private String password;
	private Integer age;
	private Boolean gender;

	// 底层在实现给对象属性赋值的时候,调用了setter方法,因此必须保证每个属性提供了setter方法。
	public void setUsername(String username) {
		this.username = username;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public void setGender(Boolean gender) {
		this.gender = gender;
	}

	@Override
	public String toString() {
		return "AppConfig{" +
			  "username='" + username + '\'' +
			  ", password='" + password + '\'' +
			  ", age=" + age +
			  ", gender=" + gender +
			  '}';
	}
}
注入数组,集合,Map类型配置
java 复制代码
# 数组的数据结构
app2.abc.names[0]=jack
app2.abc.names[1]=lucy

app2.abc.addrArray[0].city=BeiJing
app2.abc.addrArray[0].street=ChaoYang
app2.abc.addrArray[1].city=TianJin
app2.abc.addrArray[1].street=NanKai

app2.abc.addrList[0].city=BeiJing_List
app2.abc.addrList[0].street=ChaoYang_List
app2.abc.addrList[1].city=TianJin_List
app2.abc.addrList[1].street=NanKai_List

# add1指的是key,city和street指的是value
app2.abc.addrs.addr1.city=BeiJing_Map
app2.abc.addrs.addr1.street=ChaoYang_Map
app2.abc.addrs.addr2.city=TianJin_Map
app2.abc.addrs.addr2.street=NanKai_Map

app2:
  abc:
    names:
      - tom2
      - smith2
#    names: [jack, lucy]

#    addrArray:
    addr-array:
      # 指定数组中的每一个bean之前必须要有一个  -
      - city: BeiJing2
        street: ChaoYang2
      - city: TianJin2
        street: NanKai2
#    addrList:
    addr-list:
      - city: BeiJing_List2
        street: ChaoYang_List2
      - city: TianJin_List2
        street: NanKai_List2
    addrs:
      addr1:
        city: BeiJing_Map2
        street: ChaoYang_Map2
      addr2:
        city: TianJin_Map2
        street: NanKai_Map2
java 复制代码
@ConfigurationProperties(prefix = "app2.abc")
public class AppBean {
	// 数组:数组中元素是简单类型
	private String[] names;

	// 数组:数组中元素是bean
	private Address[] addrArray;

	// List集合:集合中的元素是bean
	private List<Address> addrList;

	// Map集合:String,Bean
	private Map<String, Address> addrs;

	public void setNames(String[] names) {
		this.names = names;
	}

	public void setAddrArray(Address[] addrArray) {
		this.addrArray = addrArray;
	}

	public void setAddrList(List<Address> addrList) {
		this.addrList = addrList;
	}

	public void setAddrs(Map<String, Address> addrs) {
		this.addrs = addrs;
	}

	@Override
	public String toString() {
		return "AppBean{" +
			  "names=" + Arrays.toString(names) +
			  ", addrArray=" + Arrays.toString(addrArray) +
			  ", addrList=" + addrList +
			  ", addrs=" + addrs +
			  '}';
	}
}

5.7.2 @Configuration注解

被该注解标注的类,该Bean对象的属性对应的就是配置文件中的配置信息;

底层会创建类的代理对象,但是生成代理对象会影响效率,所以需要配置取消代理机制;

java 复制代码
@Configuration(proxyBeanMethods = false)
@ConfigurationProperties(prefix = "app")
public class AppBean {
    private String name;
    private Integer age;
    private String email;
    //setter and getter
}

5.7.3 绑定嵌套bean

java 复制代码
@Component // 第一种
//@Configuration // 第二种
@ConfigurationProperties(prefix = "app.xyz")
public class User {
    private String name;
    private Address addr;

    public void setName(String name) {
        this.name = name;
    }

    public void setAddr(Address addr) {
        this.addr = addr;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", addr=" + addr +
                '}';
    }
}

public class Address {
    private String city;
    private String street;

    public void setCity(String city) {
        this.city = city;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    @Override
    public String toString() {
        return "Address{" +
                "city='" + city + '\'' +
                ", street='" + street + '\'' +
                '}';
    }
}
java 复制代码
app:
  xyz:
    name: lucy_yml
    addr:
      city: TJ
      street: NanKai

5.7.4 @EnableConfigurationProperties与@ConfigurationPropertiesScan

java 复制代码
// 如果项目中有这种老的Spring XML配置文件,使用以下注解可以让XML生效。
// 在SpringBoot主入口类上添加以下注解,让XML配置文件生效。
@ImportResource("classpath:/applicationContext.xml")

@EnableConfigurationProperties({User.class, AppBean.class})
// 将配置信息绑定到bean的第三种方式:在主入口程序上添加以下注解。
// 以下注解的作用是:启用将配置信息绑定到bean,以下代码的意思就是将配置信息绑定到User这个bean上。
//@EnableConfigurationProperties(User.class)

// 将配置信息绑定到bean的第四种方式:在主入口程序上添加以下注解。
//@ConfigurationPropertiesScan(basePackages = "com.hnlg.springboot.bean")
@SpringBootApplication
public class Springboot310ConfigtobeanApplication {

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

}

5.7.5 配置绑定到第三方对象

将配置文件中的信息绑定到某个Bean对象上,如果这个Bean对象没有源码,是第三方库提供的,怎么办?

此时可以单独编写一个方法,在方法上使用以下两个注解进行标注:

  • @Bean
  • @ConfigurationProperties

只知道有这样一个字节码Address.class;怎么把属性配置绑定到指定Bean.

java 复制代码
other:
  abc:
    city: BEIJING
    street: tongzhouqu
java 复制代码
// 指定该类是一个配置类。
@Configuration
public class AppConfig2 {

	// 假设Address是第三方库提供的类。使用以下方式可以完成配置(数据)到bean对象的属性的绑定。
	@Bean // 纳入IoC容器的管理
	@ConfigurationProperties(prefix = "other.abc") // 将配置文件中凡是以 other.abc 开头的配置数据绑定到Address对象的属性上。
	public Address address(){
		return new Address();
	}
}

5.7.6 指定数据源

resources目录下新建a目录,在a目录下新建b目录,b目录中新建group-info.properties文件,进行如下的配置:

java 复制代码
group.name=IT
group.leader=LaoDu
group.count=20
  • @Configuration:指定该类为配置类,纳入Spring容器的管理
  • @ConfigurationProperties(prefix = "group"):将配置文件中的值赋值给Bean对象的属性
  • @PropertySource("classpath:a/b/group-info.properties"):指定额外的配置文件
java 复制代码
@Configuration
@ConfigurationProperties(prefix = "group")
// 用这个注解来指定数据来源。
@PropertySource("classpath:/a/b/group-info.properties")
public class Group {
	private String name;
	private String leader;
	private Integer count;

	@Override
	public String toString() {
		return "Group{" +
			  "name='" + name + '\'' +
			  ", leader='" + leader + '\'' +
			  ", count=" + count +
			  '}';
	}

	public void setName(String name) {
		this.name = name;
	}

	public void setLeader(String leader) {
		this.leader = leader;
	}

	public void setCount(Integer count) {
		this.count = count;
	}
}

5.8 @ImportResource注解

java 复制代码
public class Person {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

resources目录下新建 applicationContext.xml 配置文件:

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="person" class="com.hnlg.springboot.bean.Person">
        <property name="name" value="jackson"/>
        <property name="age" value="20"/>
    </bean>
</beans>

主入口类

java 复制代码
// 如果项目中有这种老的Spring XML配置文件,使用以下注解可以让XML生效。
// 在SpringBoot主入口类上添加以下注解,让XML配置文件生效。
@ImportResource("classpath:/applicationContext.xml")

@SpringBootApplication
public class Springboot310ConfigtobeanApplication {

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

}

5.9 Environment

SpringBoot框架在启动的时候会将系统配置,环境信息全部封装到 Environment****对象中,如果要获取这些环境信息,可以调用 Environment****接口的方法。

在Spring Boot中,Environment接口提供了访问应用程序环境信息的方法,比如活动配置文件、系统环境变量、命令行参数等。Environment接口由Spring框架提供,Spring Boot应用程序通常会使用Spring提供的实现类AbstractEnvironment及其子类来实现具体的环境功能。

Environment对象封装的主要数据包括:

  1. Active Profiles: 当前激活的配置文件列表。Spring Boot允许应用程序定义不同的环境配置文件(如开发环境、测试环境和生产环境),通过激活不同的配置文件来改变应用程序的行为。

  2. System Properties: 系统属性,通常是操作系统级别的属性,比如操作系统名称、Java版本等。

  3. System Environment Variables: 系统环境变量,这些变量通常是由操作系统提供的,可以在启动应用程序时设置特定的值。

  4. Command Line Arguments: 应用程序启动时传递给主方法的命令行参数。

  5. Property Sources : Environment还包含了一个PropertySource列表,这个列表包含了从不同来源加载的所有属性。PropertySource可以来自多种地方,比如配置文件、系统属性、环境变量等。

java 复制代码
app:
  xyz:
    name: lucy_yml
    addr:
      city: TJ
      street: NanKai
java 复制代码
@Component
public class SomeBean {

    @Autowired
    private Environment environment;

    public void doSome(){
        // 直接使用这个环境对象,来获取环境信息,配置信息等。
        String[] activeProfiles = environment.getActiveProfiles();
        for (String activeProfile : activeProfiles) {
            System.out.println(activeProfile);
        }

        // 获取配置信息
        String street = environment.getProperty("app.xyz.addr.street");
        System.out.println(street);
    }
}

6. Spring Boot中开发AOP

当引入aop启动器之后,会引入aop依赖aspectj依赖

  • aop依赖:如果只有这一个依赖,也可以实现AOP编程,这种方式表示使用了纯Spring AOP实现aop编程。
  • aspectj依赖:一个独立的可以完成AOP编程的AOP框架,属于第三方的,不属于Spring框架。

6.1 aop启动器

XML 复制代码
<!--aop启动器-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

6.2 service提供方法

java 复制代码
public interface OrderService {
	/**
	 * 生成订单
	 */
	void generate(Integer id, String name);

	/**
	 * 订单详情
	 */
	void detail(Integer id);
}

@Service("orderService")
public class OrderServiceImpl implements OrderService {

	@Override
	public void generate(Integer id, String name) {
		System.out.println("生成订单");
	}

	@Override
	public void detail(Integer id) {
		System.out.println("订单细节");
	}

}

6.3 编写切面

java 复制代码
@Aspect
@Component
public class LoggingAspect {

	// 记录日志的工具
	private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);

	// 定义切入点,匹配所有以 "service" 结尾的包下的所有方法
	// 切入点表达式
	@Pointcut("execution(* com.hnlg.springboot.service..*(..))")
	// 为这个切入点表达式创建一个可重用的标识符
	// serviceMethods()方法名成为这个切入点的引用名称
	public void serviceMethods() {
	}

	// 在切入点的方法执行前执行此方法
	// 前置通知
	@Before("serviceMethods()")
	public void logBefore(JoinPoint joinPoint) {
		System.out.println("joinPoint:" + joinPoint);
		System.out.println("切点签名:" + joinPoint.getSignature());
		String methodName = joinPoint.getSignature().getName();
		Object[] args = joinPoint.getArgs();
		logger.info("方法 [{}] 携带的 [{}] 被调用了.", methodName, args);
	}
}

测试

java 复制代码
@SpringBootApplication
public class Springboot311AopApplication {

	public static void main(String[] args) {
		ConfigurableApplicationContext applicationContext = SpringApplication.run(Springboot311AopApplication.class, args);
		
		OrderService orderService = applicationContext.getBean(OrderService.class);
		orderService.generate(111, "jackson");
		orderService.detail(111);

		applicationContext.close();
	}
}

7. 持久层框架整合

7.1 Vip

java 复制代码
public class Vip {
	private Long id;
	private String name;
	private String cardNumber; // 数据库字段 card_number
	private String birth;
}

7.2 接口interface

7.2.1 Mapper接口

java 复制代码
// VipMapper通过@MapperScan被MyBatis创建了代理实现
public interface VipMapper {
    /**
     * 保存会员信息
     * @param vip 会员信息
     * @return 1表示保存成功。
     */
    int insert(Vip vip);

    /**
     * 获取所有会员信息
     * @return 会员列表
     */
    List<Vip> selectAll();
}

7.2.2 Service接口

java 复制代码
public interface VipService {

	/**
	 * 保存会员信息
	 * @param vip  会员信息
	 * @return true表示成功,false表示失败
	 */
	boolean save(Vip vip);

	/**
	 * 查看会员列表
	 * @return 会员列表
	 */
	List<Vip> findAll();
}
java 复制代码
@Service("vipService")
public class VipServiceImpl implements VipService {

	@Autowired
	private VipMapper vipMapper;

	@Override
	public boolean save(Vip vip) {
		return vipMapper.insert(vip) == 1;
	}

	@Override
	public List<Vip> findAll() {
		return vipMapper.selectAll();
	}
}

7.3 MyBatis配置

java 复制代码
# 数据源配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot
    username: root
    password: 1234
    type: com.zaxxer.hikari.HikariDataSource

# mybatis相关配置
# 1. 起别名
# 2. 告诉springboot,mapper配置文件的位置
# 3. 启用自动映射:数据库表的列名和javabean的属性名。card_number-cardNumber
mybatis:
  type-aliases-package: com.hnlg.springboot.bean
  mapper-locations: classpath:/mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true

7.4 Mapper的扫描(主入口程序)

java 复制代码
// 通过这个指定去哪里找Mapper接口(配置Mapper的扫描)
// 使用@MapperScan指定Mapper接口扫描路径
// Spring 需要知道哪些 Mapper 需要被管理
@MapperScan(basePackages = {"com.hnlg.springboot.repository"})
@SpringBootApplication
public class Springboot312MybatisApplication {
// Spring Boot 读取配置文件,创建数据源
// MyBatis 根据配置创建 SqlSessionFactory
// 扫描 Mapper 接口并创建实现类
	public static void main(String[] args) {
		// 启动Spring Boot应用,返回应用上下文对象
		// 加载所有配置(包括application.yml/properties)
		// 初始化数据源(根据配置文件中的数据库连接信息)
		// 创建SqlSessionFactory(MyBatis的核心工厂类)
		// 扫描并注册所有Bean(包括@Service, @Repository等)
		// 启动内嵌的Web服务器(如果有Web依赖)
		ConfigurableApplicationContext applicationContext = SpringApplication.run(Springboot312MybatisApplication.class, args);

		// 从应用上下文中获取VipService的Bean实例
		VipService vipService = applicationContext.getBean(VipService.class);

      	/*// 保存会员
      	Vip vip1 = new Vip("jack1", "1234567892", "1999-10-11");
      	vipService.save(vip1);
      	// 保存会员
      	Vip vip2 = new Vip("lucy1", "1234567893", "1999-10-12");
      	vipService.save(vip2);*/
		// 查看会员列表
		vipService.findAll().forEach(System.out::println);

		applicationContext.close();
	}
}

8. Lombok库

Lombok 自动生成构造函数、getter、setter、equals、hashCode、toString 方法等,从而避免了手动编写这些重复性的代码。

@Data

  • 等价于 @ToString, @EqualsAndHashCode, @Getter@Setter, @RequiredArgsConstructor.
  • 用于生成:必要参数的构造方法、getter、setter、toString、equals 和 hashcode 方法。

@Getter / @Setter

  • 分别用于生成所有的 getter 和 setter 方法。
  • 可以作用于整个类,也可以作用于特定的字段。

@NoArgsConstructor

  • 生成一个无参构造方法。

@AllArgsConstructor

  • 生成一个包含所有实例变量的构造器。

@RequiredArgsConstructor

  • 生成包含所有被 final 修饰符修饰的实例变量的构造方法。
  • 如果没有 final****的实例变量,则自动生成无参数构造方法。

@ToString / @EqualsAndHashCode

  • 用于生成 toString 和 equals/hashCode 方法。
  • 这两个注解都有 exclude****属性,通过这个属性可以定制toString、hashCode、equals方法。
java 复制代码
@Data
// 无参数构造方法
@NoArgsConstructor
// 全参数构造方法
@AllArgsConstructor
public class User {
	private Long id;
	private String name;
	private Integer age;
}
java 复制代码
public class Test {
    public static void main(String[] args) {
        // 创建User对象
        User user = new User();
        user.setId(111L);
        user.setName("jackson");
        user.setAge(20);
        System.out.println(user);

        // 创建User对象
        user = new User(120L, "lucy", 30);
        System.out.println(user);
    }
}
java 复制代码
@NoArgsConstructor
@AllArgsConstructor
// 生成必须的构造方法。
// 如果类中有final修饰的实例变量,则生成带有该实例变量的构造方法。
// 如果类中没有final修饰的实例变量,则自动添加无参数构造方法。
//@RequiredArgsConstructor

@Data
public class Person {
    private String name;
    private int age;

    // final修饰的实例变量必须在构造方法中为其初始化。
    //private final String email;

    /*public Person(String email){
        this.email = email;
    }*/
}

8.1 Lombok的其他注解

8.1.1 @Value注解

该注解会给所有属性添加final,给所有属性提供 getter 方法,自动生成toStringhashCodeequals

通过这个注解可以创建不可变对象。

8.1.2 @Builder注解

GoF23种设计模式之一:建造模式

建造模式(Builder Pattern)属于创建型设计模式。GoF23种设计模式之一。

用于解决对象创建时参数过多的问题。它通过将对象的构造过程与其表示分离,使得构造过程可以逐步完成,而不是一次性提供所有参数。

建造模式的主要目的是让对象的创建过程更加清晰、灵活和可控。

简而言之,建造模式用于:

  1. 简化构造过程:通过逐步构造对象,避免构造函数参数过多。
  2. 提高可读性和可维护性:让构造过程更加清晰和有序。
  3. 增强灵活性:允许按需配置对象的不同部分。
java 复制代码
// 建造模式。23种设计模式之一。GoF之一。
public class Person {
	// 一般建造模式的bean属性使用final进行修饰
	private final String name;
	private final int age;

	// 提供一个私有的全参数的构造方法
	private Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	// getter
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}

	@Override
	public String toString() {
		return "Person{" +
			  "name='" + name + '\'' +
			  ", age=" + age +
			  '}';
	}

	// 通过这个公开的静态方法获取建造器对象。
	public static PersonBuilder builder() {
		return new PersonBuilder();
	}
	// 静态的内部类:建造者
	public static class PersonBuilder {
		private String name;
		private int age;
		public PersonBuilder name(String name) {
			this.name = name;
			return this;
		}
		public PersonBuilder age(int age) {
			this.age = age;
			return this;
		}
		public Person build() {
			return new Person(name, age);
		}
	}

    public static void main(String[] args) {
        Person person = Person.builder()
                .name("jackson")
                .age(20)
                .email("jackson@123.com")
                .build();
        System.out.println(person);
    }
}
@Builder注解自动生成建造模式代码

8.1.3 @Singular

@Singular注解是辅助@Builder注解的。

当被建造的对象的属性是一个集合,这个集合属性使用@Singular注解进行标注的话,可以连续调用集合属性对应的方法完成多个元素的添加

如果没有这个注解,则无法连续调用方法完成多个元素的添加。

java 复制代码
@Data
@Builder // 帮助这个类生成符合建造模式的代码。
public class Person {
    private String name;
    private int age;

    @Singular("addPhone")
    private List<String> phones;
}
java 复制代码
public class Test {
    public static void main(String[] args) {
        /*Person person = Person.builder()
                .name("jack")
                .age(30)
                .build();
        System.out.println(person);*/

        /*没有singular注解时的代码*/
        /*List<String> phones = new ArrayList<>();
        phones.add("12345678912");
        phones.add("12345678913");
        phones.add("12345678914");

        Person person = Person.builder()
                .name("jack")
                .age(30)
                .phones(phones)
                .build();
        System.out.println(person);*/
        
        Person person = Person.builder()
                .name("jack")
                .age(30)
                .addPhone("12345678912")
                .addPhone("12345678913")
                .addPhone("12345678914")
                .build();
        System.out.println(person);
    }
}

8.1.4 @Slf4j

1. @Log4j

自动生成一个 org.apache.log4j.Logger 对象。

适用于 Apache Log4j 1.x 版本。

2. @Slf4j

自动生成一个 org.slf4j.Logger 对象。

适用于 SLF4J(Simple Logging Facade for Java),这是一种日志门面,可以与多种实际的日志框架(如 Logback、Log4j 等)集成。

3. @Log4j2

自动生成一个 org.apache.logging.log4j.Logger 对象。

适用于 Apache Log4j 2.x 版本。

java 复制代码
@Slf4j
public class UserService {
    public void saveUser(){
        log.info("保存用户信息....");
    }
}

public class UserServiceTest {
	public static void main(String[] args) {
		UserService userService = new UserService();
		userService.saveUser();
	}
}
XML 复制代码
<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.34</version>
        <scope>provided</scope>
    </dependency>

    <!--Slf4j日志规范-->
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.17</version>
    </dependency>
    <!--slf4j日志实现:logback-->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.5.18</version>
    </dependency>
</dependencies>

9. SSM整合

java 复制代码
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Vip implements Serializable {
    private Long id;

    private String name;

    private String cardNumber;

    private String birth;

    public Vip(String name, String cardNumber, String birth) {
        this.name = name;
        this.cardNumber = cardNumber;
        this.birth = birth;
    }

    private static final long serialVersionUID = 1L;
}
java 复制代码
@RestController
public class VipController {

	@Autowired
	private VipService vipService;

	@GetMapping("/detail")
	public Vip detail(@RequestParam("cn") String cardNumber){
		return vipService.findByCardNumber(cardNumber);
	}

}
java 复制代码
@Repository
public interface VipMapper {
    int deleteByPrimaryKey(Long id);

    int insert(Vip record);

    int insertSelective(Vip record);

    Vip selectByPrimaryKey(Long id);

    int updateByPrimaryKeySelective(Vip record);

    int updateByPrimaryKey(Vip record);

    Vip selectByCardNumber(String cardNumber);
}
java 复制代码
public interface VipService {

	/**
	 * 根据会员的卡号查询会员的信息。
	 * @param cardNumber 会员的卡号
	 * @return 会员信息
	 */
	Vip findByCardNumber(String cardNumber);
}

@Service("vipService")
public class VipServiceImpl implements VipService {

	@Autowired
	private VipMapper vipMapper;

	@Override
	public Vip findByCardNumber(String cardNumber) {
		return vipMapper.selectByCardNumber(cardNumber);
	}
}
java 复制代码
@MapperScan(basePackages = "com.hnlg.ssm.repository")
@SpringBootApplication
public class Springboot314SsmApplication {

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

}
java 复制代码
# 数据源
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot
spring.datasource.username=root
spring.datasource.password=1234

# mybatis配置
mybatis.type-aliases-package=com.hnlg.ssm.bean
mybatis.mapper-locations=classpath:/mapper/*.xml
mybatis.configuration.map-underscore-to-camel-case=true
相关推荐
前行的小黑炭2 小时前
Android :如何提升代码的扩展性,方便复制到其他项目不会粘合太多逻辑,增强你的实战经验。
android·java·kotlin
uzong2 小时前
互联网“黑话”生存实用指南(100)
后端
-凌凌漆-2 小时前
【Qt】【C++】虚析构函数及 virtual ~Base() = default
java·c++·qt
凯尔萨厮2 小时前
Java学习笔记四(继承)
java·笔记·学习
IT_陈寒2 小时前
JavaScript 2024:10个颠覆你认知的ES新特性实战解析
前端·人工智能·后端
Mr_Xuhhh2 小时前
项目-sqlite类的实现
java·jvm·sqlite
孫治AllenSun3 小时前
【Springboot】介绍启动类和启动过程
java·spring boot·后端
绝无仅有3 小时前
面试之MySQL基础和事务实战经验总结与分享
后端·面试·github
程序员爱钓鱼3 小时前
Go语言实战案例 — 工具开发篇:Go 实现二维码生成器
后端·google·go