介绍
要了解动态代理,首先要知道什么是代理,在笔者看来,代理的功能概括来说就是:在不修改被代理类代码的情况下给这个类包含的方法增加某些功能。
**至于为什么要不修改这个被代理类?**可能是为了满足开闭原则,可能是想把这个被代理类给隐藏起来,等等 。原因可能有很多,但概括起来就是不修改代理类。
要增加什么功能呢?(后文提到的增强指的就是增加功能)
这个就看使用者怎么写了,这个是非常灵活的,常用的就是增加日志、统计方法耗时等
我熟知的动态代理通常有两种,即JDK动态代理与CGLIB动态代理。
笔者最近学习了JDK动态代理,所以编写这个博客输出一下,因为笔者也是初学,了解的不多,尽可能写的详细~
好处是,笔者知道初学者的学习的难点在哪,应该更能帮助初学者理解~
坏处嘛,嘿嘿,如果教错了,那就抱歉啦~
JDK动态代理
笔者前面前面提到过JDK动态代理是基于接口来实现的,具体怎么个实现法,参考下面这张图。
代理类实现了与被代理类相同的接口,那么相应的代理类要实现对应的接口方法。
既然是要增强被代理类某些方法的功能,那么思考一下,代理类实现接口方法时方法中应当包含那些内容?
答案显而易见:实现新增功能的代码 + 调用被代理类对应的方法

比如我想统计一个方法的执行时间,那么伪代码如下
void test (Object[] args){
1. 统计开始时间
2. 调用被代理类的test方法
3. 统计结束时间
4. 计算整体耗时
}
鲁迅曾经说过:光说理论不给代码,那就是在耍流氓(鲁迅:也许我没说过? )
客官稍安勿躁,细想一下要实现如上的功能我们需要解决的两个问题:
- 代理对象怎么创建?
- 增强功能肯定是要写代码的,这个代码写在哪?
代理对象怎么创建
非常非常简单,java.lang.reflect中有一个类Proxy, 这个类中有个静态方法Proxy.newProxyInstance(),通过这个方法我们可以获取某个对象的代理对象。
啪一下就蹦出来个陌生的方法就, 问你怕不怕? 别怕,慢慢来~
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
这个静态方法有三个参数需要提供(这个静态方法还有一个重载方法,我们不需要关注)
ClassLoader loader: 被代理对象的类加载器Class<?>[] interfaces: 被代理对象实现的接口InvocationHandler h:一个InvocationHandler接口的实现类
问:为什么需要被代理对象的类加载器?
答:所谓动态代理,动态的点就在于JVM会帮我们生成代理类的字节码文件并加载,然后实例化,这过程就需要类加载器ClassLoader,为了和被代理对象保持一致,所以就使用被代理对象的类加载器进行加载。
问:为什么需要被代理对象的接口集合?
答:这个接口本质上就是告诉代理对象,哪些方法是我想要增强的。 也就是说,提供的所有接口中的所有方法,就是JVM帮我们创建的代理对象所能代理的方法,也就是我们可以对其进行功能增强的方法。
这也意味着,并非需要把被代理类实现的所有接口传递进去,仅仅需要将包含我们想要增强方法的接口传递进去即可。
如被代理类 Test实现了两个接口,分别是接口A,接口B, 现在我想增强接口A中的方法,这个时候,传递进去的接口集合中仅仅需要接口A。
问:这个InvocationHandler接口是个什么东东?
答:这个就涉及到我们前面提到的第二个问题:新增功能的代码我们要写在哪里?, 答案就是这个InvocationHandler里 ,InvocationHandler接口中只有一个方法需要我们实现,那就是invoke方法,准确的说,我们要新增的代码功能,就是写在这个invoke方法里的。
Object invoke(Object proxy, Method method, Object[] args)
客官先别急,这个方法具体怎么用我们后面会提到,现在我们只需要有一个认知:我们想要增强的功能是写在invoke这个方法里的,因此我们需要创建一个类实现InvocationHandler接口并实现其中的invoke方法,并将这个类当做参数传给newProxyInstance方法
理清了这三个参数,成功调用Proxy.newProxyInstance方法,我们就可以获取到代理类对象。
举例
举个具体的例子:
接口:
public interface JDKTest {
void hello();
String eat(String food);
}
被代理类:
public class JDKTestImpl implements JDKTest{
@Override
public void hello() {
System.out.println("hello");
}
@Override
public String eat(String food) {
return "吃了" + food;
}
}
InvocationHanlder实现类:
package com.zp.myproject.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target){
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName()+"实现了代理增强");
return method.invoke(target,args


3212

被折叠的 条评论
为什么被折叠?



