a)
什么是Proxy Design Pattern?
在说Java动态代理之前,先复习下代理模式(Proxy Pattern)。如下类图所示:
一旦有了代理,它将代替被代理类去参与程序的业务逻辑。代理和被代理都实现了同样的接口,并且代理类会hold一个被代理类,这样当在代理上调用业务方法的时候,代理可以把真正的核心逻辑仍然让被代理类去完成。
b)
Java的动态代理(Dynamic Proxy)
是怎么回事?
简单说动态代理是Java提供的一种机制,它是在运行的时候基于一个或多个接口(Interface)创造出实现该接口或多个接口的代理类实例。值得再加强一提的是,Dynamic Proxy是基于接口
的,它能为单个或者多个接口创建一个代理类实例。这个机制主要有两个类参与实现:
- java.lang.reflect.Proxy
- java.lang.reflect.InvocationHandler
1.
java.lang.reflect.Proxy
Proxy是一个实现了Serializable的具体类,它里面的方法主要就是用来根据必要的条件创建出指定接口或者是多个接口的代理类。下面就是其提供的常用的public方法:
private final static Class[] constructorParams =
{ InvocationHandler.class };
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
/*
* Look up or generate the designated proxy class.
*/
Class cl = getProxyClass(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
}
}
从这个方法的参数可以知道,要成功创建一个Proxy Instance,要具备以下条件:
1) ClassLoader
,一般使用当前对象的就可以了
2) Class<?>[]
,接口数组,这就是生成的代理类最后实现的接口
3) InvocationHandler
,配备一个实现了这个接口的类实例是一定
需要的,当在生成好的代理类实例上调用接口中的方法时,这些方法调用会被派发到这个InvocationHandler中去,下面将分作一节详细说它。
2.
java.lang.reflect.InvocationHandler
这是一个接口,里面只有一个方法如下:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
上面说到了,当在动态产生好的代理类实例上调用接口方法时,这个方法调用会被转到这个invoke方法里面来,就连Object中的hashCode, equal还有toString方法也躲不过,对它们的调用会被通通转到invoke里面来。这样在实际使用中,我们让InvocationHandler的实现类hold住一个被代理的类,然后就可以在invoke的里面对被代理的类方法进行所谓的拦截了,即使在被代理类的业务方法调用前或后另作一些其他的工作了。
这里结合最开始的类图给出代码举例。
首先是Client
public class Client {
public static void main(String[] args) {
Subject concreteSubject = new ConcreteSubject();
Class[] interfaceNeedsImp = new Class[] {Subject.class};
InvocationHandler handler = new SubjectProxy(concreteSubject);
ClassLoader cl = Subject.class.getClassLoader();
//Here the type casting you must use the interface
//if using the concrete class, shxt will happen cause
//the returned instance is the instance of the generated proxy class
Subject proxySubject = (Subject) java.lang.reflect.Proxy.newProxyInstance(cl,
interfaceNeedsImp,
handler);
proxySubject.greet();
System.out.println();
proxySubject.request();
}
}
值得一提的是注意转型那里,要用接口来转,用具体类转要出错。
Subject接口
//弄了两个方法表明是业务方法
public interface Subject {
Subject request();
void greet();
}
ConcreteSubject的代码
public class ConcreteSubject implements Subject {
public void greet() {
System.out.println(" greet() of ConcreteSubject invoked");
}
public Subject request() {
System.out.println(" request() of ConcreteSubject invoked");
return this;
}
}
SubjectProxy的代码
public class SubjectProxy implements InvocationHandler {
private Subject aConcreteSubject;
public SubjectProxy(Subject target) {
aConcreteSubject = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("Proxy prints this before " + method.getName()
+ ".() of ConcreteSubject");
Object o = method.invoke(aConcreteSubject, args);
if (o instanceof Subject) {
System.out.println("Proxy prints this after concrete " + method.getName()
+ ".() of ConcreteSubject");
return proxy;
}
System.out.println("Proxy prints this after concrete" + method.getName()
+ ".() of ConcreteSubject");
return o;
}
}
这里这个类和类图中传统的Proxy Pattern有出入了,这个SubjectProxy没有去实现Subject接口,而是实现了InvocationHandler。在Client类中,Proxy会把SubjectProxy和它需要实现的Subject做绑定的,也就是下面几句Client的代码,小小的重复贴一下之前在Client中的几行关键代码如下:
Subject proxySubject = (Subject) java.lang.reflect.Proxy.newProxyInstance(cl,
interfaceNeedsImp, //一群等待被实现的"接口"同志们
handler);
这差不多就是Java的动态代理机制了。下面是程序的输出,一目了然,ConcreteSubject的方法都被拦截了:
Proxy prints this before greet.() of ConcreteSubject
greet() of ConcreteSubject invoked
Proxy prints this after concretegreet.() of ConcreteSubject
Proxy prints this before request.() of ConcreteSubject
request() of ConcreteSubject invoked
Proxy prints this after concrete request.() of ConcreteSubject
额外需要注意的:
1. 网上有好多人在讨论InvocationHandler中invoke方法的第一个参数proxy怎么用?
答案是有时候接口方法会把当前接口引用作为返回值返回,参考上面例子中的request()业务方法。它返回了Subject引用,如果在代理中拦截到该方法不做特别处理的话,返回出去的就是ConcerteSubject的引用,若想继续使用SubjectProxy到底,就可以判断一下返回参数proxy。所以在上面例子里的SubjectProxy中有下面的代码段:
if (o instanceof Subject) {
System.out.println("Proxy prints this after concrete " + method.getName()
+ ".() of ConcreteSubject");
return proxy;
}
2.
java.lang.reflect.Proxy
的源代码写得挺精彩。它使用到了loaderToCache的一个WeakHashMap,使程序在做缓存的同时不会泄漏内存,值得学习。
3. 当代理需要实现多个接口,并且多个接口中有些方法duplicate了,那顺序会起决定作用,在Class[]中最前面的那个接口会被认为是方法的提供者!
- 大小: 19.5 KB
分享到:
相关推荐
总结来说,Java动态代理提供了一种在运行时创建具有额外功能的对象的方式,它通过`InvocationHandler`控制方法调用的逻辑,`Proxy`类则负责生成符合指定接口的代理对象。通过理解和掌握这些知识点,我们可以灵活地...
总结来说,Java动态代理为开发者提供了灵活的代码扩展机制,可以根据实际需求选择适合的实现方式。JDK动态代理适用于接口丰富的场景,而Cglib更适合对性能有较高要求或者目标对象无法实现接口的情况。
总结来说,Java动态代理提供了一种在不修改原有代码的情况下,对已有类进行扩展的手段。它可以用于添加如日志、性能监控、事务处理等功能,极大地提高了代码的灵活性和可维护性。在实际开发中,如Spring AOP框架就...
### Java动态代理实现AOP详解 #### 一、引言 随着软件开发复杂度的提升,传统的面向对象编程(OOP)已经难以满足现代软件工程的需求。为了更好地管理跨切面的关注点,如日志记录、性能监控、安全控制等,面向切面...
总结来说,Java动态代理是一种强大的工具,它允许我们在运行时动态创建代理类,实现对已有接口的方法增强。通过`Proxy`和`InvocationHandler`,我们可以轻松地插入如日志、事务管理等通用功能,而无需修改原有代码,...
总结Java 动态代理为我们提供了在运行时创建代理对象的能力,减少了代码的冗余,提高了代码的灵活性。JDK 动态代理适用于目标类实现接口的情况,而 CGLIB 则可以处理无接口的类。了解和掌握动态代理技术对于深入理解...
总结来说,Java的静态代理适用于代理类较少且代理逻辑相对固定的情况,而动态代理则在代理类数量不确定或者代理逻辑可能变化时更为合适。两者都可以实现为原始对象添加附加功能,但动态代理在灵活性和代码维护方面...
总结一下,Java动态代理机制提供了在运行时创建代理对象的能力,允许我们对已有的接口或类的行为进行扩展。`InvocationHandler`接口提供了自定义方法调用行为的入口,而`Proxy`类则负责生成动态代理对象。这种设计...
Java动态代理是Java编程中一个重要的特性,它允许我们在运行时创建代理对象,这些代理对象可以作为原有...希望这个总结能对你有所帮助,无论是学习还是工作中,理解并掌握动态代理都能让你在处理复杂系统时游刃有余。
总结来说,Java的静态代理和动态代理都能实现对目标对象的代理,但静态代理需要手动创建代理类,适用于目标类数量固定且已知的情况;而动态代理则在运行时生成代理类,更加灵活,尤其适合处理数量不确定或动态变化的...
### Java中的动态代理知识点解析 #### 一、动态代理概念 在Java中,动态代理是一种设计模式,它允许我们创建一个对象来代表另一个对象。这种模式通常用于在不修改目标对象的情况下,为对象添加额外的功能或者行为...
总结来说,Java动态代理机制提供了在运行时动态创建具有指定接口的代理对象的能力,使得我们可以在不修改源代码的情况下,对目标对象进行功能增强。这在很多场景下都非常有用,比如AOP(面向切面编程)、事件监听、...
总结,Java JDK的动态代理为我们提供了一种灵活的方式,可以在不修改原始代码的情况下扩展或修改对象的行为。通过创建代理对象,我们可以方便地实现如日志记录、事务管理、权限验证等附加功能,极大地提高了代码的可...
总结来说,Java动态代理为我们提供了一种灵活的方式,可以在运行时扩展或改变对象的行为,无需修改原有代码。JDK动态代理适用于目标对象实现了接口的情况,而CGLIB则适用于未实现接口的目标类。理解并熟练运用这两种...
本文将深入探讨两种主要的Java代理实现:JDK动态代理和CGLIB代理。 一、JDK动态代理 JDK动态代理基于接口实现,它要求被代理的类必须实现至少一个接口。在运行时,Java会动态地创建一个新的类,这个类实现了与原始...
### Java动态代理知识点详解 #### 一、Java动态代理简介 在Java中,动态代理是一种非常重要的机制,它允许我们在运行时动态地创建一个接口的实现类实例。这种技术广泛应用于AOP(面向切面编程)、RPC(远程过程...
与静态代理不同,动态代理在程序运行时生成,利用Java的反射API动态创建代理类。动态代理适用于那些在运行时才知道需要代理的对象或者代理行为的情况。Java提供了`java.lang.reflect.Proxy`类和`java.lang.reflect....