这里写目录标题
- 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的思想以后,再去看源码,发现都离不开动态代理,那就是离不开回调反射