今天学习了Spring的相关知识,IOC,bean,AOP,事务,接下来我将将我的学习过程记录下来,分享到CSDN,做一个知识点汇总,里面包括了一些我自己的想法,如果有问题请指正我!
一.SpringIOC
在传统开发中,创建对象必须要手动new对象,导致代码的耦合度是很高的。在实际开发中对象与对象之间的调用是非常高的,我们不可能每次调用对象都重新new一下,例如:controller,service,dao这些类都是相互依赖,相互关联。IOC通过控制反转,对象创建权限交给Spring容器,容器初始化时创建对象并维护对象间的相互依赖,使用时直接从容器中获取,实现代码的解耦。
初始化是什么:在SpringIOC容器中,“启动并做好准备工作”的过程。
关键词:new对象,耦合性高。控制反转,对象创建交给ioc容器,初始化(创建对象+维护对象间依赖),解耦。
二.bean
1,Spring中什么是bean?Spring中什么是IOC容器?

上面说了,IOC通过控制反转,对象创建权交给IOC容器,容器初始化创建对象,维护依赖。
所以IOC容器是负责管理bean定义加载,作用:实例化,创建对象,注入依赖,生命周期控制。
Bean是IOC容器管理的对象,由容器创建+注入依赖+管理生命周期。
面试题1.spring框架中的单例bean是线程安全的吗?
不是线程安全的,Spring框架有一个@Scope注解,默认值是singleton单例,因为一般在Spring的bean是注入无状态对象。没有线程安全问题,如果在bean中定义了可修改的成员变量,要考虑线程安全,可使用多例或加锁解决。
@Service
@Scope(“singleton”) //bean在每个SpringIOC容器中只有一个实例
//prototype:一个bean可以定义多个实例
@controller
@RequestMapping("/user")
public class userController{
private int count; //实例成员变量
@Autowired
private UserService userservice; //对象引用
}
结论:Spring默认单例bean本身不保证线程安全,线程安全与否看Bean是不是无状态的。
什么是无状态的对象?
这个类中没有成员变量,对象不会保存任何业务数据,所有数据都是方法调用的时候通过参数传进来,用完就扔。
无状态代码如下:
@Service
public class UserService {
// 没有写 private User user; 这种成员变量
public void queryUser(Long userId){
// userId是调用方法传过来的局部变量,每个线程调用都会自己生成一份,互不干扰
}
}
多个线程同时调用queryUser,每个线程变量都在自己栈中,不会相互篡改数据,这个时候是线程安全的。
线程不安全怎么解决*2方法
1.改成多例@Scope("prototype"),每次请求都新建Bean对象,每个线程用自己的对象。相互不干扰,开销会比较大。
2.加锁synchronized:同一时间只允许一个线程操作共享成员变量,并发性能下降。
三.AOP
springAOP是面向切面编程,底层是基于动态代理实现的,创建一个切面类,用于存放抽取出来日志,事务等与业务无关的横切逻辑。通过@Aspect(标记切面)+五大通知—->定义增强时机。利用动态代理在目标方法执行前后插入横切逻辑,实现代码的复用和解耦。

五大通知作用是告诉Spring什么时候把哪个横切逻辑“植入”方法中。
核心=AOP环绕通知+切点表达式
通过环绕通知的参数获取请求的参数(类,方法,注解,请求方式)获取成功后保存数据库。
/**
* AOP日志切面
* @Aspect 标记这是切面类
* @Component 交给Spring管理
*/
@Aspect
@Component
public class LogAspect {
// 切点表达式:拦截自己项目controller下所有方法,根据你的包路径修改
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
public void pointCut(){}
/**
* 环绕通知:功能最强,可以在目标方法前后执行,还能控制是否执行目标方法
* ProceedingJoinPoint:只能环绕通知使用,可以执行目标方法 proceed()
*/
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 1. 获取目标类
Class<?> targetClass = joinPoint.getTarget().getClass();
String className = targetClass.getName();
// 2. 获取方法签名、方法对象
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
String methodName = method.getName();
// 3. 获取方法入参
Object[] args = joinPoint.getArgs();
String params = Arrays.toString(args);
// 4. 获取方法上所有注解
Annotation[] annotations = method.getAnnotations();
System.out.println("【AOP切面】类名:" + className);
System.out.println("【AOP切面】方法名:" + methodName);
System.out.println("【AOP切面】请求参数:" + params);
System.out.println("【AOP切面】方法注解:" + Arrays.toString(annotations));
long start = System.currentTimeMillis();
Object result;
try {
// 执行目标方法,这行就是调用我们写的controller/service业务方法
result = joinPoint.proceed();
} catch (Throwable e) {
// 记录异常日志
System.out.println("方法执行异常:" + e.getMessage());
throw e;
}
long costTime = System.currentTimeMillis() – start;
System.out.println("【AOP切面】返回结果:" + result);
System.out.println("【AOP切面】执行耗时:" + costTime + " ms");
注意:SpringBoot 必须加@Component把切面交给容器,否则切面不生效。
四.事务
事务就是要么全部成功,要不数据就全部回滚。
相关注解:@Transactional(放在service层业务上)
事务分为编程式事务+声明式事务
1.编程式事务:具有入侵性,只是在service的业务方法上写事务代码,用TransactionTemplate把业务逻辑跑起来(事务代码+业务代码),所以修改业务代码时候还要修改业务代码,所以建议使用声明式事务
2.声明式事务:声明式事务就是基于AOP,通过@Transactional注解,让Spring自动用于切面织入事务逻辑。
面试题:Spring中事务是如何实现的?
我们使用声明式事务,通过AOP功能,底层依靠AOP动态代理技术,前后进行拦截,执行方法前开启事务,执行方法后执行情况提交或回滚事务。下面代码是我搜豆包的,我觉得可以看懂。
下面代码是事务代码:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class AccountService {
// 加上注解:当前方法受Spring事务管理
@Transactional
public void transferMoney() {
// 业务1:A扣钱
deductMoneyA();
// 模拟出错!抛出运行时异常,事务触发回滚,A扣钱操作会撤销
int i = 1 / 0;
// 业务2:B加钱
addMoneyB();
}
private void deductMoneyA() {
System.out.println("A账户扣钱");
}
private void addMoneyB() {
System.out.println("B账户加钱");
}
}
底层伪代码(帮助理解 AOP 代理做了什么,不是实际项目代码)
// AOP代理增强逻辑(Spring底层自动生成)
public void transferMoneyProxy(){
try{
// 1.开启事务
beginTransaction();
// 执行真实业务方法 transferMoney()
realObject.transferMoney();
// 无异常:提交事务
commitTransaction();
}catch (RuntimeException e){
// 出现运行时异常:回滚
rollbackTransaction();
throw e;
}
}
核心:Spring 声明式事务底层基于 AOP 动态代理




