上一篇讲到到java的代理模式以及java的静态代理的实现方式。静态代理的问题在于需要为每个委托类建立一个代理类,这样不仅耗费大量的精力,也不利于项目的解耦和维护。本篇就要讲讲java的动态代理,动态代理在spring等框架中十分重要,它不仅保留代理模式的优点,也更好地解耦项目,对于代码的复用和维护都是更有优势。
1.动态代理的简单例子
1)委托类接口
//委托类接口
public interface TestService {
void business();
}
2)委托类的实现
//委托类的实现类
public class TestImplement implements TestService{
@Override
public void business() {
try{
System.out.println("do the busniess");
Thread.sleep(200);
}catch (Exception e) {
e.printStackTrace();
}
}
}
3)处理类(和静态代理很大的区别就是处理类更通用)
public class LoggerInvocationHandler implements InvocationHandler {
private Object target;// 目标类
public LoggerInvocationHandler(Object target) {
this.target = target;
}
//这是一个简单的日志处理类,会记录方法的执行时间和耗时
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Long timeStart = System.currentTimeMillis();
System.out.println("-- invoke start---timeStart="+timeStart);
Object result = method.invoke(this.target, args);
System.out.println("-- invoke finish---takes="+(System.currentTimeMillis()-timeStart));//记录方法的调用耗时
return result;
}
}
4)测试代码
TestService target = new TestImplement();
LoggerInvocationHandler myInterceptor = new LoggerInvocationHandler(target);
TestService proxyObj = (TestService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInterceptor);
proxyObj.business();
运行结果:
– invoke start—timeStart=1504015240306
do the busniess
– invoke finish—takes=201
这就是动态代理的一个简单的例子,它能记录方法执行的时间和耗时,并且LoggerInvocationHandler.class是通用的。
2.动态代理的原理
首先我们从入口开始看
TestService proxyObj = (TestService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInterceptor);
点击进入Proxy.newProxyInstance()方法,先看下注释
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler.
*
* <p>{@code Proxy.newProxyInstance} throws
* {@code IllegalArgumentException} for the same reasons that
* {@code Proxy.getProxyClass} does.
*
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
从注释可以看出这个方法,是给指定接口的代理类生成实例。比如我们前面传入的是TestService,那么就是返回TestService的代理类。这就是动态代理和静态代理的区别,静态代理需要我们自己写代理类,而动态代理是动态生成的。
更详细的动态代理原理可以参考 终点的博客
以上的动态代理方式委托类必须是接口,一般称作JDK动态代理。那么委托类如果不是接口该怎么办?这就需要CGLIB等方式