AOP原理之动态代理
- 2019 年 10 月 5 日
- 筆記
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37933685/article/details/81635537
个人博客:https://suveng.github.io/blog/
AOP原理之动态代理
实现AOP的底层是反射机制,其中有两种实现方式:
其一是JDK的动态代理;
其二是基于CGLib的动态代理;
这里用简单的demo来演示两种方式的过程:
基于JDK的动态代理
JDK的动态代理是必须要一个接口来实现,那么现在来创建这个接口:
UserDao.java
** * @author Veng Su [email protected] * @date 2018/8/13 10:52 */ public interface UserDao { public void say(); public void ask(); }
接着我们来创建一个接口的实现类:
UserDaoImpl.java
/** * @author Veng Su [email protected] * @date 2018/8/13 10:52 */ public class UserDaoImpl implements UserDao { public void say() { System.out.println("suveng create say method"); } public void ask() { System.out.println("suven create ask method"); } }
现在接口和实现类都准备好了,我们可以开始实现一个代理类了。
JDKProxy.java
/** * @author Veng Su [email protected] * @date 2018/8/13 10:53 */ // 思路:先把需要代理增强的东西传进来,接着增强之后再把新的返回出去 public class JDKProxy { //新建方法返回增强类 public static UserDao getUserDaoProxy(final UserDao userDao){ //1.获取类加载器 ClassLoader userDaoClassLoader=userDao.getClass().getClassLoader(); //2. 获取接口 Class<?>[] interfaces=userDao.getClass().getInterfaces(); //3.创建代理类 UserDao userDaoProxy= (UserDao) Proxy.newProxyInstance(userDaoClassLoader, interfaces, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //开始写增强内容 if (method.getName().equals("say")){ System.out.println("这是增强内容"); } return method.invoke(userDao,args); } }); return userDaoProxy; } }
好了,到这里我们的代理已经创建好了,主要是使用了Proxy.newProxyInstance()这个方法创建一个代理类,然后把这个代理类返回。接下来我们就可以用JDKProxy来创建一个被代理后的UserDao这个增强类。
为什么需要接口? 因为Proxy.newProxyInstance()这个方法的参数需要传入一个接口的参数,所以用JDK创建动态代理需要一个接口类。
接下来我们来测试一下:
@org.junit.Test public void testJDKProxy(){ UserDao userDao= JDKProxy.getUserDaoProxy(new UserDaoImpl()); userDao.say(); }
运行结果如下图所示:

基于CGLib的动态代理:
CGLIB(Code Generation Library)是一个开源项目! 是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。 摘自百度百科
JDK的动态代理用起来非常简单,但它有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的继承的类,该怎么办?
现在我们可以使用CGLIB包
首先我们需要准备一个类,随便一个类。那我们复用UserDaoImpl的类,把它改造一下
User.java
/** * @author Veng Su [email protected] * @date 2018/8/13 10:52 */ public class User { public void say() { System.out.println("suveng create say method"); } public void ask() { System.out.println("suven create ask method"); } }
接下我们创建一个代理类;
CGLibProxy.java
/** * author: Veng Su * email: [email protected] * date: 2018/8/13 14:33 */ public class CGLibProxy { public static User getProxy(){ //1.创建CGLib核心类 Enhancer enhancer=new Enhancer(); //2. 制定需要代理的类,也就是父类 enhancer.setSuperclass(User.class); //3. 设置回调函数 enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if (method.getName().equals("say")){ System.out.println("我是增强内容"); } return methodProxy.invokeSuper(o,objects); } }); //4. 生成代理对象 User userDaoProxy= (User) enhancer.create(); return userDaoProxy; } }
这就实现了一个CGLib代理类。
注意:methodProxy.invokeSuper(o,objects);这里要调用的父类的方法,如果调用methodProxy.invoke(o,objects);会无线调用导致堆栈溢出。
测试:
@Test public void testCGLibProxy(){ User user= CGLibProxy.getProxy(); user.say(); }
运行结构如下图所示:

码云源码地址
https://gitee.com/suwenguang/SpringFrameworkDemo
总结
其实学习动态代理还要很长的路要走,这里只是简单的实现。目前写业务的我理解到这里就OK,够用了,如果还有需要深入理解动态的话,建议去把JDK的反射包的源码和CGLib的源码了解一遍。加油!