本文不涉及静态代理,只涉及动态代理,本人见过将动态代理讲的比较好的文章在底部,有兴趣的读者可以移步。
老步骤:
1.什么是动态代理?
通俗的讲,动态代理就是创建一个类的代理对象,当需要访问这个类的某些方法时,可以通过调用代理对象的同名方法,而真正返回的却是这个被代理类所实现的方法。
2.为什么需要动态代理?
a.设计模式中有一个设计原则是
开闭原则
,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强。
b.我们在使用RPC框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现。
c.Spring的AOP机制就是采用动态代理的机制来实现切面编程。[1]
3.怎么实现动态代理?
想要实现动态代理,需要解决两个问题
(1)如何根据被加载到内存中的被代理类,动态地创建代理类及其对象;
(2)当通过代理类的对象调用方法时,如何动态的调用被代理类中的同名方法;
其实直接以实例来说明是最好的,下面以人和超人为例来讲解:
(1)先创建一个接口,里面有两个抽象方法
interface Human {
String eat(String food);
String word();
}
(2)某个类实现这个接口
class SuperMan implements Human{
@Override
public String eat(String food) {
return "超人最爱吃:" + food;
}
@Override
public String word() {
return "超人专门打怪兽";
}
}
(3)创建一个专门生成代理类的工厂类
PS:学习动态代理之前一定要理解Java反射机制,不然很多地方没法弄懂
class HumanProxyFactory {
/**
* 传入被代理类,返回一个代理类对象
* @param obj
* @return
*/
public static Object createProxy(Object obj) {
MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
myInvocationHandler.bind(obj);
Object proxyInstance = Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), myInvocationHandler);
return proxyInstance;
}
}
上面最关键的行在于createProxy
方法的第四行,也就是如何生成一个代理类的对象(ProxyInstance),这里使用了Java API自带的一个类java.lang.reflect.Proxy
,有兴趣的同学的可以直接看JDK的源代码,本人也没看过。Proxy类中存在一个专门创建代理类的函数newProxyInstance
,这里面有三个参数,分别是被代理类的类加载器,被代理类实现的接口,以及一个实现了InvocationHandler
接口的对象,前两个参数只要掌握了反射就能理解,重点在于第三个参数,所以下面需要自己写一个类来实现InvocationHandler
接口。
(4)实现InvocationHandler
接口
/**
* 自己实现一个InvocationHandler接口,当代理类调用自己的方法时,实现的却是被代理类的方法
*/
class MyInvocationHandler implements InvocationHandler {
Object obj;
public void bind(Object obj) {
this.obj = obj;
}
/**
* 传入的是代理类对象,代理类对象的方法,以及该方法中的参数数组
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/* 这里的返回值,实际上是被代理类调用此方法的返回值,可以为null */
Object o = method.invoke(obj, args);
return o;
}
}
(5)在测试类中检验结果
public class ProxyTest {
public static void main(String[] args) {
Human proxy = (Human) HumanProxyFactory.createProxy(new SuperMan());
String s = proxy.eat("牛排");
System.out.println(s);
}
}
结果如下:
以上就是动态代理的基本原理