最近在看Spring的AOP, 发现它是通过动态代理来实现的,就顺便看了一下动态代理的一些例子,来写一写自己的理解。
首先动态代理有两个重要且必须用到的东西:
1. InvocationHandler(接口, 每个动态代理类必须实现这个接口)
2. Proxy(类, 用来动态创建一个代理对象的类)
InvocationHandler接口中有一个invoke方法。在代理实例上处理方法调用并返回结果。当与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
- proxy 正在被代理的对象真实实例
- method 指代该代理对象实例的正在调用的某个方法对象
- args 指代该方法对象接受的参数
Proxy类中有一个newProxyInstance()方法。该方法是用于创建动态代理类和实例的静态方法.返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
下面是一段简易的动态代理机制代码, 一个加减乘除的例子。
首先有一个简单的接口类
public interface ArithmeticCalculator {
public abstract int add(int i, int j); //加
public abstract int sub(int i, int j); //减
public abstract int mul(int i, int j); //乘
public abstract int div(int i, int j); //除
}
第二个类就是接口的实现类了。很简单
public class ArithmeticCalculatorImp implements ArithmeticCalculator{
@Override
public int add(int i, int j) {
int tmp = i+j;
return tmp;
}
@Override
public int sub(int i, int j) {
int tmp = i-j;
return tmp;
}
@Override
public int mul(int i, int j) {
int tmp = i*j;
return tmp;
}
@Override
public int div(int i, int j) {
int tmp = i/j;
return tmp;
}
}
第三个类就是动态代理类了
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class ArithmeticCalculatorProxy {
//要代理的对象
private ArithmeticCalculator target;
public ArithmeticCalculatorProxy(ArithmeticCalculator target0){
this.target = target0;
}
public ArithmeticCalculator getProxy(){
ArithmeticCalculator proxy = null;
//代理对象由哪一个类加载器负责加载
ClassLoader loader = target.getClass().getClassLoader();
//代理对象的类型, 即其中有哪些对象
Class[] interfaces = new Class[]{ArithmeticCalculator.class};
InvocationHandler h = new InvocationHandler() {
/**
* proxy: 正在返回的那个代理对象。 一般情况下, 在invoke 方法中都不使用该对象。会死循环报栈溢出
* method: 正在被调用的方法
* args : 调用方法时, 传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println("The method " + methodName + " begins with " + Arrays.asList(args));
Object result = null;
try {
//前置通知
result = method.invoke(target, args);
//返回通知 可以访问返回值
} catch (Exception e) {
// TODO: handle exception
}
//后置通知
System.out.println("The method " + methodName + " ends with " + result);
return result;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
好了我们来测试一哈。
public class TestProxy {
public static void main(String[] args) {
ArithmeticCalculator target = new ArithmeticCalculatorImp();
ArithmeticCalculator proxy = new ArithmeticCalculatorProxy(target).getProxy();
int result = proxy.add(1, 2);
System.out.println("-- > " + result);
result = proxy.div(4, 2);
System.out.println("-- > " + result);
}
}
结果是:
The method add begins with [1, 2]
The method add ends with 3
– > 3
The method div begins with [4, 2]
The method div ends with 2
– > 2
有同学会问, invoke是什么时候调用的? 这把我问倒(:зゝ∠)了。我不能告诉你我也想过这个问题但是我也不知道, 后来看了很多帖子,才明白下面这个方法Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
做了以下几件事.
(1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy.$Proxy0
类 实现了interfaces的接口,并继承了Proxy类.
(2)实例化$Proxy0
并在构造方法中把BusinessHandler传过去,接着$Proxy0
调用父类Proxy的构造器,为h赋值,如下:
class Proxy{
InvocationHandler h=null;
protected Proxy(InvocationHandler h) {
this.h = h;
}
…
}
$Proxy0
类的部分重点源码如下:
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
**m3 = Class.forName("com.ml.test.Manager").getMethod("modify",
new Class[0]);**
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
} //static
public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}
public final void **modify()** {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
就是在这里调用了invoke方法来实现的。 好像有点乱- -。 下次接着补充吧