这里写目录标题
- jdk动态代理例子
- CGlib动态代理例子
- 手写spring中的事务
- 部分自定义注解版aop实现方式
Spring的两大重点,IOC和AOP,今天我们就来学AOP,众所周知AOP的底层是动态代理,让我们看一下这两种动态代理的区别。
例子:
我们常常使用aop切面编程打印日志,但是他的底层是什么呢?我们常常看到的是封装好的注解,并不知道他的底层是如何实现的。
那我们下边先看手动调用动态代理实现执行方法前后打印日志。
jdk动态代理例子
客户端首先调用代理对象的方法
CalculatorProxy类
package AOP.Proxy;import AOP.service.Calculator;
import AOP.util.Util;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;/*** @BelongsProject: JAVAtest* @BelongsPackage: AOP.Proxy* @Author: GuoYuan.Zhao* @Description: 描述什么人干什么事儿* @CreateTime: 2024-01-24 14:47* @Version: 1.0*/public class CalculatorProxy {//必须要有接口,如果没有接口,不能使用,这种方式是用jdk提供的reflect 包下边的类,但是//生产环境中我不能保证每个类都有具体的接口,所有有第二中方式cglib//两种动态代理的方式,一种是JDK 一种是cglibpublic static Calculator getCalculator( final Calculator calculator){//获取被代理对象的类加载器ClassLoader loader = calculator.getClass().getClassLoader();Class<?>[] interfaces = calculator.getClass().getInterfaces();InvocationHandler handler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try{System.out.println(method.getName()+"方法开始执行,参数列表是:"+ Arrays.asList(args));result = method.invoke(calculator,args);System.out.println(method.getName()+"方法结束执行,参数列表是:"+ result);}catch (Exception e){System.out.println(method.getName()+"方法抛出异常"+e.getMessage());}finally {System.out.println(method.getName()+"方法执行结束over");}
//return result;}};Object instance = Proxy.newProxyInstance(loader, interfaces, handler);return (Calculator) instance;}Calculator接口// //获取被代理对象的类加载器
// ClassLoader loader = calculator.getClass().getClassLoader();
//
// Class<?>[] interfaces = calculator.getClass().getInterfaces();
// InvocationHandler handler = new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Object result = null;
// try{System.out.println(method.getName()+"方法开始执行,参数列表是:"+ Arrays.asList(args));
// Util.start(method,args);
// result = method.invoke(calculator,args);System.out.println(method.getName()+"方法开始执行,参数列表是:"+ result);
// Util.stop(method,result);
// }catch (Exception e){System.out.println(method.getName()+"方法抛出异常"+e.getMessage());
// Util.logExpection(method,e);
// }finally {System.out.println(method.getName()+"方法执行结束over");
//
// Util.logFinally(method);
// }// return result;
// }
// };
// Object instance = Proxy.newProxyInstance(loader, interfaces, handler);
// return (Calculator) instance;
// }MyCalculator类// //获取被代理对象的类加载器
// ClassLoader loader = calculator.getClass().getClassLoader();
//
// Class<?>[] interfaces = calculator.getClass().getInterfaces();
// InvocationHandler handler = new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Object result = null;
// try{System.out.println(method.getName()+"方法开始执行,参数列表是:"+ Arrays.asList(args));
// Util.start(method,args);
// result = method.invoke(calculator,args);System.out.println(method.getName()+"方法开始执行,参数列表是:"+ result);
// Util.stop(method,result);
// }catch (Exception e){System.out.println(method.getName()+"方法抛出异常"+e.getMessage());
// Util.logExpection(method,e);
// }finally {System.out.println(method.getName()+"方法执行结束over");
//
// Util.logFinally(method);
// }// return result;
// }
// };
// Object instance = Proxy.newProxyInstance(loader, interfaces, handler);
// return (Calculator) instance;}
public interface Calculator {public Integer add(Integer i,Integer j) throws NoSuchMethodException;public Integer div(Integer i,Integer j);public Integer mul(Integer i,Integer j);public Integer sub(Integer i,Integer j);}
package AOP.service;import AOP.util.Util;
import org.springframework.stereotype.Service;import java.lang.reflect.Method;/*** @BelongsProject: JAVAtest* @BelongsPackage: AOP.service* @Author: GuoYuan.Zhao* @Description: 描述什么人干什么事儿* @CreateTime: 2024-01-24 14:15* @Version: 1.0*/@Service
public class MyCalculator implements Calculator{@Overridepublic Integer add(Integer i, Integer j) throws NoSuchMethodException {//11111
// System.out.println("add方法开始执行:参数是"+i+"___"+j);
// int result = i+j;
// System.out.println("add方法结束,执行结果是"+result);
// return result;//22222// Method add = MyCalculator.class.getMethod("add", Integer.class, Integer.class);
// Util.start("add",i,j);
// Integer result = i+j;
// Util.stop(add,result);
// return result;//333333Integer result = i+j;return result;}@Overridepublic Integer div(Integer i, Integer j) {System.out.println("div方法开始执行:参数是"+i+"___"+j);Integer result = i/j;System.out.println("div方法结束,执行结果是"+result);return result;}@Overridepublic Integer mul(Integer i, Integer j) {System.out.println("mul方法开始执行:参数是"+i+"___"+j);int result = i*j;System.out.println("mul方法结束,执行结果是"+result);return result;}@Overridepublic Integer sub(Integer i, Integer j) {System.out.println("sub方法开始执行:参数是"+i+"___"+j);Integer result = i-j;System.out.println("sub方法结束,执行结果是"+result);return result;}
}
客户端
主函数{Calculator calculator = CalculatorProxy.getCalculator(new MyCalculator());calculator.add(1,1);saveProxyClass("E:\\zy\\TGB-zgy-2022\\MiMust\\MiDesignDemo\\JAVAtest\\NormalTest1\\demo\\src");}public static void saveProxyClass(String path) throws IOException {byte[] $proxy1s = ProxyGenerator.generateProxyClass("$Proxy1", MyCalculator.class.getInterfaces());FileOutputStream out = new FileOutputStream(new File(path + "$Proxy1.class"));out.write($proxy1s);}
最后可以看到代理类
这个类里边有 我的目标方法,其实客户端调用的就是这个方法
然后h就是我们上边那个匿名内部类的对象
CGlib动态代理例子
CglibFactory类
public class CglibFactory implements MethodInterceptor {public CglibFactory(MyCalculatorCGlib target) {}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("执行方法"+ method.getName());Object result = methodProxy.invokeSuper(o, objects);//这里实现将返回值字符串变为大写的逻辑
// if(result != null) {
// result = ((String) result).toUpperCase();
// }System.out.println("执行方法完毕结果是"+result);return result;}public MyCalculatorCGlib myCglibCreator() {System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\zy\\TGB-zgy-2022\\MiMust\\MiDesignDemo\\JAVAtest\\NormalTest1\\demo\\src");Enhancer enhancer = new Enhancer();//将目标类设置为父类,cglib动态代理增强的原理就是子类增强父类,cglib不能增强目标类为final的类//因为final类不能有子类enhancer.setSuperclass(MyCalculatorCGlib.class);//设置回调接口,这里的MethodInterceptor实现类回调接口,而我们又实现了MethodInterceptor,其实//这里的回调接口就是本类对象,调用的方法其实就是intercept()方法enhancer.setCallback(this);//create()方法用于创建cglib动态代理对象return (MyCalculatorCGlib) enhancer.create();}
}
MyCalculatorCGlib类
public class MyCalculatorCGlib {public Integer add(int i, int j) {Integer result = i+j;return result;}public void doSecond() {
// System.out.println("doSecond()方法");}}
客户端
MyCalculatorCGlib target = new MyCalculatorCGlib();
// System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\zy\\TGB-zgy-2022\\MiMust\\MiDesignDemo\\JAVAtest\\NormalTest1\\demo\\src");MyCalculatorCGlib proxy = new CglibFactory(target).myCglibCreator();Integer result = proxy.add(1,1);
按照上边的思路,说完上边两种代理方式,我们下边来说如何使用这种方式手写事务呢
手写spring中的事务
首先从原理分析,事务的原理就是当sql出现问题的时候,数据回滚为原来的样子,具体他们是通过spring中的DataSourceTransactionManager实现的,在sql执行前,开启事务事务,然后执行sql,如果正常就提交事务,如果不正常就回滚事务。
这就是大概得逻辑,是不是就像上边打印日志一样,在执行方法前进行一些操作,在执行方法后进行一些操作。
public class Main {public static void main(String[] args) {
// TransactionManager transactionManager = new SimpleTransactionManager();
// TransactionProxyFactory factory = new TransactionProxyFactory(transactionManager);
// MyService service = factory.createProxy(new MyService());
// service.doSomething(); // 这个调用将被代理拦截,并处理事务MyService myService = new MyServiceImpl();TransactionManager transactionManager = new SimpleTransactionManager();DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();HikariDataSource dataSource = new HikariDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/zipkin?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai");dataSource.setUsername("root");dataSource.setPassword("123456");dataSourceTransactionManager.setDataSource(dataSource);transactionManager.setDataSourceTransactionManager(dataSourceTransactionManager);// 创建代理对象MyService proxy = TransactionalInvocationHandler.createProxy(myService, transactionManager, MyService.class);// 调用代理对象的方法,这将触发事务管理proxy.doSomething();}
}
@Service
public interface MyService {// @Transactionalpublic void doSomething() ;
}
@Service
public class MyServiceImpl implements MyService {@Overridepublic void doSomething() {try {System.out.println("我真的要执行sql语句");int i = 1/0;} catch (ArithmeticException e) {// 处理算术异常,例如记录日志或返回错误消息throw new RuntimeException("An arithmetic operation has failed", e);}}
}
@Component
public interface TransactionManager {TransactionStatus beginTransaction();void commitTransaction(TransactionStatus transactionStatus);void rollbackTransaction(TransactionStatus transactionStatus);public void setDataSourceTransactionManager(DataSourceTransactionManager dataSourceTransactionManager) ;}
@Component
public class SimpleTransactionManager implements TransactionManager {private boolean isActive = false;@Overridepublic void setDataSourceTransactionManager(DataSourceTransactionManager dataSourceTransactionManager) {this.dataSourceTransactionManager = dataSourceTransactionManager;}private DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();@Overridepublic TransactionStatus beginTransaction() {if (isActive) {throw new IllegalStateException("Transaction already active");}// 模拟事务开始逻辑(在实际应用中,这里会涉及到数据库连接的获取、设置隔离级别等操作)TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());isActive = true;System.out.println("开启事务了");return transaction;}@Overridepublic void commitTransaction(TransactionStatus transactionStatus) {if (!isActive) {throw new IllegalStateException("No active transaction");}// 模拟事务提交逻辑dataSourceTransactionManager.commit(transactionStatus);isActive = false;System.out.println("提交事务了");}@Overridepublic void rollbackTransaction(TransactionStatus transactionStatus) {if (!isActive) {throw new IllegalStateException("No active transaction");}// 模拟事务回滚逻辑dataSourceTransactionManager.rollback(transactionStatus);isActive = false;System.out.println("回滚事务了");}
}
public class TransactionalInvocationHandler implements InvocationHandler {@Autowiredprivate final Object target;@Autowiredprivate final TransactionManager transactionManager;public TransactionalInvocationHandler(Object target, TransactionManager transactionManager) {this.target = target;this.transactionManager = transactionManager;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Exception {TransactionStatus transactionStatus = null;try {transactionStatus = transactionManager.beginTransaction();Object result = method.invoke(target, args);transactionManager.commitTransaction(transactionStatus);return result;} catch (Exception e) {transactionManager.rollbackTransaction(transactionStatus);throw e;}}public static <T> T createProxy(T target, TransactionManager transactionManager, Class<T> interfaceType) {return (T) Proxy.newProxyInstance(interfaceType.getClassLoader(),new Class<?>[]{interfaceType},new TransactionalInvocationHandler(target, transactionManager));}
}
运行结果:
部分自定义注解版aop实现方式
自定义注解 MyTransactionAnnotation
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTransactionAnnotation {
}
MyTransaction类
@Component
@Slf4j
public class MyTransaction {@Autowiredprivate DataSourceTransactionManager dataSourceTransactionManager;/*** 开启事务,并配置默认的事务传播机制* @return*/public TransactionStatus begin(){TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());log.info("事务开启成功");return transaction;}/*** 事务提交* @param transaction*/public void commit(TransactionStatus transaction){log.info("事务提交成功");dataSourceTransactionManager.commit(transaction);}/*** 事务回滚* @param transaction*/public void rollback(TransactionStatus transaction){log.info("事务回滚成功");dataSourceTransactionManager.rollback(transaction);}
}
MyTransactionAop类
@Slf4j
@Aspect
@Component
public class MyTransactionAop {@Autowiredprivate MyTransaction myTransaction;@Around(value = "@annotation(com.transaction.annotation.MyTransactionAnnotation)")public Object myTransactionAop(ProceedingJoinPoint joinPoint){log.info("进入到事务aop, 准备开启事务");TransactionStatus transactionStatus = myTransaction.begin();try {log.info("准备执行目标方法");// 执行目标方法Object object = joinPoint.proceed();log.info("目标方法执行完毕,准备提交");// 执行方法完毕,提交事务,并返回myTransaction.commit(transactionStatus);return object;}catch (Throwable throwable) {log.error("目标函数异常,手动回滚");// 目标函数异常,手动回滚myTransaction.rollback(transactionStatus);return "目标函数异常";}}
}
TestController类
@RestController
@Slf4j
public class TestController {@GetMapping("test_transaction")@MyTransactionAnnotationpublic String testTransaction(@RequestParam(value = "name") String name){// int i = 1/0;return name;}
}
@SpringBootApplication
@EnableTransactionManagement
public class HbzTransactionApplication {public static void main(String[] args) {SpringApplication.run(HbzTransactionApplication.class, args);}
}
application.yml文件
server:port: 9001servlet:context-path: /test
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/zipkin?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456
总结:当我们大概了解这个AOP的思想以后,再去看源码,发现都离不开动态代理,那就是离不开回调反射