第一种讲解:
Jdk提供了invocationHandler接口和Proxy类,借助这两个工具可以实现动态代理。
invocationHandler接口上场:
//Object proxy:被代理的对象
//Method method:要调用的方法
//Object[] args:方法调用时所需要参数
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
接口里只有一个方法invoke,这个方法非常重要,先混个脸熟,稍后解释。
Proxy类上场,它里面有一个很重要的方法 newProxyInstance:
//CLassLoader loader:被代理对象的类加载器
//Class<?> interfaces:被代理类全部的接口
//InvocationHandler h:实现InvocationHandler接口的对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
调用Proxy的newProxyInstance方法可以生成代理对象
实现一个类,该类用来创建代理对象,它实现了InvocationHandler接口:
public class ProxyHandler implements InvocationHandler {
private Object targetObject;//被代理的对象
//将被代理的对象传入获得它的类加载器和实现接口作为Proxy.newProxyInstance方法的参数。
public Object newProxyInstance(Object targetObject){
this.targetObject = targetObject;
//targetObject.getClass().getClassLoader():被代理对象的类加载器
//targetObject.getClass().getInterfaces():被代理对象的实现接口
//this 当前对象,该对象实现了InvocationHandler接口所以有invoke方法,通过invoke方法可以调用被代理对象的方法
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
}
//该方法在代理对象调用方法时调用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("记录日志");
return method.invoke(targetObject,args);
}
}
被代理的对象targetObject可以通过方法参数传进来:
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
我们重点来分析一下这段代码:
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
动态代理对象就是通过调用这段代码被创建并返回的。
方法有三个参数:
第一个参数:
targetObject.getClass().getClassLoader():targetObject对象的类加载器。
第二个参数:
targetObject.getClass().getInterfaces():targetObject对象的所有接口
第三个参数:
this:也就是当前对象即实现了InvocationHandler接口的类的对象,在调用方法时会调用它的invoke方法。
再来看一下这段代码:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在这里可以通过判断方法名来决定执行什么功能
System.out.println("记录日志");
//调用被代理对象的方法
return method.invoke(targetObject, args);
}
这个方法就是生成的代理类中的方法被调用时会去自动调用的方法,可以看到在这个方法中调用了被代理对象的方法: method.invoke(targetObject, args);
我们可以在这里加上需要的业务逻辑,比如调用方法前记录日志功能.
见证奇迹的时刻到了:
public class Test {
public static void main(String[] args){
ProxyHandler proxyHandler=new ProxyHandler();
IPrinter printer=(IPrinter) proxyHandler.newProxyInstance(new Printer());
printer.print();
}
}
打印结果:
记录日志
打印
当执行printer.print();时会自动调用invoke方法,很多初学者不理解为什么能调用这个方法,回忆一下创建代理对象的时候是通过
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
来创建的,方法的第三个参数this是实现了 InvocationHandler 接口的对象, InvocationHandler 接口有invoke方法。现在有点思路了吧~
将被代理的对象作为参数传入就可以执行里面的任意方法,所有的方法调用都通过invoke来完成。不用对每个方法进行处理,动态代理是不是很简洁。
代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,通俗的来讲代理模式就是我们生活中常见的中介,动态代理和静态代理的区别在于静态代理我们需要手动的去实现目标对象的代理类,而动态代理可以在运行期间动态的生成代理类。
作者:夏昊
链接:https://www.zhihu.com/question/20794107/answer/811250346
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
第二种讲解
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
作者:ZeaTalk
链接:https://www.zhihu.com/question/20794107/answer/23330381
最近正好在看,特来挖坟。
关于动态代理设计模式很可能题主就在不知不觉中使用了,例如Spring中的AOP,Struts2中的拦截器等。
先来看静态代理模式代码:
package test;
public interface Subject
{
public void doSomething();
}
package test;
public class RealSubject implements Subject
{
public void doSomething()
{
System.out.println( "call doSomething()" );
}
}
package test;
public class SubjectProxy implements Subject
{
Subject subimpl = new RealSubject();
public void doSomething()
{
subimpl.doSomething();
}
}
package test;
public class TestProxy
{
public static void main(String args[])
{
Subject sub = new SubjectProxy();
sub.doSomething();
}
}
刚开始我会觉得SubjectProxy定义出来纯属多余,直接实例化实现类完成操作不就结了吗?后来随着业务庞大,你就会知道,实现proxy类对真实类的封装对于粒度的控制有着重要的意义。但是静态代理这个模式本身有个大问题,如果类方法数量越来越多的时候,代理类的代码量是十分庞大的。所以引入动态代理来解决此类问题。
先看代码:
package test;
public interface Subject
{
public void doSomething();
}
package test;
public class RealSubject implements Subject
{
public void doSomething()
{
System.out.println( "call doSomething()" );
}
}
package test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyHandler implements InvocationHandler
{
private Object tar;
//绑定委托对象,并返回代理类
public Object bind(Object tar)
{
this.tar = tar;
//绑定该类实现的所有接口,取得代理类
return Proxy.newProxyInstance(tar.getClass().getClassLoader(),
tar.getClass().getInterfaces(),
this);
}
public Object invoke(Object proxy , Method method , Object[] args)throws Throwable
{
Object result = null;
//这里就可以进行所谓的AOP编程了
//在调用具体函数方法前,执行功能处理
result = method.invoke(tar,args);
//在调用具体函数方法后,执行功能处理
return result;
}
}
public class TestProxy
{
public static void main(String args[])
{
ProxyHandler proxy = new ProxyHandler();
//绑定该类实现的所有接口
Subject sub = (Subject) proxy.bind(new RealSubject());
sub.doSomething();
}
}
看完代码,现在我来回答,动态代理的作用是什么:
- Proxy类的代码量被固定下来,不会因为业务的逐渐庞大而庞大;
- 可以实现AOP编程,实际上静态代理也可以实现,总的来说,AOP可以算作是代理模式的一个典型应用;
- 解耦,通过参数就可以判断真实类,不需要事先实例化,更加灵活多变。