Appearance
Spring Framework
1. 框架概念
1.1 生活中的框架
框架是一个集成了基本结构、规范、设计模式、编程语言和程序库等基础组件的软件系统,用于构建更高级别的应用程序。
框架思维:为解决特定问题而提供的一整套解决方案。
1.2 程序中的框架
主流框架:SSM
- Spring:为所有 bean(组件)提供管理解决方案
- SpringMVC:解决表述层(控制层)常见问题
- Mybatis:解决数据访问层(Dao 层)问题
框架优点:
- 提高开发效率
- 降低开发成本
- 提高应用程序稳定性
- 提供标准化解决方案
2. Spring Framework 简介
2.1 Spring 广义与狭义
广义 Spring:Spring 技术栈(全家桶)
- Spring Framework、Spring MVC、SpringBoot、Spring Cloud 等
狭义 Spring:Spring Framework(基础框架)
2.2 Spring Framework 概述
Spring 是基于 IoC 和 AOP 的容器框架
核心概念:
- IoC 容器:负责实例化、配置和组装 bean
- IoC(控制反转):控制权由应用程序转移到 IoC 容器
- DI(依赖注入):在容器内部处理组件间的依赖关系
- AOP:面向切面编程,动态统一添加额外功能
主要功能模块:
| 模块 | 功能 |
|---|---|
| Core Container | 核心容器,控制反转和依赖注入 |
| AOP&Aspects | 面向切面编程 |
| TX | 声明式事务管理 |
| Testing | 快速整合测试环境 |
| Data Access/Integration | 数据访问/集成功能 |
| Spring MVC | Web 应用程序集成功能 |
2.3 Spring Framework 特点
- 丰富的生态系统
- 模块化设计
- 简化 Java 开发
- 不断创新和发展
3. Spring IoC/DI 基本实现
3.1 基于 XML 方式装配组件
环境准备:
xml
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.6</version>
</dependency>
</dependencies>实现步骤:
- POJO 类:
java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
private Integer stuId;
private String stuName;
private Integer stuAge;
}- 配置文件(spring.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="zs" class="com.at.bean.Student">
<property name="stuId" value="1001"/>
<property name="stuName" value="zs"/>
<property name="stuAge" value="18"/>
</bean>
</beans>- 测试类:
java
@Test
public void testStudent(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("spring.xml");
Student bean = ioc.getBean(Student.class);
System.out.println("bean = " + bean);
}3.2 基于配置类装配组件
配置类:
java
@Configuration
public class SpringConfig {
@Bean
public Student student(){
return new Student(1001, "zhangsan", 18);
}
}测试类:
java
@Test
public void testSpring(){
ApplicationContext ioc = new AnnotationConfigApplicationContext(SpringConfig.class);
Student bean = ioc.getBean(Student.class);
System.out.println("bean = " + bean);
}3.3 @Bean 注解详解
@Bean 源码属性:
name:指定 bean 名称value:与 name 属性是别名关系initMethod:指定初始化方法destroyMethod:指定销毁方法autowireCandidate:是否作为自动装配候选者
装配 DruidDataSource:
java
@Configuration
public class DruidConfig {
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Bean
public DataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driverClassName);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
}3.4 Bean 生命周期
六个阶段:
- 加载 Bean 定义
- 实例化 Bean 组件
- 设置 Bean 属性
- 调用 Bean 初始化方法
- Bean 可以使用
- 调用 Bean 销毁方法
示例:
java
public class Student {
public Student() {
System.out.println("Student==>构造器!!!");
}
public void setStuId(Integer stuId) {
System.out.println("==>Student->setId()!!!");
this.stuId = stuId;
}
public void initStudent() {
System.out.println("==>Student->init-method()!!!");
}
public void destroyStudent() {
System.out.println("==>Student->destroy-method()!!!");
}
}java
@Configuration
public class SpringConfig {
@Bean(value = "student", initMethod = "initStudent", destroyMethod = "destroyStudent")
public Student student(){
Student student = new Student();
student.setStuId(101);
return student;
}
}3.5 Bean 作用域
常用作用域:
| 作用域 | 含义 | 创建时机 | 默认值 |
|---|---|---|---|
| singleton | IOC 容器中单实例 | IOC 容器初始化时 | 是 |
| prototype | 多个实例 | 获取 bean 时 | 否 |
使用:
java
@Bean
@Scope(value = "singleton") // 或 "prototype"
public Student student(){
return new Student();
}4. Spring IoC/DI 深入学习
4.1 开启组件扫描
java
@Configuration
@ComponentScan(basePackages = "com.at")
public class SpringConfig {}4.2 分层管理组件注解
| 注解 | 说明 |
|---|---|
| @Component | 通用组件 |
| @Repository | 数据访问层(Dao 层) |
| @Service | 业务层(Service 层) |
| @Controller | 控制层 |
4.3 属性自动注入注解
@Value:为字面量实现自动装配
java
@Value("${jdbc.url}")
private String url;@Autowired:为非字面量类型实现自动装配
- 先按类型匹配,再按 id 筛选
@Qualifier:配合 @Autowired 指定 bean id
java
@Autowired
@Qualifier("userDao")
private UserDao userDao;@Resource:Java EE 注解,默认按名称匹配
4.4 @Import 注解
导入配置类:
java
@Configuration
@Import({DatabaseConfig.class, WebConfig.class})
public class AppConfig {}导入普通类:
java
@Import(MyService.class)
public class AppConfig {}4.5 @Conditional 注解
条件化装配 Bean:
java
@Configuration
public class AppConfig {
@Bean
@Conditional(MyCondition.class)
public MyService myService() {
return new MyServiceImpl();
}
}衍生条件注解:
- @ConditionalOnProperty
- @ConditionalOnClass
- @ConditionalOnBean
- 等
4.6 FactoryBean 与 BeanFactory 区别
| 特性 | FactoryBean | BeanFactory |
|---|---|---|
| 角色 | 定义如何创建特定类型 bean | 管理 bean 生命周期 |
| 主要用途 | 控制 bean 创建逻辑 | 提供 bean 获取和管理 |
| 接口实现 | 实现者提供具体创建逻辑 | Spring 容器基础接口 |
5. Spring AOP 详解
5.1 AOP 前奏
问题:核心业务代码与非核心业务代码耦合
解决方案:
- 提取工具类解决代码分散
- 使用代理模式解决代码混乱
5.2 代理模式
静态代理:
java
public class CalcImplStaticProxy implements Calc {
private CalcImpl calcImpl;
public int add(int i, int j) {
MyLogging.methodBefore("add", i, j);
int rs = calcImpl.add(i, j);
MyLogging.methodAfter("add", rs);
return rs;
}
}动态代理:
java
public class CalcImplDynamicProxy {
private Object target;
public Object getProxy(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
String methodName = method.getName();
MyLogging.methodBefore(methodName, args);
Object rs = method.invoke(target, args);
MyLogging.methodAfter(methodName, rs);
return rs;
}
);
}
}5.3 Spring 支持的动态代理
JDK 动态代理:
- 基于接口
proxy-target-class="false"
CGLIB 动态代理:
- 基于继承
proxy-target-class="true"(SpringBoot 默认)
5.4 基于注解实现 AOP
环境准备:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>切面类:
java
@Component
@Aspect
public class MyLogging {
@Before("execution(public int com.at.aop.CalcImpl.add(int,int))")
public void methodBefore(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("==>"+methodName+"()正在执行,参数:"+ Arrays.toString(args));
}
}开启支持:
java
@Configuration
@EnableAspectJAutoProxy
public class SpringConfigAop {}5.5 AOP 相关术语
- 横切关注点:非核心业务代码
- 通知:非核心业务代码提取到类中
- 连接点:非核心业务代码织入位置(通知之前)
- 切入点:非核心业务代码织入位置(通知之后)
- 切面类:包含通知的类
- 目标对象:被代理的对象
- 代理对象:通过代理类获取的对象
5.6 切入点表达式
语法:
java
@Before("execution(* com.at.aop.*.*(..))")重用表达式:
java
@Pointcut("execution(* com.at.aop.*.*(..))")
public void myJoinPoint(){}
@Before("myJoinPoint()")
public void methodBefore(JoinPoint joinPoint){}5.7 AOP 五大通知
前置通知(@Before):
java
@Before("myJoinPoint()")
public void methodBefore(JoinPoint joinPoint){}后置通知(@After):
java
@After("myJoinPoint()")
public void methodAfter(JoinPoint joinPoint){}返回通知(@AfterReturning):
java
@AfterReturning(value = "myJoinPoint()", returning = "rs")
public void methodAfterRetuning(JoinPoint joinPoint, Object rs){}异常通知(@AfterThrowing):
java
@AfterThrowing(value = "myJoinPoint()", throwing = "ex")
public void methodAfterThrowing(JoinPoint joinPoint, Exception ex){}环绕通知(@Around):
java
@Around("myJoinPoint()")
public Object methodAround(ProceedingJoinPoint pjp){
try {
// 前置通知
Object rs = pjp.proceed();
// 返回通知
return rs;
} catch (Throwable e) {
// 异常通知
} finally {
// 后置通知
}
}5.8 切面优先级
java
@Aspect
@Order(1)
public class LoggingAspect {}6. Spring 事务管理
6.1 JdbcTemplate 基本用法
环境准备:
properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_tx
spring.datasource.username=root
spring.datasource.password=root常用 API:
java
// 增删改
jdbcTemplate.update(String sql, Object... args);
// 查询单个对象
jdbcTemplate.queryForObject(String sql, RowMapper, Object... args);
// 查询多个对象
jdbcTemplate.query(String sql, RowMapper);6.2 事务概念回顾
ACID 属性:
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔离性(Isolation)
- 持久性(Durability)
隔离级别:
- 读未提交(READ UNCOMMITTED)
- 读已提交(READ COMMITTED)
- 可重复读(REPEATABLE READ)- MySQL 默认
- 串行化(SERIALIZABLE)
6.3 Spring 声明式事务
编程式事务:
java
Connection conn = ...;
try {
conn.setAutoCommit(false);
// 业务代码
conn.commit();
} catch(Exception e){
conn.rollBack();
} finally{
conn.close();
}声明式事务(推荐):
java
@Service
@Transactional
public class UserService {
// 方法会自动在事务中执行
}事务管理器配置:
java
@Configuration
@EnableTransactionManagement
public class TxConfig {
@Bean
public TransactionManager transactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
}6.4 @Transactional 注解属性
只读事务:
java
@Transactional(readOnly = true)事务超时:
java
@Transactional(timeout = 3) // 3秒超时回滚规则:
java
@Transactional(
rollbackFor = Exception.class,
noRollbackFor = FileNotFoundException.class
)隔离级别:
java
@Transactional(isolation = Isolation.REPEATABLE_READ)传播行为:
java
@Transactional(propagation = Propagation.REQUIRED) // 默认
@Transactional(propagation = Propagation.REQUIRES_NEW)6.5 事务传播行为
常用传播行为:
- REQUIRED(默认):如果当前存在事务,则加入该事务;如果不存在,则创建新事务
- REQUIRES_NEW:创建新事务,如果当前存在事务,则挂起当前事务
示例:
java
@Service
public class UserServiceAll {
@Autowired
private UserService userService;
@Transactional
public void updateUserAll(){
userService.updatePwdByUsername("zhangsan", "666666");
userService.updateNicknameByUsername("普通员工", "zhangsan");
}
}