动态代理的原理、作用以及实现
做java学习以及开发的小伙伴们对于动态代理这个词一定不陌生,但是到底什么是动态代理,或许解释起来是有些麻烦。这篇文章的目的也是为了能够让大家更加深刻的理解动态代理。
动态代理,代理顾名思义,像工厂和商家之间的商家一样,商家帮工厂出售产品,工厂则负责制作产品,那么代理类也是一样,你写了一个SayHello类了,然后使用代理类去代替你写的SayHello类,执行类中的方法。
或许经过上面的一番描述,大多数小伙伴们会更加疑惑,哎,我明明已经写了SayHello类了,为啥子不直接用它,而是要去使用一个代理呢?怪麻烦的。
对于SayHello类而言,如果需求不变,那么类可能满足功能,但是如果有一天,对于类SayHello类的需求改变了呢?是不是就需要拓展SayHello类了?这时,代理的作用也就显现出来了。这时候因为SayHello类中的方法,是在代理类中由代理类来调用的,所以在不添加源代码的基础上,也可以实现原方法的拓展。
原理如图:
借用一下某位仁兄的图片该图片作者的博客
实现代码如下:
//SayHello接口
interface ISayHello{
void sayHello();
}
//SayHello接口的实现类
class SayHelloImpl implements ISayHello{
@Override
public void sayHello(){
System.out.println("say hello!");
}
}
//测试类,主要用于测试代理,提供程序入口函数main
public class Main{
public static void main(String[] args) throws IllegalArgumentException, ClassNotFoundException{
* SayHello接口变量
* Proxy是java内置的代理对象
* newProxyInstance方法是创建代理对象的方法
* newProxyInstance(
* 该参数代表被代理对象的类加载器
* ClassLoader loader,
* 被代理对象所实现的接口
* Class<?>[] interfaces,
* 实现代理的接口
* InvocationHandler h
* )
* 通过Proxy的newProxyInstance方法产生的对象,就是一个实现了SayHelloImpl类所实现接口的对象(相当于匿名的SayHelloImpl)
ISayHello iSayHello = (ISayHello)Proxy.newProxyInstance(
//被代理类为SayHelloImpl,获取它的类加载器
Class.forName("cn.zzcfirst.SayHelloImpl").getClassLoader(),
//获取被代理类SayHelloImpl所实现的接口
Class.forName("cn.zzcfirst.SayHelloImpl").getInterfaces(),
//创建匿名InvocationHandler对象,重写invoke方法,在代理类调用被代理类的方法时,进入InvocationHandler的invoke方法
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("添加拓展功能");
//利用反射执行SayHelloImpl对象的方法,改invoke与上面的invoke不同
method.invoke(
Class.forName("cn.zzcfirst.SayHelloImpl").newInstance(),args);
System.out.println("添加拓展功能");
//此处返回null是因为我所调用的方法没有返回值
//此处的返回值可以写为(对于方法有返回值)
//return method.invoke(被代理类对象,方法所需参数);
return null;
}
});
//使用代理对象,调用SayHelloImpl类中的方法。
iSayHello.sayHello();
}
}
在上面的例子中,我开始创建了SayHelloImpl类,但是我想为它的sayHello方法添加其他功能,但是又不想改动原有方法,就可以利用动态代理去为其增加新的功能,而且使用动态代理还可以隐藏原有SayHelloImpl类的实现,例如使用上述代理对象,可能功能与原有类相同,但是调用者却不知道原有sayHello。