对于Sbring框架中的一些部分,类似于AOP、RMI均存在使用代理机制执行方法的思想,代理机制实质上是通过反射机制得到另一个类的方法以及对象,不需要通过使用方法所在类的对象来调用此,且对于之前只能执行然后返回结果的方法进行处理,使得我们可以在方法执行前后进行相关操作,类似于取出或改变参数、得到结果以及修改结果。
代理机制基于反射机制,由反射得到类的对象以及方法名称及参数。然后使用Proxy类,返回结果。代理机制的实现存在两种方案,第一种是JDKProxy,一种是CGLibProxy。二者的区别在与实现方式的不同,得到的代理对象不同,JDKProxy是使用接口来实现代理,换言之使用JDKProxy必须使用接口才可以实现,代理对象必须为一个接口的对象。而CGLibProxy则不需要接口,它的原理是使用继承,以给定对象的类作为基类,得到一个子类的实例化对象,从而调用父类的方法。但是使用CGLibProxy时必须保证他所代理的对象存在无参构造,因为在设置父类时使用的是无参构造的方法。
最重要的一点是代理机制依然存在对于方法调用的权限!private修饰的方法均不能被代理机制调用。
具体实现过程如下:
JDKProxy的简单实现:
public static <T> T getProxy(T object) {
Class<?> clazz = object.getClass();
Class<?>[] interfaces = clazz.getInterfaces();
ClassLoader classLoader = clazz.getClassLoader();
return (T) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行方法前......");
Object result = method.invoke(object, args);
System.out.println("执行方法后......");
return result;
}
});
}
上面就是JDK代理机制的完整实现,传递进来一个接口类的实现类的对象,通过反射机制得到这个对象所属类的所有接口,最终得到一个接口类型的对象,使用此对象来调用方法,示例如下:
ClassOneImp one = new ClassOneImp();
ClassOne proxy = JDKProxy.getProxy(one);
int result = proxy.doOne(2, 4);
System.out.println("result: " + result);
结果如下:
可以看到我们在方法执行前后都可以进行处理,达到了我们使用代理机制的目的。
CGLibProxy的简单实现:
对于CGLibProxy我们需要提供一个cglib-nodep-2.1.3.jar包来得到一个Enhancer类的对象,以及他的一系列方法来实现代理机制。
如下:
public static <T> T getProxy(T object) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(object.getClass());
enhancer.setCallback(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行方法前......");
Object result = method.invoke(object, args);
System.out.println("执行方法后......");
return result;
}
});
return (T) enhancer.create();
}
JDK代理机制使用了继承的思想,实现对象的代理。结果与JDK代理机制相差不大,测试如下:
ClassTwo two = new ClassTwo(2);
int result = CGLibProxy.getProxy(two).doTwo();
System.out.println(result);
对于代理机制这里只是简单实现,在之后很多框架学习中都会再次使用到,它对于方法参数与结果的获取与修改也将会派上大用场。