目录
一种设计模式,它的作用是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接调用,而是通过代理类间接调用

代理类持有目标对象,并且实现相同的接口,代理类在目标方法调用前后进行额外的操作,代理类和目标对象的关系是在编译期就写死的
静态代理工作原理:
(1) 定义一个接口(或抽象类),目标对象实现这个接口
(2) 创建一个代理类,实现目标接口,并持有目标对象
(3) 代理类重写目标接口方法,在重写方法中调用目标对象同名方法
(4) 代理类的重写方法在目标对象同名方法前后做额外操作
示例代码:
- // 接口
- public interface Travel {
- void vacation();
- }
-
- // 目标对象
- public class TravelImpl implements Travel{
- @Override
- public void vacation() {
- System.out.println("度假...");
- }
- }
-
- // 代理类
- public class TravelProxy implements Travel {
-
- private TravelImpl travel; //引入目标对象
-
- public void setTravel(TravelImpl travel) {
- this.travel = travel;
- }
-
- @Override
- public void vacation() {
- System.out.println("去的车票购买");
- travel.vacation();
- System.out.println("回的车票购买");
- }
- }
-
- // 测试
- @Test
- public void travelTest() throws Exception {
- TravelProxy travel = new TravelProxy();
- travel.setTravel(new TravelImpl());
- travel.vacation();
- // 去的车票购买
- // 度假...
- // 回的车票购买
- }
JAVA动态代理是基于反射实现的,代理类的创建和方法都是在运行期完成的
原理: 生成一个方法被增强的接口的实现类的代理对象
涉及的类: java.lang.reflect.Proxy
涉及的接口: java.lang.reflect.InvocationHandler
要求: 被代理的类至少实现一个接口
示例代码:
- @Test
- public void travelTest() throws Exception {
- // 目标对象
- TravelImpl travelImpl = new TravelImpl();
- /**
- * newProxyInstance参数说明:
- * ClassLoader(类加载器):将被代理类的字节码文件加载到JVM
- * Class[](字节码数组):被代理类实现的所有接口的字节码数组
- * InvocationHandler(拦截器,被代理类实现的任何"接口方法"都会被拦截)
- * proxy:代理对象的引用(一般不用)
- * method:被代理对象的方法对象(反射原理)
- * args:当前方法所需参数
- */
- // 生成代理对象
- Travel travelProxy = (Travel) Proxy.newProxyInstance(TravelImpl.class.getClassLoader(), TravelImpl.class.getInterfaces(), new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- // 获取方法参数
- Object myName = args[0];
- // 获取方法名
- String methodName = method.getName();
- // 执行原始方法(有返回值)
- //参数1:目标对象
- //参数2,方法参数
- System.out.println("去的车票购买");
- Object methodReturn = method.invoke(travelImpl, args);
- System.out.println("回的车票购买");
- // 返回参数
- return methodReturn;
- }
- });
- // 执行代理对象
- travelProxy.vacation();
- //去的车票购买
- //度假...
- //回的车票购买
- travelProxy.study();
- //去的车票购买
- //去求学...
- //回的车票购买
- }
原理: 生成一个方法被增强的该类的子类的代理对象
引入jar包: cglib
涉及的类: net.sf.cglib.proxy.Enhancer
要求: 被代理的类不能是最终类(final,不能被继承)
示例代码:
- @Test
- public void staticProxyTest() {
- // 目标对象
- TravelImpl travelImpl = new TravelImpl();
- // 代理对象
- TravelImpl travelProxy = (TravelImpl) Enhancer.create(TravelImpl.class, new MethodInterceptor() {
- @Override
- public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
- System.out.println("去的车票购买");
- Object methodReturn = method.invoke(travelImpl, objects);
- System.out.println("回的车票购买");
- return methodReturn;
- }
- });
- // 执行代理对象
- travelProxy.vacation();
- }
底层核心原理是动态代理
AOP(Aspect Oriented Programming)面向切面编程(使用动态代理技术,在不修改源码的基础上,给程序添加额外的功能)
| 注解 | 说明 |
| @Aspect | 标识类为"切面类" |
| @Pointcut("execution(表达式)") | 切入点表达式 例: public * xyz.aboluo.service.impl.*.*(..) |
| @Before | 前置通知 |
| @AfterReturning | 后置通知 |
| @AfterThrowing | 异常通知 |
| @After | 最终通知(总会执行) |
| @Around | 环绕通知 |
(1) 引入依赖
(2) 切面类
- @Component
- @Aspect //标识该类为一个"切面类"
- @Order(1) //针对"多切面",数字越小"越先执行,越后结束"
- public class LogAdvice {
-
- @Pointcut("execution(public * xyz.aboluo.controller.*.*(..))")
- private void pc1() {
- }
-
- @Pointcut("execution(public * xyz.aboluo.service.impl.*.*(..))")
- private void pc2() {
- }
-
- @Pointcut("pc1() || pc2()")
- private void pc3() {
- }
-
- //前置通知
- @Before("pc2()")
- public void beforeAdvice() {
- System.out.println("前置通知,方法前执行");
- }
-
- //后置通知
- @AfterReturning("pc2()")
- public void afterReturningAdvice() {
- System.out.println("后置通知,方法后执行");
- }
-
- //异常通知
- @AfterThrowing("pc2()")
- public void afterThrowingAdvice() {
- System.out.println("异常通知,异常时执行");
- }
-
- //最终通知
- @After("pc2()")
- public void afterAdvice() {
- System.out.println("最终通知,始终执行");
- }
-
- //环绕通知
- @Around("pc2()")
- public Object aroundAdvice(ProceedingJoinPoint pjp) {
- Object methodReturn = null;
- try {
- System.out.println("前置通知");
- Object target = pjp.getTarget(); //获取被代理对象
- String methodName = pjp.getSignature().getName(); //获取当前方法名
- Object[] args = pjp.getArgs(); //获取当前方法执行所需的参数
- methodReturn = pjp.proceed(args); //原方法执行
- System.out.println("后置通知");
- } catch (Throwable throwable) {
- System.out.println("异常通知");
- } finally {
- System.out.println("最终通知");
- }
- return methodReturn;
- }
- }
(3) 切面执行顺序
单切面: @Around --> @Before --> 原始方法 -->@After --> @AfterReturning --> @Throwing
多切面: 使用@Order(1)注解,数字越小"越先执行,越后结束"

