代理模式:
定义:代理模式是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个真实对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。Java动态代理实例:
真实对象接口: public interface HelloInterface {
public void say(String s);
}
真实对象:
public class Hello implements HelloInterface{
public void say(String s) {
System.out.println(s);
}
}
代理处理类:
public class MyInvoke implements InvocationHandler {
private Object obj;
public MyInvoke(Object obj){
this.obj=obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("代理前执行");
System.out.println("Method:" + method);
method.invoke(obj, args);
System.out.println("代理执行后");
return null;
}
}
测试用例:
public class Test {
public static void main(String[] args) {
HelloInterface hello = new Hello();
MyInvoke my = new MyInvoke(hello);
// Hello h=(Hello)Proxy.getProxyClass(Hello.class.getClassLoader(), new Class[]{Hello.class},my);
HelloInterface h = (HelloInterface) Proxy.newProxyInstance(my.getClass().getClassLoader(), hello.getClass().getInterfaces(), my);
System.out.println(h);
h.say("hello");
}
}
输出结果:
代理前执行Method:public
代理执行后
null
代理前执行
Method:public abstract void 代理.HelloInterface.say(
hello
代理执行后
结果分析:
测试用例中执行代码System.out.println(h)时,由于使用了代理对象h,此时先执行(HelloInterface) Proxy.newProxyInstance(my.getClass().getClassLoader(), hello.getClass().getInterfaces(), my);,执行过后h此为空对象。再自动调用了代理处理对象my中的invoke方法,由于此时传入的invoke方法的入参的代理对象proxy为空,所以执行过后再执行System.out.println(h),所以输出null;
执行第八行h.say("hello");时,此时代理对象不是空值,所以可以正常执行。
代码说明:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentExceptionloader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,这个参数可以和第一个参数结合起来产生一个实现此接口对象的代理对象,这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上,会执行此对象的invoke方法
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指代代理类实例
method: 指代的是我们所要调用真实对象的某个方法的Method对象
args: 指代的是调用真实对象某个方法时接受的参数
源码分析:
Proxy 静态方法 newProxyInstancepublic static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
throws IllegalArgumentException {
// 检查 h 不为空,否则抛异常
if (h == null) {
throw new NullPointerException();
}
// 获得与制定类装载器和一组接口相关的代理类类型对象
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, interfaces);
// 通过反射获取构造函数对象并生成代理类实例
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
SecurityManager sm = System.getSecurityManager();
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
return newInstance(cons, ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}
总结:
静态代理模式由于代码是写死的,在业务变动时,代码改动很大,对于项目开发非常不利。动态代理由于使用了Java的反射,所以代码在业务变化时,不需要改动,Spring中的AOP就是采用了动态代理的实现方式。动态代理实现得需要两步:
第一步:实现InvocationHandler接口,并且invoke方法中必须含有真实对象的引用
第二步:Proxy.newProxyInstance()方法,第一个是类加载器,第二个必须是实际对象的接口数组,这样才能反射出来的对象有所包含接口数组的方法,第三个对象必须是代理处理类实例,这样才能在代理对象运行方法时,执行代理处理类的invoke方法。
毕业不到一年的Java菜鸟,有什么错误,请多多指教,共同进步