代理模式

概述

代理模式,即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 条评论
登录 后参与评论

相关文章

来自专栏Fundebug

5分钟掌握JavaScript小技巧

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

901
来自专栏Fundebug

详解JavaScript之神奇的Object.defineProperty

摘要: JavaScript有个很神奇的Object.defineProperty(),了解一下?

925
来自专栏Java爬坑系列

【Java入门提高篇】Day1 抽象类

  基础部分内容差不多讲解完了,今天开始进入Java提高篇部分,这部分内容会比之前的内容复杂很多,希望大家做好心理准备,看不懂的部分可以多看两遍,仍不理解的部分...

1826
来自专栏linux驱动个人学习

Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】

Android系统的运行时库层代码是用C++来编写的,用C++ 来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃。不过系统为...

672
来自专栏吴伟祥

编码总结笔记 原

我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一...

1226
来自专栏喵了个咪的博客空间

zephir-(6)运算符

#zephir-运算符# ? ##前言## 先在这里感谢各位zephir开源技术提供者 了解的动态变量和静态变量之后我们今天来了解一下在编码工作中至关重要的运算...

3579
来自专栏码洞

《快学 Go 语言》第 3 课 —— 分支与循环

上面这个等式每一个初学编程的同学都从老师那里听说过。它并不是什么严格的数据公式,它只是对一般程序的简单认知。数据结构是内存数据关系的静态表示,算法是数据结构从一...

933
来自专栏Play & Scala 技术分享

挑逗 Java 程序员的那些 Scala 绝技

有个问题一直困扰着 Scala 社区,为什么一些 Java 开发者将 Scala 捧到了天上,认为它是来自上帝之吻的完美语言;而另外一些 Java 开发者却对它...

1476
来自专栏数据结构与算法

洛谷P3224 [HNOI2012]永无乡

题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示。某些岛之间...

2725
来自专栏GopherCoder

『Go 内置库第一季:strings』

这一季的系列主题,主要围绕内置库进行。如果一个人写的代码比你的赞,那么他对内置库的熟悉程度一定比你强。

953

扫码关注云+社区