代理模式

概述

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

相关文章

来自专栏xingoo, 一个梦想做发明家的程序员

基于Dubbo的http自动测试工具分享

公司是采用微服务来做模块化的,各个模块之间采用dubbo通信。好处就不用提了,省略了之前模块间复杂的http访问。不过也遇到一些问题: PS: Githu...

2258
来自专栏进击的程序猿

第2章:spring 依赖第2章:spring 依赖

另外在声明具体的值上,我们可以是 Straight values(primitives, Strings),也可以使idref元素,或者是对其他bean的指向,...

633
来自专栏对角另一面

读Zepto源码之Ajax模块

Ajax 模块也是经常会用到的模块,Ajax 模块中包含了 jsonp 的现实,和 XMLHttpRequest 的封装。 读 Zepto 源码系列文章已经放到...

1980
来自专栏美团技术团队

Mson,让JSON序列化更快

本文由秦喆 芝任 天洲 赵鹏四位作者共同完成。 问题 我们经常需要在主线程中读取一些配置文件或者缓存数据,最常用的结构化存储数据的方式就是将对象序列化为JSON...

39311
来自专栏玩转JavaEE

使用MyBatis轻松实现递归查询与存储过程调用

vhr部门管理模块更新啦!为了让小伙伴们快速理解部门管理模块实现思路,我想通过3篇短文来给大家介绍下大致的实现思路和核心代码。 项目地址:https://git...

3246
来自专栏CSDN技术头条

Spring 框架之 AOP 原理剖析

前言 AOP(Aspect Oriented Programming)面向切面编程是 Spring 框架最核心的组件之一,它通过对程序结构的另一种考虑,补充了...

5874
来自专栏xiaoheike

hibernate persist update 方法没有正常工作(不保存数据,不更新数据)

在工程中通过spring aop的方式配置事务,使用hibernate做持久化。在代码实现中使用hibernate persit()方法插入数据到数据库,使用h...

641
来自专栏Java Edge

谈谈Spring AOP基本的概念2 Pointcut切点

2735
来自专栏JavaQ

深入理解Spring系列之十:DispatcherServlet请求分发源码分析

DispatcherServlet是SpringMVC的核心分发器,它实现了请求分发,是处理请求的入口,本篇将深入源码分析它的请求分发过程。可点击文末左下角“阅...

3249
来自专栏Java成神之路

SpringMVC学习笔记

(1)通过 contextConfigLocation 来配置 SpringMVC 的配置文件

724

扫码关注云+社区