POM文件中为何要以继承的方式引入SpringBoot?
继承父工程的优势
- 依赖管理:在父工程中定义依赖的版本,子模块直接引用而不必指定版本号
- 插件管理:在父工程中配置插件,子模块直接使用
- 属性设置:在父工程中定义一些通用属性,如项目编码、java版本等
- 统一配置:可以统一多个子模块的构建配置,确保一致性。
继承了父工程,那么引入依赖的时候不需要指定版本号,因为在父工程中,各种依赖的版本号已经预设好了。
SpringBoot核心注解
@SpringBootApplication
被此标注表示该类是SpringBoot项目的入口类。
此注解被以下三个注解标注,说明@SpringBootApplication同时有以下三个注解的功能
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
@SpringBootConfiguration
@SpringBootConfiguration被@Configuration标注说明项目的主入口类同时是一个配置类,因此在主入口类中使用@Bean注解方法的话,该方法返回值对象会被纳入Ioc容器管理。
@EnableAutoConfiguration
启用自动配置,SpringBoot默认情况下启用自动配置。
自动配置有什么用?
自动配置只要启动,SpringBoot就会去类路径中查找Class。根据类路径中有某些类来自动管理Bean,不需要程序员手动配置。
比如SpringBoot检测到SqlSessionFactory,或者在application.properties中配置了数据源,SpringBoot会认为项目中含有MyBatis框架,会将MyBatis相关的Bean初始化,然后放到Ioc容器中管理起来。
@ComponentScan
@ComponentScan负责组件扫描。会扫描此包及此包下所有子包或子包的子包等的路径。
外部化配置
外部化配置是指将配置信息存储 在应用程序代码之外的地方。这样配置信息独立于 代码进行管理。方便配置修改。修改后不需要重新编译,也不需要重新部署。
springboot默认先找外部化配置
Application.properites
-
Application.properites配置文件是SpringBoot默认的额配置文件
-
Application.properites不是必须的,SpringBoot提供了默认配置,如果需要修改默认配置,就在Application.properites中进行配置。
-
Application.properites可以放在类路径中,也可以放在项目之外,因此成为外部化配置
SpringBoot在启动时会从以下位置按顺序加载Application.properites:
- file:./config/: 首先在SpringBoot当前工作目录下的config文件夹中查找(如果没找到Application.properites,会继续查找Application.yml,2个都没找到,才会进入下一个位置查找,以此类推)
- file:./: 这里找不到会继续查找下一个位置
- classpath:/config/:
- classpath:/
如果在多个位置有相同属性的定义,那么最先检查的位置中的属性值先使用。
如果要指定配置文件位置,可以通过--spring.config.location=进行指定,比如:
cmd
java -jar xxxx.jar --spring.config.location=file:///E:\a\b\application.properties
注意:以上的--spring.config.location=file:///E:\a\b\application.properties属于命令行参数,会被传递到main方法的(String[] args)参数上。
读取配置
java
// 读取配置文件中myapp.path的值,
// 如果这个key不存在,并且没有指定默认值,那么会报错
// ${myapp.path:50}指定myapp.path的默认值是50
@Value("${myapp.path:50}")
private String appPath;
YAML语法规则
数据结构
-
支持多种数据结构,包括:字符串、数字、布尔值、数组、List集合、Map键值对等
-
yaml使用一个空格来分割属性名和属性值,比如:
yaml
name: jack
- yaml使用换行+空格表示层级关系,注意不能使用tab 必须是空格,空格数量无要求,建议2个或4个,比如:
yaml
myapp:
name: mall
- 同级元素左侧对其
- 大小写敏感
- 使用# 进行注释
- 在一个映射中,键必须唯一
- 普通文本可以使用单引号,也可以使用双引号,也可以什么都不用**(单引号中的\n表示普通文本,双引号中的\n表示换行)**
- 保留文本原格式使用 | 比如:
yaml
username: |
aaaa
bbb
ccc
- 文档切割: --- 这个符号下面的配置认为是一个独立的yaml文件,便于大文件的阅读。
配置文件合并
properties
#properties文件合并
# 对于数组来说,使用逗号进行分隔开
spring.config.import=classpath:/application-mysql.properties,classpath:/application-redis.properties
yml文件合并的第一种写法
yaml
spring:
config:
import: [classpath:/application-mysql.yml,classpath:/application-redis.yml]
yml文件合并的第二种写法
yaml
spring:
config:
import:
- classpath:/application-mysql.yml
- classpath:/application-redis.yml
多环境切换
开发环境配置文件:application-dev.properties
测试环境配置文件:application-test.properties
预生产环境配置文件:application-preprod.properties
生产环境配置文件:application-prod.properties
如果启用生产环境配置,可以有以下两种操作方式:
- 在application.properties添加配置:spring.profiles.active=prod
- 在命令行参数上添加: --spring.profiles.active=prod
将配置绑定到简单Bean
java
package com.ali.bindtobean.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
// 纳入Ioc容器
@Component
// 将配置文件一次性绑定到Bean对象上
@ConfigurationProperties(prefix = "myapp")
public class AppConfig {
// 要实现一次性绑定,配置文件中的属性名 必须和Bean对象的属性名要一致
// 底层在给对象属性赋值时,调用了setter方法,因此每个属性必须有setter方法
private String name;
private Integer age;
private String password;
private Boolean gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Boolean getGender() {
return gender;
}
public void setGender(Boolean gender) {
this.gender = gender;
}
@Override
public String toString(){
return "AppConfig [name=" + name + ", age=" + age + ", gender=" + gender + "]";
}
}
properties
spring.application.name=bindtobean
myapp.name=jack
myapp.age=12
myapp.password=123
myapp.gender=true
绑定嵌套Bean
在一个Bean的属性中,有一个其他Bean类型。这样就是嵌套Bean。
java
package com.ali.bindtobean.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "app.xyz")
public class User {
private String name;
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [name=" + name + ", address=" + address.toString() + "]";
}
}
java
package com.ali.bindtobean.bean;
public class Address {
private String city;
private String street;
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
@Override
public String toString() {
return "Address [city=" + city + ", street=" + street + "]";
}
}
properties
app.xyz.name=lucy
app.xyz.address.city=xj
app.xyz.address.street=dayang
其他方式绑定Bean
java
// 在主入口程序添加以下注解,启用将配置信息绑定到User这个Bean
@EnableConfigurationProperties({User.class, Address.class})
另一种方式:
java
// 在主入口程序添加以下注解,扫面指定包。将配置信息绑定到这个包下的类
@ConfigurationPropertiesScan(basePackages = "com.ali.bindtobean.bean")
复杂的属性结构绑定Bean
绑定数组、集合、Map到Bean
properties
app2.abc.names[0]=jack
app2.abc.names[1]=lucy
app2.abc.names[2]=tom
app2.abc.addresses[0].city=bj
app2.abc.addresses[0].street=chaoyang
app2.abc.addresses[1].city=tj
app2.abc.addresses[1].street=nankai
app2.abc.addressList[0].city=bj_list
app2.abc.addressList[0].street=chaoyang_list
app2.abc.addressList[1].city=tj_list
app2.abc.addressList[1].street=nankai_list
# addr1 和addr2 都是key
app2.abc.addressMap.addr1.city=bj_map
app2.abc.addressMap.addr1.street=chaoyang_map
app2.abc.addressMap.addr2.city=tj_map
app2.abc.addressMap.addr2.street=nankai_map
yaml文件配置方式如下:
yaml
app2:
abc:
names:
- tom
- smith
addresses:
- city: beijing
street: chaoyang
- city: tianjin
street: nankai
# addressList 可以写成 address-list
addressList:
- city: beijing
street: chaoyang
- city: tianjin
street: nankai
addressMap:
addr1:
city: beijing
street: chaoyang
addr2:
city: tianjin
street: nankai
java
package com.ali.bindtobean.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Map;
@ConfigurationProperties(prefix = "app2.abc")
public class AppBean {
// 数组中元素是简单类型
private String[] names;
// 数组中元素是Bean
private Address[] addresses;
//List集合。List中元素是Bean
private List<Address> addressList;
//Map集合: String,Bean
private Map<String,Address> addressMap;
public void setNames(String[] names) {
this.names = names;
}
public void setAddresses(Address[] addresses) {
this.addresses = addresses;
}
public void setAddressList(List<Address> addressList) {
this.addressList = addressList;
}
public void setAddressMap(Map<String, Address> addressMap) {
this.addressMap = addressMap;
}
@Override
public String toString() {
return "";
}
}
将配置绑定到第三方对象
yaml
other:
abc:
city: beijing
street: daxing
java
package com.ali.bindtobean.config;
import com.ali.bindtobean.bean.Address;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig2 {
// address 是第三方类,使用以下方式完成配置到属性的绑定
@Bean
@ConfigurationProperties(prefix = "other.abc")
public Address address() {
return new Address();
}
}
指定配置数据来源
java
@Component
@ConfigurationProperties(prefix = "app2.abc")
// 指定配置数据来自/a/b/group-info.properties路径的配置文件
@PropertySource("classpath:/a/b/group-info.properties")
public class AppBean {
...
}
@ImportResource注解
当SpringBoot项目中出现ApplicationContext.xml文件。并且文件中配置了Bean。要把这个Bean注入到容器中。
java
package com.ali.bindtobean.bean;
public class Person {
private String name;
private int 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;
}
@Override
public String toString() {
return super.toString();
}
}
配置文件如下:
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.ali.bindtobean.bean.Person">
<property name="name" value="jack"/>
<property name="age" value="20"/>
</bean>
</beans>
java
// 在主入口程序添加以下注解让applocationContext.xml文件生效
@ImportResource("classpath:/applocationContext.xml")
Environment
spring提供的一个接口。SpringBoot启动的时候会把环境、系统信息封装到Environment对象中,需要获取这些信息,可使用Environment接口的方法。
Environment对象主要包括
- 当前激活的配置文件 active-profiles
- 系统属性,如系统名字 、java版本
- 环境变量
- 应用程序启动时传给主方法的命令行参数
java
@Autowired
private Environment environment;
public void doSomething() {
// 获取当前激活的配置文件
String[] activeProfiles = environment.getActiveProfiles();
for (String activeProfile : activeProfiles) {
System.out.println(activeProfile);
}
// 获取配置信息
String property = environment.getProperty("app.xyz.address.city");
System.out.println(property);
}
SpringBoot aop实现
添加依赖
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>3.3.5</version>
</dependency>
编写切面类
java
package com.ali.springaop.component;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import java.util.Arrays;
// 指定切面类
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
// 定义切入点,匹配所有以"service"结尾的包下的所有方法
@Pointcut("execution(* com.ali.springaop.service..*(..))")
public void ServiceMethods(){
}
// 前置通知,切入点的方法执行前执行此代码
@Before("ServiceMethods()")
public void before(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
logger.info("Method [{}] with parameters [{}] is called", methodName, Arrays.toString(args));
}
}