`
xuyuanshuaaa
  • 浏览: 386692 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

java 动态代理类的实现,原理及应用

 
阅读更多
在目前的Java开发包中包含了对动态代理的支持,但是其实现只支持对接口的的实现。

其实现主要通过是java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。

Proxy类主要用来获取动态代理对象,InvocationHandler接口用来约束调用者实现,如下,HelloWorld接口定义的业务方法,HelloWorldImpl是HelloWorld接口的实现,HelloWorldHandler是InvocationHandler接口实现。代码如下:

业务接口:
public interface HelloWorld {

       void sayHelloWorld() ;

}

业务接口实现:
public class HelloWorldImpl implements HelloWorld {

       public void sayHelloWorld() {

              System.out.println("Hello World!");            

       }

}

InvocationHandler实现,需要在接口方法调用前后加入一部份处理工作,这里仅仅在方法调用前后向后台输出两句字符串,其代码如下:
import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class HelloWorldHandler implements InvocationHandler {

       //要代理的原始对象

       private Object objOriginal;

       /**

        * 构造函数。

        * @param obj 要代理的原始对象。

        */

       public HelloWorldHandler(Object obj) {

              this.objOriginal = obj ;

       }

       public Object invoke(Object proxy, Method method, Object[] args)

                     throws Throwable {

             

              Object result ;

             

        //方法调用之前

              doBefore();

             

        //调用原始对象的方法

              result = method.invoke(this.objOriginal ,args);

             

        //方法调用之后

              doAfter();

             

              return result ;

       }

      

       private void doBefore() {

              System.out.println("before method invoke!");

       }

      

       private void doAfter() {

              System.out.println("after method invoke!");

       }

}

测试代码:
import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Proxy;

 

 

 

public class Test {

 

 

 

       public static void main(String[] args) {

 

 

 

              HelloWorld hw = new HelloWorldImpl();

             

              InvocationHandler handler = new HelloWorldHandler(hw);

             

              HelloWorld proxy = (HelloWorld) Proxy.newProxyInstance(

                            hw.getClass().getClassLoader(),

                            hw.getClass().getInterfaces(),

                            handler);

              proxy.sayHelloWorld();

       }

}

Ø         首先获取一个业务接口的实现对象;

Ø         获取一个InvocationHandler实现,此处是HelloWorldHandler对象;

Ø         创建动态代理对象;

Ø         通过动态代理对象调用sayHelloWorld()方法,此时会在原始对象HelloWorldImpl. sayHelloWorld()方法前后输出两句字符串。

运行测试类输出如下:
before method invoke!

Hello World!

after method invoke!

此处Test类中的方法调用代码比较多,在我们的实际应用中可以通过配置文件来来简化客户端的调用实现。另外也可以通过动态代理来实现简单的AOP。
               

1. 代理模式

代理模式是常用的Java设计模式,它的特征是代理类与委托类有同样的接口,如下图所示。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理类的创建时期,代理类可分为两种。

◆静态代理类:由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

◆动态代理类:在程序运行时,运用反射机制动态创建而成。

2.动态代理类

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。java.lang.reflect包中的Proxy类和 InvocationHandler接口提供了生成动态代理类的能力。

2.1 Proxy类

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 IllegalArgumentException


参数loader指定动态代理类的类加载器,参数interfaces指定动态代理类需要实现的所有接口,参数handler指定与动态代理类关联的 InvocationHandler对象。

举例,以下两种方式都创建了实现Foo接口的动态代理类的实例:
View Code

/**** 方式一 ****/
//创建InvocationHandler对象
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对象
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类的静态方法创建的动态代理类的实例具有以下特点:

◆假定变量foo是一个动态代理类的实例,并且这个动态代理类实现了Foo接口,那么“foo instanceof Foo”的值为true。把变量foo强制转换为Foo类型是合法的:(Foo) foo   //合法

◆每个动态代理类实例都和一个InvocationHandler实例关联。Proxy类的getInvocationHandler(Object proxy)静态方法返回与参数proxy指定的代理类实例所关联的InvocationHandler对象。
◆假定Foo接口有一个amethod()方法,那么当程序调用动态代理类实例foo的amethod()方法时,该方法会调用与它关联的InvocationHandler对象的invoke()方法。

2.2 InvocationHandler接口

InvocationHandler接口为方法调用接口,它声明了负责调用任意一个方法的invoke()方法:

Object invoke(Object proxy,Method method,Object[] args) throws Throwable

参数proxy指定动态代理类实例,参数method指定被调用的方法,参数args指定向被调用方法传递的参数,invoke()方法的返回值表示被调用方法的返回值。

2.3 举例

如下图所示,HelloServiceProxyFactory类(如例程10-15所示)的getHello- ServiceProxy()静态方法负责创建实现了HelloService接口的动态代理类的实例。

http://new.51cto.com/files/uploadimg/20070212/105519704.jpg

例  HelloServiceProxyFactory.java

package proxy;
import java.lang.reflect.*;

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); //事后处理
return result;
}
};

Class classType=HelloService.class;
return (HelloService)Proxy.newProxyInstance(classType.getClassLoader(),
new Class[]{classType},
handler);
}//# getHelloServiceProxy()
}


如下所示的Client2类先创建了一个HelloServiceImpl实例,然后创建了一个动态代理类实例helloServiceProxy,最后调用动态代理类实例的echo()方法。

package proxy;
public class Client2{
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"));
}
}

打印结果如下:

动态代理类的名字为$Proxy0
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)
echo:Hello


能在运行过程中根据接口的类型动态的调用实现该接口的类
动态代理的主要作用就是:实现了日志和业务的分开,也就是某个类只是要提供了某些业务,比如银行取款业务。
这个类实现了取款业务的同时也需要实现日志功能,如果不用动态代理的话,那么由此一来该类代码里面已经额外地添加了自己不该添加的日志功能能代码。所以我们就得使用动态代理把它的业务代码和日志功能代码分开。所以用到了动态代理概念,spring里面的AOP就是一个很好的例子。
动态代理主要是在运行时期创建一个实现一组特定接口的代理类,拦截对目标对象方法的调用..

分享到:
评论

相关推荐

    Java设计模式及应用场景之《代理模式》

    文章目录一、代理模式定义二、代理模式的结构和说明三、代理模式的分类四、代理模式示例五、动态代理1、JDK动态代理JDK动态代理...实现原理CGLIB动态代理注意事项六、三种代理方式的对比七、代理模式的应用场景及案例...

    JAVA高并发高性能高可用高扩展架构视频教程

    类加载器的高级特性(自定义类加器实现加密解密) iBATIS开源主流框架(实现半自动化hibernate) 企业实用技能之详解(眼睛横纹模式验证码防止恶意登陆) 动态页面的静态化处理 图片上传技术 在springMVC中实现原始的Excel...

    JAVA上百实例源码以及开源项目源代码

     Java zip压缩包查看程序,应用弹出文件选择框,选择ZIP格式的压缩文件,可以像Winrar软件一样查看压缩文件内部的文件及文件夹,源码截图如上所示。 Java 数字签名、数字证书生成源码 2个目标文件 摘要:JAVA源码,...

    JAVA上百实例源码以及开源项目

     Java zip压缩包查看程序,应用弹出文件选择框,选择ZIP格式的压缩文件,可以像Winrar软件一样查看压缩文件内部的文件及文件夹,源码截图如上所示。 Java 数字签名、数字证书生成源码 2个目标文件 摘要:JAVA源码,...

    Java典型模块

    3.7.4 动态代理类的设计模式 3.8 小结 第2篇 线程开发 第4章 学生并发接水(线程Thread) 4.1 学生并发接水原理 4.1.1 项目结构框架分析 4.1.2 项目功能业务分析 4.2 不排队形式学生并发接水 4.2.1 水龙头类 4.2.2 ...

    java基础案例与开发详解案例源码全

    6.8.1 接口的定义及实现174 6.8.2 接口中的常量174 6.8.3 接口的多重实现174 6.9 本章练习175 第7章 7.1 面向对象的分析与设计简介180 7.1.1 类的设计建议180 7.1.2 类名.变量名.方法名的选取181 7.1.3 类的属性设计...

    Java Web程序设计教程

    12.1.3java动态代理与aop 244 12.1.4springaop简介 245 12.2使用spring的通知 246 12.2.1beforeadvice 246 12.2.2afterreturningadvice 248 12.2.3methodinterceptor 249 12.2.4throwadvice 250 12.3使用...

    Java面试题.docx

    12、静态代理和动态代理的区别,什么场景使用? 14、Java中实现多态的机制是什么? 16、说说你对Java反射的理解 17、说说你对Java注解的理解 18、Java中String的了解 19、String为什么要设计成不可变的? 20、...

    java 面试题 总结

    Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而...

    Java常见面试题208道.docx

    60.怎么实现动态代理? 五、对象拷贝 61.为什么要使用克隆? 62.如何实现对象克隆? 63.深拷贝和浅拷贝区别是什么? 六、Java Web 64.jsp 和 servlet 有什么区别? 65.jsp 有哪些内置对象?作用分别是什么? 66.说...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     25.2 在业务代理类中访问EJB组件  25.3 发布J2EE应用  25.3.1 在JBoss上部署EJB组件  25.3.2 在JBoss上部署Web应用  25.3.3 在JBoss上部署J2EE应用  25.4 小结 附录A 标准SQL语言的用法  A.1 数据...

    Springaop原理及各种应用场景

    AOP是AspectOrientedPrograming的简称,面向切面编程。AOP适合于那些具有横切逻辑的应用:如性能监测,访问控制,事务管理、缓存、对象...AOP框架提供的命令进行编译,从而在编译阶段就可生成AOP代理类,因此也称为编译

    疯狂JAVA讲义

    1.2 Java的竞争对手及各自优势 4 1.2.1 C#简介和优势 4 1.2.2 Ruby简介和优势 4 1.2.3 Python的简介和优势 5 1.3 Java程序运行机制 5 1.3.1 高级语言的运行机制 6 1.3.2 Java程序的运行机制和JVM 6 1.4 开发...

    史上最全java面试,103项重点知识,带目录

    60. 怎么实现动态代理? 24 五、对象拷贝 24 61. 为什么要使用克隆? 24 62. 如何实现对象克隆? 24 63. 深拷贝和浅拷贝区别是什么? 28 六、Java Web 28 64. jsp 和 servlet 有什么区别? 28 65. jsp 有哪些内置...

    超级有影响力霸气的Java面试题大全文档

    Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现。 最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在多个线程访问Hashtable时,不需要自己为它的方法实现同步,而...

    JAVA中级书籍

    1、对于Java基础技术体系(包括JVM、类装载机制、多线程并发、IO、网络)有一定的掌握和应用经验。 掌握JVM内存分配、JVM垃圾回收;类装载机制; 性能优化; 反射机制;多线程;IO/NIO; 网络编程;常用数据结构和...

Global site tag (gtag.js) - Google Analytics