所谓代理,又分为静态代理和动态代理两种。在介绍动态代理之前,我们先了解下在Java中静态代理的使用方式和局限性。
假设当前我们有一个功能接口,需要通过代理类来调用该功能接口的实现类。我们可以使用静态代理调用的方式进行处理,在代理中可以执行额外的处理代码(如日志打印、执行时间的统计等等),代码如下:
/** * 功能接口 */interface Duck { void info(); void say();}/** * 功能接口实现类 */class RealDuck implements Duck { @Override public void info() { System.out.println("鸭子"); } @Override public void say() { System.out.println("我是一只鸭子"); }}/** * 代理类 */class DuckProxy implements Duck { private Duck duck; public DuckProxy(Duck duck) { this.duck = duck; } @Override public void info() { System.out.println("调用前--->"); duck.info(); System.out.println("调用后--->"); } @Override public void say() { System.out.println("调用前--->"); duck.say(); System.out.println("调用后--->"); }}public class TestStaticProxy { public static void main(String[] args) { // 创建被代理类对象 Duck realDuck = new RealDuck(); // 创建代理类对象,将通过该对象进行被代理类的调用 Duck duckProxy = new DuckProxy(realDuck); // 调用代理类对象的方法,转而调用被代理类的方法 duckProxy.info(); // 同上 duckProxy.say(); }}
以上,我们实现了一个静态代理。其存在一个弊端:假设要增加另外的一个接口则需要一个与之配对的另一个代理,这样会导致类的爆炸。。。此时我们可以引入动态代理来规避此类问题,减少代码的冗余
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * @author luhuancheng * @since 2018/2/8 23:15 */interface Human { void info(); void say();}/** * 被代理类 */class SuperMan implements Human { @Override public void info() { System.out.println("超人来了......"); } @Override public void say() { System.out.println("我是超人......"); }}/** * 日志工具 */class LogUtils { public static void before() { System.out.println("调用前时间" + System.currentTimeMillis()); } public static void after() { System.out.println("调用后时间" + System.currentTimeMillis()); }}class MyInvocationHandler implements InvocationHandler { private Object object; public void setObject(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { LogUtils.before(); Object result = method.invoke(object, args); LogUtils.after(); return result; }}class MyProxy { public static Object getProxy(Object object) { MyInvocationHandler handler = new MyInvocationHandler(); handler.setObject(object); // 返回一个代理类对象。该代理类实现了与对象object一致的接口。 // 并且在调用该代理类对象的相关方法时,转而调用其 invoke(Object proxy, Method method, Object[] args)方法; // 实现了对模版代码的重用,并且避免了代理类与被代理类必须成对存在的弊端 return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), handler); }}public class TestDynamicProxy { public static void main(String[] args) { SuperMan superMan = new SuperMan(); Object object = MyProxy.getProxy(superMan); Human man = (Human) object; man.info(); man.say(); }}