IOC:
控制反转,是一种编程思想,Spring是实现了这个思想的一套框架。将对象的创建权利反转给第三方容器(Spring的bean容器),这样做能降低类与类之间的耦合;
耦合:假设A类和B类,如果直接在A类中new一个B类的对象,称之为硬编码耦合。解耦就是要消除这种耦合性,因为硬编码耦合的程序会有一定的问题,假如B类的构造形式发生了变化,就必须要修改A类。
class A{
B b = new B();
}
class B{
public B(){};
}
//假设B类的构造方法有参数,此时A类也要修改;
class A{
B b = new B("str");
}
class B{
public B(String str){};
}
在实际开发过程中,类的构造形式变化有多种,比如实现类和代理类的切换,所以要有IOC;
AOP:
面向切面编程,实际开发过程中,业务模块通常可以分为两部分核心业务和非核心业务(事务控制,日志管理,资源开启回收…),通常来说,业务之间的核心任务都是不同的,但是非核心业务有可能很相像。这些非核心业务代码抽取出来,形成一个切面,针对这个切面编程的开发模式,就是面向切面编程;
aop的底层实现:
1、代理模式
简单来说:代理就是对目标方法进行增强;
代理模式分为静态代理和动态代理;
静态代理的缺陷:
1.1一个系统有多少个目标方法类,就需要创建多少个代理对象;
1.2如果一个目标方法类中有很多方法需要增强,代理对象的方法会有很多重复的代码;
1.3静态代理的复用性差
**动态代理:**有jdk动态代理和cglib动态代理
jdk动态代理是实现invocationHandler接口;
cglib动态代理是继承MethodInterceptor;
jdk动态代理:
1、当客户端执行代理对象的方法时,会先进入到拦截器的invoke方法;
2、拦截器的invoke方法体的内容就是代理对象方法体的内容;
3、拦截器中invoke方法的method参数是在调用的时候赋值的;
这两种动态代理在springaop都有,是根据实际情况选择用jdk还是cglib的;
动态代理的加载方式
三个关键:切面类,通知,目标方法
SpringAOP将动态代理做成了配置化;
具体步骤:
1、添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、准备切面
@Aspect
@Component
public class Aop {
/**
* 增强方法 - 环绕增强,环绕增强的返回值就是目标方法的返回值
* @Around("切点表达式") 切点?- 这个增强到底要增强哪个目标方法
*/
@Around("@annotation(MyLog)")
public Object writerLog(ProceedingJoinPoint joinPoint){
System.out.println("调用目标方法前需要的操作");
//开始调用目标方法
Object result = null;
try {
result = joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("调用目标方法后需要的操作~对返回值进行修改");
return result;
}
}
aop的运用场景:
事务控制、权限控制、用户的统一行为记录、分布式系统的登录状态统一判断、统一的异常处理… …
Spring事务传播行为和数据库无关,是spring的特性
事务:对数据库的一组操作的最小逻辑执行单元;这个单元要么成功,要么放弃执行;
事务是为了保证数据库数据一致性的重要手段
四大特性:原子性,一致性,隔离性,持久性
REQUIRED(默认行为) - 如果没有事务就主动开启事务,否则就沿用当前的事务
SUPPORTS - 如果没有事务就不用事务,如果有就沿用当前事务
MANDATORY - 如果当前没有事务就会抛异常
REQUIRES_NEW - 每次都会新开一个事务
NOT_WUPPORTED - 不支持事务,如果当前存在事务,就会挂起当前事务,直到当前业务执行完成才恢复事务
NEVER - 存在事务就抛异常
NESTED - 事务的嵌套,假设方法a调用了方法b,方法b是这个传播行为。在调用方法b之前,方法a的事务会在当前位置记录一个回滚点,如果方法b发生异常,不会回滚整个事务,而是回滚到回滚点的位置。简单来说,看想去好像方法b只回滚了自己的事务,