代理模式

概述

代理模式,即ProxyPattern,java常用设计模式之一,动态代理实现了著名的AOP思想。代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。

通俗的讲,可以拿到现实中来举例,可能说的并不准确,比如,苹果出了一款iphone手机,拿到中国交给代理商来卖,如联通、电信,就是所谓的定制机,联通电信又给iphone手机植入了一些软件,再卖给使用者。我们最后买到的手机就是代理商处理过的。

静态代理

静态代理很好理解,代码类似如下:

原类:

package staticProxy;public class Object {   public void service() {      // do something   }}

代理类:

package staticProxy;public class ProxyObject {   private staticProxy.Object obj;   public ProxyObject(staticProxy.Object obj) {      this.obj = obj;   }   public void service() {      // do something      this.obj.service();   }}

静态代理需要对每个原类创建一个代理类,这样做需要代理的情况少的话还可以接受,如果多的话,就无法接受了,所以我们需要一种动态创建代理类的方式。

动态代理

Java支持动态代理,可以在运行期根据原对象来动态创建代理对象。有两种方式可以实现动态代理,一种是通过JDK Proxy,另一种是第三方类库CGLIB,前者得到的代理对象是实现和原类相同的接口,后者得到的是继承自原类。下面主要介绍的是JDK Proxy。

Proxy类中有个newProxyInstance方法,可以通过该方法得到代理对象,该方法有三个参数:

ClassLoader loader:原类的类加载器;

Class[] interfaces:原类实现的接口列表;

InvocationHandler handler:指派方法调用的调用处理程序。

调用该方法创建代理对象时,会把InvocationHandler传入$Proxy内,并根据相应接口生成方法,每个方法内都调用InvocationHandler中的invoke方法,在invoke方法中执行相应方法。

原理图

实现

Advice.java,增强类,用于创建代理对象时增强功能。

public class Advice {   /** 前置增强 */   public void beforeMethod() {      System.out.println("前置增强");   }   /** 后置增强 */   public void afterMethod() {      System.out.println("后置增强");   }   /** 异常增强 */   public void catchMethod() {      System.out.println("异常增强");   }   /** 最后执行增强 */   public void finallyMethod() {      System.out.println("最后增强");   }}

ProxyFactory.java,代理类工厂,用于产生代理对象。

public class ProxyFactory {   /** 代理类的增强对象 */   private Advice advice;   /** 代理的目标对象 */   private Object target;   public ProxyFactory() {}   public ProxyFactory(Advice advice, Object target) {      this.advice = advice;      this.target = target;   }   /**    * 得到代理对象    * @return    */   public Object getProxy() {      Object proxy = Proxy.newProxyInstance(           target.getClass().getClassLoader(),           target.getClass().getInterfaces(),new InvocationHandler() {              /**               * 代理对象需要执行的方法               */              public Object invoke(Object proxy, Method method, Object[] args) {                 Object result = null;                 advice.beforeMethod();                 try {                    result = method.invoke(target, args);                    advice.afterMethod();                 } catch (Exception e) {                    advice.catchMethod();                 } finally {                    advice.finallyMethod();                 }                 return result;              }           });      return proxy;   }   public void setAdvice(Advice advice) {      this.advice = advice;   }   public void setTarget(Object target) {      this.target = target;   }}

ITest.java,目标对象接口。

public interface ITest {   void test();}

Test.java,目标对象类。

public class Test implements ITest {   public void test() {      System.out.println("目标对象");   }   public static void main(String[] args) {      ProxyFactory pf = new ProxyFactory(new Advice(), new Test());      ITest test = (ITest) pf.getProxy();      test.test();   }}

输出结果:

前置增强目标对象后置增强最后增强

总结

动态代理实现了AOP思想,AOP弥补了OOP的不足。本篇主要介绍的是jdk proxy动态代理的使用方式,对AOP没有特意说明。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码匠的流水账

spring mvc中的几类拦截器对比

是servlet规范中的Filter,spring中有一个基本的实现叫做org/springframework/web/filter/GenericFilter...

871
来自专栏后端之路

MyBatis插件小知识点

背景 mybatis作为一款十分优秀的orm框架在大量的互联网应用中得到使用。其提供了比较完善的插件扩展机制 通常我们会使用插件做到许多共通的事情 比如 慢sq...

2379
来自专栏跟着阿笨一起玩NET

深入了解VSTS的Unit Test测试属性

深入的了解一下方法上带有的属性的含义. 每个方法上几乎都带有TestMethod这个属性,我们直觉告诉我们,这肯定是表示被测试函数的意思.事实也正是如此,在Un...

381
来自专栏向治洪

彻底搞清楚 RxJava 是什么东西

其实从rxjava14年出现到现在,我是去年从一个朋友那里听到的,特别是随着现在app项目越来越大,分层越来越不明确的情况下,rxjava出现了,以至于出现了r...

2457
来自专栏非著名程序员

这是一篇清晰易懂的 Rxjava 入门教程

? 原文作者:Carson_Ho 原文地址:http://www.jianshu.com/p/a406b94f3188 特别声明:本文为Carson_Ho原创...

4746
来自专栏Android先生

Android:这是一篇 清晰 易懂的Rxjava 入门教程

2、如果读者还没学习过Rxjava 1.0也没关系,因为Rxjava 2.0只是在Rxjava 1.0上增加了一些新特性,本质原理 & 使用基本相同

621
来自专栏郭霖

Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程

在本系列的上一篇文章中,我们学习了Glide的基本用法,体验了这个图片加载框架的强大功能,以及它非常简便的API。还没有看过上一篇文章的朋友,建议先去阅读 An...

49210
来自专栏向治洪

ttf设置文字字体

MainActivity如下: package cn.testfont;   import android.os.Bundle;   import andr...

1899
来自专栏林冠宏的技术文章

分享个 之前写好的 android 文件流缓存类,专门处理 ArrayList、bean。

转载麻烦声明出处:https://cloud.tencent.com/developer/user/1148436/activities 目录:   1,前序 ...

2.2K5
来自专栏刘望舒

JNI的实现原理

JNI是Java Native Interface的缩写,它为java提供了调用C和C++代码的能力。java.lang包下的很多类都用到了native方法,比...

1152

扫码关注云+社区