1.JDK动态代理

    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标的代码,动态将横切逻辑和业务逻辑编织在一起。而Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

    通过使用动态代理,可以在运行时动态创建出同时实现多个Java接口的相关代理类及其对象实例。当客户代码通过这些被代理的接口来访问其中的方法时,相关的调用信息就会被传递给代理中的一个特殊对象进行处理,处理的结果作为方法调用的结果返回。客户代码看到的只是接口,具体的逻辑被封装在代理的实现中。

    动态代理机制的强大之处在于可以在运行时动态实现多个接口,而不需要在源代码中通过inplements关键词来声明。同时,动态代理把对接口中的方法调用的处理逻辑交给开发人员,让开发人员可以灵活处理。通过动态代理可以实现面向对象编程(AOP)中的常见的方法拦截功能。

2.基本使用方式

    使用动态代理时只需要理解两个要素即可:第一个是要代理的接口,另外一个是处理接口方法调用的java.lang.reflect.InvocationHandler。动态代理只支持对接口提供代理,一般的Java类是不行的。如果要代理的接口不是公开的,那么被代理的接口和创建动态代理的代码必须在同一个包中。在创建动态处理的时候,需要提供InvocationHandler接口的实现,以处理实际的调用。在进行处理的时候可以得到表示实际调用方法的Method对象和调用的实际参数列表。

InvocationHandler接口的实现类的示例

public class LoggingInvocationHandler implements InvocationHandler{
private static final Logger logger = Logger.getLogger(LoggingInvocationHandler.class);
private Object target;
public LoggingInvocationHandler(Object obj){
this.target = obj;
} public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
logger.log(Level.Info + "调用方法" + method.getName() + ":参数为" + Arrays.deepToString(args));
return method.invoke(target,args);
}
}

创建和使用动态代理的示例

public static void useProxy(){
String str = "Hello World";
LoggingInvocationHandler handler = new LoggerInvocationHandler(str);
ClassLoaser cl = SimpleProxy.class.getClassLoader();
Comparable obj = (Comparable)Proxy.newProxyInstance(cl,new Class[]{Comparable},handler);
obj.comparedTo("Good");
}

代码说明:

    创建动态代理时需要一个InvocationHandler接口的实现,这是使用的的是上面的LoggingInvocationHandler类的实例。动态代理的创建是由java.lang.reflect.Proxy类的静态方法newProxyInstance来完成的。创建时需要提供类加载器实例、被代理的接口列表以及InvocationHandler接口的实现。在创建完成之后,需要通过类型转换把代理对象转换成被代理的某个接口来使用。

    虽然LoggingInvocationHandler类只是简单地记录了日志,并没有改变方法的实际执行,但是实际上,在InvocationHandler接口的invoke方法中可以实现各种各样复杂的逻辑。比如对实际调用参数进行转换,或者是改变实际调用的方法,还可以对调用的返回结果进行修改。开发人员可以自己的需要,添加感兴趣的业务逻辑。这实际上就是AOP中常用的方法拦截,即拦截一个方法调用,以在其上附加所需的业务逻辑。InvocationHandler很适合于封装一些横切(cross-cutting)的代码逻辑,包括日志、参数检查与校验、异常处理和返回值归一化等。

    一般来说,在创建一个动态代理的InvocationHandler实例的时候,需要把原始的方法调用的接受者对象也传进去,以方便执行原始的方法调用。这可以在创建InvocationHandler的时候,通过构造方法来传递。在大多数情况下,代理对象只会实现一个Java接口。对于这种情况,可以结合泛型来开发一个通用的工厂方法,以创建代理对象。

为任何接口及其实现类创建代理的工厂方法

public static <T>T makeProxy(Class<T> clazz,final T target,InovcationHandler handler){
ClassLoader classLoader = target.getClass().getClassLoader();
return (T) Proxy.newProxyInstance(classLoader,new Class<?>[]{clazz},handler)
}