事务是数据库的,并不是java的,一个事务中的所有操作,要么全部执行,要么全部不执行
事务的4大特性:
(A) 原子性: 十五中的操作要么都生效,要么都不生效
(C) 一致性: 事务执行前后,数据库中定义的约束,业务规则等保持不变
(I) 隔离性: 并发访问数据库时,多个事物之间互不影响
(D) 持久性: 如果事务被成功提交,数据会持久保存在数据库
原子性、一致性、持久性都是单事务; 隔离性是多事务并发
脏读: 读取到另一个事务未提交的数据
不可重复读: 受其它事务update的干扰(期望是操作修改之前的数据)
虚读/幻读: 读取不到其它事务的insert/delete,但操作数据时提示"数据异常"等问题
| 隔离级别 | 脏读 | 不可重复读 | 虚读/幻读 |
| read uncommitted | 有 | 有 | 有 |
| read committed (oracle默认) | 无 | 有 | 有 |
| repeatable read (mysql默认) | 无 | 无 | 有 |
| searializable | 无 | 无 | 无 |
底层原始是利用了AOP
(1) 添加依赖
(2) 配置事务管理器(注入数据源),开启spring对声明式事务的注解支持
(3) 在类/方法(方法优先级更高)上添加@Transactional注解
- /**
- * readOnly=true
- * 只读:只能查询,不能增删改
- * timeout=10 //默认-1(永不超时)
- * 超时(秒):响应超时,回滚
- * 回滚策略:设置哪些异常回滚,哪些异常不回滚
- * 设置回滚:rollbackFor={Exception.class,RuntimeException.class}
- * rollbackForClassName={"全限定类名"}
- * 设置不回滚:noRollbackFor={......}
- * noRollbackForClassName={.....}
- * isolation 事务隔离级别:解决"读的问题"
- * =Isolation.DEFAULT使用数据库的默认隔离级别
- * =Isolation.READ_UNCOMMITTED
- * =Isolation.READ_COMMITTED (oracle默认,有"不可重复读")
- * =Isolation.REPEATABLE_READ (mysql默认,有"虚读/幻读")
- * =Isolation.SERIALIZABLE
- * propagation 事务传播行为:事务之间的调用(例如:A调用B,那么要使用哪个的事务)
- * Propagation.REQUIRED(默认):当前线程有事务就用当前事务,没有就新建事务
- * Propagation.REQUIRES_NEW:不管当前线程有没有事务都新建一个事务,新事务与之前事务没有嵌套关系,之前的事务挂起
- */
- @Transactional(readOnly = false, timeout = 10, rollbackFor = RuntimeException.class, isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED)
- public void aaa() {
- userDao.aaa();
- }
事务传播行为示例:
有A,B两个事务,在A事务中循环调用B事务2次(第一次成功,第二次失败)
(1) A事务传播行为:REQUIRED,B事务传播行为:REQUIRED
- @Transactional(propagation = Propagation.REQUIRED)
- public void transactionA() {
- for (int i = 0; i < 2; i++) {
- transactionB();
- }
- }
-
- @Transactional(propagation = Propagation.REQUIRED)
- public void transactionB() {
- // 第一次执行失败,第二次执行成功
- }
在一个线程中,B事务中执行的2次事务都回滚,因为B事务使用的是Propagation.REQUIRED事务传播特性,因为AB在同一个线程中,而且已经存在了A事务,所以B就沿用了A事务
(2) A事务传播行为:REQUIRED,B事务传播行为:REQUIRES_NEW
- @Transactional(propagation = Propagation.REQUIRED)
- public void transactionA() {
- for (int i = 0; i < 2; i++) {
- transactionB();
- }
- }
-
- @Transactional(propagation = Propagation.REQUIRES_NEW)
- public void transactionB() {
- // 第一次执行失败,第二次执行成功
- }
在一个线程中,B事务中执行的第1次事务正常提交,第二次事务回滚,因为B事务使用的是Propagation.REQUIRES_NEW事务传播特性,因此每次transactionB方法执行都会新建一个新的事务(即B事务),新事务(B事务)与原事务(A事务)没有嵌套关系