这里写目录标题
- 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 一种是cglib
public static Calculator getCalculator( final Calculator 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));
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{
@Override
public 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;
//333333
Integer result = i+j;
return result;
}
@Override
public Integer div(Integer i, Integer j) {
System.out.println("div方法开始执行:参数是"+i+"___"+j);
Integer result = i/j;
System.out.println("div方法结束,执行结果是"+result);
return result;
}
@Override
public Integer mul(Integer i, Integer j) {
System.out.println("mul方法开始执行:参数是"+i+"___"+j);
int result = i*j;
System.out.println("mul方法结束,执行结果是"+result);
return result;
}
@Override
public 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) {
}
@Override
public 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 {
// @Transactional
public void doSomething() ;
}
@Service
public class MyServiceImpl implements MyService {
@Override
public 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;
@Override
public void setDataSourceTransactionManager(DataSourceTransactionManager dataSourceTransactionManager) {
this.dataSourceTransactionManager = dataSourceTransactionManager;
}
private DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
@Override
public TransactionStatus beginTransaction() {
if (isActive) {
throw new IllegalStateException("Transaction already active");
}
// 模拟事务开始逻辑(在实际应用中,这里会涉及到数据库连接的获取、设置隔离级别等操作)
TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
isActive = true;
System.out.println("开启事务了");
return transaction;
}
@Override
public void commitTransaction(TransactionStatus transactionStatus) {
if (!isActive) {
throw new IllegalStateException("No active transaction");
}
// 模拟事务提交逻辑
dataSourceTransactionManager.commit(transactionStatus);
isActive = false;
System.out.println("提交事务了");
}
@Override
public 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 {
@Autowired
private final Object target;
@Autowired
private final TransactionManager transactionManager;
public TransactionalInvocationHandler(Object target, TransactionManager transactionManager) {
this.target = target;
this.transactionManager = transactionManager;
}
@Override
public 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 {
@Autowired
private 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 {
@Autowired
private 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")
@MyTransactionAnnotation
public 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: 9001
servlet:
context-path: /test
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/zipkin?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
总结:当我们大概了解这个AOP的思想以后,再去看源码,发现都离不开动态代理,那就是离不开回调反射