Java学习笔记--JDK动态代理的更多相关文章

  1. Java学习笔记--Cglib动态代理

    CGLib动态代理 使用JDK创建代理有一个限制,即它只能为接口创建代理实例,这一点可以从Proxy的接口方法newProxyInstance(ClassLoader loader,Class[] i ...

  2. AOP学习心得&jdk动态代理与cglib比较

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

  3. Java中的JDK动态代理

    所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...

  4. Java设计模式之JDK动态代理原理

    动态代理核心源码实现public Object getProxy() { //jdk 动态代理的使用方式 return Proxy.newProxyInstance( this.getClass(). ...

  5. Java学习笔记14--动态代理

    InvocationHandler接口 public interface InvocationHandler{ public Object invoke(Object proxy,Method met ...

  6. Java 反射之JDK动态代理

    Proxy提供用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类.如果我们在程序中为一个或多个接口动态地生成实现类,就可以使用Proxy来创建动态代理类:如果需要为一个或多个接口动态的 ...

  7. 8.3(java学习笔记)动态编译(DynamicCompiler)与动态运行(DynamicRun)

    一.动态编译 简单的说就是在运行一个java程序的过程中,可以通过一些API来编译其他的Java文件. 下面主要说动态编译的实现: 1.获取java编译编译器 2.运行编译器(须指定编译文件) 获取编 ...

  8. 【JVM学习笔记】动态代理

    基于JDK的动态代理例子如下 接口 Subject public interface Subject { public abstract void request(); } 实现类RealSubjec ...

  9. [java学习笔记]JDK的安装和环境变量的配置

    1.JDK的下载和安装 jdk(java development kit)是java提供给我们的一套java开发工具,它必运行在JVM(java虚拟机)上,java语言的跨平台性就是利用java运行在 ...

随机推荐

  1. java反转链表

    /** * 遍历,将当前节点的下一个节点缓存后更改当前节点指针 */ public static Node reverse2(Node head) { if (head == null) return ...

  2. js------科学计数法转换为正常小数

    // toD.js文件export default (val) => { const e = String(val) let rex = /^([0-9])\.?([0-9]*)e-([0-9] ...

  3. Josephus Problem的详细算法及其Python、Java实现

      笔者昨天看电视,偶尔看到一集讲述古罗马人与犹太人的战争--马萨达战争,深为震撼,有兴趣的同学可以移步:http://finance.ifeng.com/a/20170627/15491157_0. ...

  4. Bootstrap学习记录-1.Navigation

    Bootstrap中的导航栏功能需要添加bootstrap.css.jquery.js.bootstrap.js,其中,jquery.js文件是bootstrap.js文件中必须的,否则就会抛出异常信 ...

  5. httpclient请求服务的各种方法实例

    <!--话不多说,直接上代码--> import com.csis.ConfigManagerimport com.csis.io.web.DefaultConfigItemimport ...

  6. webstrom vue项目让局域网访问

    vue项目package.json "dev": "webpack-dev-server --inline --progress --config build/webpa ...

  7. 【Dubbo&&Zookeeper】4、 Java实现Dubbo服务提供者及消费者注册

    转自:http://blog.csdn.net/u010317829/article/details/52128852 创建Mavn工程.HelloDubbo. pom.xml添加dubbo及spri ...

  8. 设计模式之备忘录模式(Memento )

    当我们在实际应用中需要提供撤销机制,当一个对象可能需要再后续操作中恢复其内部状态时,就需要使用备忘录模式.其本质就是对象的序列化和反序列化的过程,支持回滚操作. 作用 在不破坏封装性的前提下,捕获一个 ...

  9. 详解 ESLint 规则,规范你的代码

    在很久之前就想通过工具来规范自己的代码风格,减少程序出错的概率,如果看过我的 一个前端程序猿的Sublime Text3的自我修养 ,这篇博客的朋友,肯定知道在当时我使用 SublimeLinter- ...

  10. Linux常用基本命令:三剑客命令之-awk格式化动作

    我们之前说过,awk是一个超强的文本格式化工具,而本文的printf动作就是经常用来做格式化文本的.使用方式跟c语言的printf差不多. 1,printf默认不会回车换行 ghostwu@dev:~ ...