学习笔记Spring中的动态代理
Posted 棉花糖灬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习笔记Spring中的动态代理相关的知识,希望对你有一定的参考价值。
本文参考了文章Spring AOP动态代理的实现方式和文章Spring中的动态代理。
1. 动态代理的两种实现方式
(1) 两种动态代理
Spring中的AOP(面向切面编程)是基于动态代理技术实现的,而动态代理是基于反射设计的。动态代理的实现方式有2种:JDK动态代理和CGLIB动态代理。
- JDK动态代理:通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口,核心是InvocationHandler接口和Proxy类
- CGLIB(Code Generation Library)动态代理:CGLIB是一个代码生成类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的
(2) 注意事项
-
如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
-
如果目标对象实现了接口,也可以强制使用CGLIB实现AOP
-
如果目标对象没有实现接口,必须采用CGLIB的动态代理,spring会自动在两种模式之间转换
-
不管哪一种方式都不能用private和final做修饰词
2. 动态代理实例
假设现在有一个addUser方法,它会往数据库中添加一条记录,现在要通过动态代理对其做增加,在该方法执行前后分别打印一条日志。本节只把两种动态代理共用的部分创建出来。
(1) 创建UserService接口类
public interface UserService
// 模拟添加用户的方法
public void addUser();
(2) 创建UserServiceImpl接口实现类
public class UserServiceImpl implements UserService
// 模拟添加用户的方法
@Override
public void addUser()
System.out.println("模拟添加用户");
3. 基于JDK的动态代理
(1) 创建JDK动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class MyProxy
public static UserService getJDKProxy(UserService service)
/*
* Proxy.newProxyInstance的参数有三个:
* 目标对象的类加载器
* 目标对象的接口
* 代理对象的执行处理器
* */
UserService userService = (UserService)Proxy.newProxyInstance(service.getClass().getClassLoader(),
service.getClass().getInterfaces(),
new InvocationHandler()
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
System.out.println("addUser()方法执行前打印日志");
// 调用原方法
Object result = method.invoke(service, args);
System.out.println("addUser()方法执行后打印日志");
return result;
);
return userService;
(2) 编写测试方法
import org.junit.jupiter.api.Test;
public class ProxyTest
@Test
public void JDKProxyTest()
// 创建目标对象
UserService userService = new UserServiceImpl();
// 生成代理对象
UserService proxy = MyProxy.getJDKProxy(userService);
// 调用目标对象方法
userService.addUser();
System.out.println("=======================================");
// 调用代理对象方法
proxy.addUser();
(3) 运行结果
模拟添加用户
=======================================
addUser()方法执行前打印日志
模拟添加用户
addUser()方法执行后打印日志
4. 基于CGLIB的动态代理
(1) 创建CGLIB动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.apache.catalina.User;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class MyProxy
public static UserService getGCLIBProxy(UserService service)
// 创建增强器
Enhancer enhancer = new Enhancer();
// 设置需要增强的类的对象
enhancer.setSuperclass(service.getClass());
// 设置回调方法
enhancer.setCallback(new MethodInterceptor()
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable
System.out.println("addUser()方法执行前打印日志");
// 调用原方法
Object result = methodProxy.invokeSuper(o, args);
System.out.println("addUser()方法执行后打印日志");
return result;
);
UserService userService = (UserService)enhancer.create();
return userService;
(2) 编写测试方法
import org.junit.jupiter.api.Test;
public class ProxyTest
@Test
public void CGLIBProxyTest()
// 创建目标对象
UserService userService = new UserServiceImpl();
// 生成代理对象
UserService proxy = MyProxy.getGCLIBProxy(userService);
// 调用目标对象方法
userService.addUser();
System.out.println("=======================================");
// 调用代理对象方法
proxy.addUser();
其输出和JDKProxy的输出相同
以上是关于学习笔记Spring中的动态代理的主要内容,如果未能解决你的问题,请参考以下文章
Spring5学习笔记 — “Spring AOP底层原理(动态代理)”