Java 几种动态代理实现及其性能比较
发布时间:2025-05-13 07:29:07 发布人:远客网络
一、Java 几种动态代理实现及其性能比较
1.动态代理是指在运行时,动态生成代理类。代理类的字节码将在运行时生成并载入当前的ClassLoader.
生成动态代理类的方法很多,如JDK自带的动态代理、CGLIB、Javassist或者ASM库。
JDK动态代理使用简单,它内置在JDK中,因此不需要引入第三方Jar包,但相对功能比较弱。CGLIB和Javassist都是高级的字节码生成库,总体性能比JDK自带的动态代理好,而且功能十分强大。ASM是低级的字节码生成工具,使用ASM已经近乎在于使用Javabytecode编程,对开发人员要求较高,也是性能最好的一种动态代理生辰工具。但ASM的使用是在过于繁琐,而且性能也没有数量级的提升,与CGLIB等高级字节码生成工具相比,ASM程序的可维护性也较差。
1)通过实现InvocationHandler接口创建自己的调用处理器
2)通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类
3)通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型
4)通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入
//InvocationHandlerImpl实现了InvocationHandler接口,并能实现方法调用从代理类到委托类的分派转发
//其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用
InvocationHandler handler= new InvocaitonHandlerImpl(..);
//通过Proxy为包括Interface接口在内的一组接口动态创建代理类的对象
Class clazz= Proxy.getProxyClass(classLoader,new Class[]{Interface.class,...});
//通过反射从生成的类对象获得构造函数对象
Constructor constructor= clazz.getConstructor(new Class[]{InvocationHandler.class});
//通过构造函数对象创建动态代理类实例
Interface Proxy=(Interface)constructor.newInstance(new Object[]{handler});
//Proxy类的静态方法newProxyInstance对上面具体步骤的后三步做了封装,简化了动态代理对象的获取过程。
//InvocationHandlerImpl实现了InvocaitonHandler接口,并能实现方法调用从代理类到委托类的分派转发
InvocaitonHandler handler= new InvocationHandlerImpl(..);
//通过Proxy直接创建动态代理类实例
nterface proxy=(Interface)Proxy.newProxyInstance(classLoader,new Class[]{Interface.class},handler);
public class DBQuery implements IDBQuery{
Thread.sleep(1000);//可能包含数据库连接等耗时操作
} catch(InterruptedException e){
public class JdkDbQueryHandler implements InvocationHandler{
IDBQuery real= null;//主题接口
public Object invoke(Object proxy, Method method, Object[] args)
real= new DBQuery();//如果是第一次调用,则生成真实对象
return real.request();//使用真实主题完成实际的操作
public static IDBQuery createJdkProxy(){
//根据指定的类加载器和接口以及截获器,返回代理类的一个实例对象
//ClassLoader loader:指定被代理对象的类加载器
//Class[] Interfaces:指定被代理对象所以事项的接口
//InvocationHandler h:指定需要调用的InvocationHandler对象
IDBQuery jdkProxy=(IDBQuery) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{IDBQuery.class}, new JdkDbQueryHandler());
二、java 动态代理怎么理解
代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。按照代理类的创建时期,代理类可分为两种。
由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。动态代理类:在程序运行时,运用反射机制动态创建而成。
如下, HelloServiceProxy类是代理类,HelloServiceImpl类是委托类,这两个类都实现了HelloService接口。其中HelloServiceImpl类是HelloService接口的真正实现者,而HelloServiceProxy类是通过调用HelloServiceImpl类的相关方法来提供特定服务的。HelloServiceProxy类的echo()方法和getTime()方法会分别调用被代理的HelloServiceImpl对象的echo()方法和getTime()方法,并且在方法调用前后都会执行一些简单的打印操作。
由此可见,代理类可以为委托类预处理消息、把消息转发给委托类和事后处理消息等。
public interface HelloService{
public String echo(String msg);
public class HelloServiceImpl implements HelloService{
public String echo(String msg){
public class HelloServiceProxy implements HelloService{
private HelloService helloService;//表示被代理的HelloService实例
public HelloServiceProxy(HelloService helloService){
this.helloService=helloService;
public void setHelloServiceProxy(HelloService helloService){
this.helloService=helloService;
public String echo(String msg){
System.out.println("before calling echo()");//预处理
String result=helloService.echo(msg);//调用被代理的HelloService实例的echo()方法
System.out.println("after calling echo()");//事后处理
System.out.println("before calling getTime()");//预处理
Date date=helloService.getTime();//调用被代理的HelloService实例的getTime()方法
System.out.println("after calling getTime()");//事后处理
在Client1类的main()方法中,先创建了一个HelloServiceImpl对象,又创建了一个HelloServiceProxy对象,最后调用HelloServiceProxy对象的echo()方法。
public static void main(String args[]){
HelloService helloService=new HelloServiceImpl();
HelloService helloServiceProxy=new HelloServiceProxy(helloService);
System.out.println(helloServiceProxy.echo("hello"));
例程3的HelloServiceProxy类的源代码是由程序员编写的,在程序运行前,它的.class文件就已经存在了,这种代理类称为静态代理类。
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。java.lang.reflect包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。
Proxy类提供了创建动态代理类及其实例的静态方法。
(1)getProxyClass()静态方法负责创建动态代理类,它的完整定义如下:
public static Class getProxyClass(ClassLoader loader, Class[] interfaces) throws IllegalArgumentException
参数loader指定动态代理类的类加载器,参数interfaces指定动态代理类需要实现的所有接口。
(2)newProxyInstance()静态方法负责创建动态代理类的实例,它的完整定义如下:
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler handler) throws
参数loader指定动态代理类的类加载器,参数interfaces指定动态代理类需要实现的所有接口,参数handler指定与动态代理类关联的 InvocationHandler对象。
以下两种方式都创建了实现Foo接口的动态代理类的实例:
InvocationHandler handler= new MyInvocationHandler(...);
Class proxyClass= Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[]{ Foo.class});
Foo foo=(Foo) proxyClass.getConstructor(new Class[]{ InvocationHandler.class}).
newInstance(new Object[]{ handler});
InvocationHandler handler= new MyInvocationHandler(...);
Foo foo=(Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{ Foo.class}, handler);
由Proxy类的静态方法创建的动态代理类具有以下特点:
动态代理类是public、final和非抽象类型的;
动态代理类继承了java.lang.reflect.Proxy类;
动态代理类的名字以“$Proxy”开头;
动态代理类实现getProxyClass()和newProxyInstance()方法中参数interfaces指定的所有接口;
Proxy类的isProxyClass(Class cl)静态方法可用来判断参数指定的类是否为动态代理类。只有通过Proxy类创建的类才是动态代理类;
动态代理类都具有一个public类型的构造方法,该构造方法有一个InvocationHandler类型的参数。
由Proxy类的静态方法创建的动态代理类的实例具有以下特点:
1.假定变量foo是一个动态代理类的实例,并且这个动态代理类实现了Foo接口,那么“foo instanceof Foo”的值为true。把变量foo强制转换为Foo类型是合法的:
2.每个动态代理类实例都和一个InvocationHandler实例关联。Proxy类的getInvocationHandler(Object proxy)静态方法返回与参数proxy指定的代理类实例所关联的InvocationHandler对象。
3.假定Foo接口有一个amethod()方法,那么当程序调用动态代理类实例foo的amethod()方法时,该方法会调用与它关联的InvocationHandler对象的invoke()方法。
InvocationHandler接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:
Object invoke(Object proxy,Method method,Object[] args) throws Throwable
参数proxy指定动态代理类实例,参数method指定被调用的方法,参数args指定向被调用方法传递的参数,invoke()方法的返回值表示被调用方法的返回值。
HelloServiceProxyFactory类的getHelloServiceProxy()静态方法负责创建实现了HelloService接口的动态代理类的实例。
例程5 HelloServiceProxyFactory.java
public class HelloServiceProxyFactory{
/**创建一个实现了HelloService接口的动态代理类的实例
*参数helloService引用被代理的HelloService实例
public static HelloService getHelloServiceProxy(final HelloService helloService){
//创建一个实现了InvocationHandler接口的匿名类的实例
InvocationHandler handler=new InvocationHandler(){
public Object invoke(Object proxy,Method method,Object args[])throws Exception{
System.out.println("before calling"+method);//预处理
Object result=method.invoke(helloService,args);
//调用被代理的HelloService实例的方法
System.out.println("after calling"+method);//事后处理
Class classType=HelloService.class;
return(HelloService)Proxy.newProxyInstance(classType.getClassLoader(),
如下所示的Client2类先创建了一个HelloServiceImpl实例,然后创建了一个动态代理类实例helloServiceProxy,最后调用动态代理类实例的echo()方法。
public static void main(String args[]){
HelloService helloService=new HelloServiceImpl();
HelloService helloServiceProxy=HelloServiceProxyFactory.getHelloServiceProxy(helloService);
System.out.println("动态代理类的名字为"+helloServiceProxy.getClass().getName());
System.out.println(helloServiceProxy.echo("Hello"));
before calling public abstract java.lang.String proxy.HelloService.echo(java.lang.String)
after calling public abstract java.lang.String proxy.HelloService.echo(java.lang.String)
从结果看出,动态代理类的名字为$Proxy0。
三、JAVA中反射是什么
JAVA中反射是动态获取信息以及动态调用对象方法的一种反射机制。
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态语言的一个关键性质。
Java反射的功能是在运行时判断任意一个对象所属的类,在运行时构造任意一个类的对象,在运行时判断任意一个类所具有的成员变量和方法,在运行时调用任意一个对象的方法,生成动态代理。
1、Class superClass=clazz.getSuperclass();//获取父类。
System.out.println("getSuperclass:"+superClass)。
2、Class[] interfaces=clazz.getInterfaces();//获取实现接口。
System.out.println("getInterfaces:"+interfaces.length)。
3、Constructor[] cons=clazz.getConstructors();//构造方法。
System.out.println("getConstructors:"+cons.length)。
参考资料来源:百度百科: JAVA反射机制