代理就是一个对象的代理对象,代理对象存在的价值主要(不是唯一)就是对访问真实业务对象进行拦截。

代理模式(Proxy)是通过代理对象访问目标对象,这样可以在目标对象基础上增强额外的功能,如添加权限,访问控制和审计等功能。

代理模式

代理(Proxy)模式结构图

Java代理分为静态代理和动态代理和Cglib代理,下面进行逐个说明。

1.静态代理

接口类AdminService.java接口

package com.lance.proxy.demo.service;public interface AdminService {void update();Object find();
}

实现类AdminServiceImpl.java

package com.lance.proxy.demo.service;public class AdminServiceImpl implements AdminService{public void update() {System.out.println("修改管理系统数据");}public Object find() {System.out.println("查看管理系统数据");return new Object();}
}

代理类AdminServiceProxy.java

package com.lance.proxy.demo.service;public class AdminServiceProxy implements AdminService {private AdminService adminService;public AdminServiceProxy(AdminService adminService) {this.adminService = adminService;}public void update() {System.out.println("判断用户是否有权限进行update操作");adminService.update();System.out.println("记录用户执行update操作的用户信息、更改内容和时间等");}public Object find() {System.out.println("判断用户是否有权限进行find操作");System.out.println("记录用户执行find操作的用户信息、查看内容和时间等");return adminService.find();}
}

测试类StaticProxyTest.java

package com.lance.proxy.demo.service;public class StaticProxyTest {public static void main(String[] args) {AdminService adminService = new AdminServiceImpl();AdminServiceProxy proxy = new AdminServiceProxy(adminService);proxy.update();System.out.println("=============================");proxy.find();}
}

输出:

判断用户是否有权限进行update操作
修改管理系统数据
记录用户执行update操作的用户信息、更改内容和时间等
=============================
判断用户是否有权限进行find操作
记录用户执行find操作的用户信息、查看内容和时间等
查看管理系统数据

总结:
静态代理模式在不改变目标对象的前提下,实现了对目标对象的功能扩展。
不足:静态代理实现了目标对象的所有方法,一旦目标接口增加方法,代理对象和目标对象都要进行相应的修改,增加维护成本。

2.JDK动态代理

为解决静态代理对象必须实现接口的所有方法的问题,Java给出了动态代理,动态代理具有如下特点:
1.Proxy对象不需要implements接口;
2.Proxy对象的生成利用JDK的Api,在JVM内存中动态的构建Proxy对象。需要使用java.lang.reflect.Proxy类的

  /*** Returns an instance of a proxy class for the specified interfaces* that dispatches method invocations to the specified invocation* handler.* @param   loader the class loader to define the proxy class* @param   interfaces the list of interfaces for the proxy class*          to implement* @param   h the invocation handler to dispatch method invocations to* @return  a proxy instance with the specified invocation handler of a*          proxy class that is defined by the specified class loader*          and that implements the specified interfaces*/
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler invocationHandler );

方法,方法参数说明:
a.ClassLoader loader:指定当前target对象使用类加载器,获取加载器的方法是固定的;
b.Class<?>[] interfaces:target对象实现的接口的类型,使用泛型方式确认类型
c.InvocationHandler invocationHandler:事件处理,执行target对象的方法时,会触发事件处理器的方法,会把当前执行target对象的方法作为参数传入。

2.1 实战代码:

AdminServiceImpl.java和AdminService.java和原来一样,这里不再赘述。
AdminServiceInvocation.java

package com.lance.proxy.demo.service;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class AdminServiceInvocation  implements InvocationHandler {private Object target;public AdminServiceInvocation(Object target) {this.target = target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("判断用户是否有权限进行操作");Object obj = method.invoke(target);System.out.println("记录用户执行操作的用户信息、更改内容和时间等");return obj;}
}

AdminServiceDynamicProxy.java

package com.lance.proxy.demo.service;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;public class AdminServiceDynamicProxy {private Object target;private InvocationHandler invocationHandler;public AdminServiceDynamicProxy(Object target,InvocationHandler invocationHandler){this.target = target;this.invocationHandler = invocationHandler;}public Object getPersonProxy() {Object obj = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), invocationHandler);return obj;}
}

DynamicProxyTest.java

package com.lance.proxy.demo.service;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class DynamicProxyTest {public static void main(String[] args) {// 方法一System.out.println("============ 方法一 ==============");AdminService adminService = new AdminServiceImpl();System.out.println("代理的目标对象:" + adminService.getClass());AdminServiceInvocation adminServiceInvocation = new AdminServiceInvocation(adminService);AdminService proxy = (AdminService) new AdminServiceDynamicProxy(adminService, adminServiceInvocation).getPersonProxy();System.out.println("代理对象:" + proxy.getClass());Object obj = proxy.find();System.out.println("find 返回对象:" + obj.getClass());System.out.println("----------------------------------");proxy.update();//方法二System.out.println("============ 方法二 ==============");AdminService target = new AdminServiceImpl();AdminServiceInvocation invocation = new AdminServiceInvocation(adminService);AdminService proxy2 = (AdminService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), invocation);Object obj2 = proxy2.find();System.out.println("find 返回对象:" + obj2.getClass());System.out.println("----------------------------------");proxy2.update();//方法三System.out.println("============ 方法三 ==============");final AdminService target3 = new AdminServiceImpl();AdminService proxy3 = (AdminService) Proxy.newProxyInstance(target3.getClass().getClassLoader(), target3.getClass().getInterfaces(), new InvocationHandler() {public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("判断用户是否有权限进行操作");Object obj = method.invoke(target3, args);System.out.println("记录用户执行操作的用户信息、更改内容和时间等");return obj;}});Object obj3 = proxy3.find();System.out.println("find 返回对象:" + obj3.getClass());System.out.println("----------------------------------");proxy3.update();}
}

输出结果:

============ 方法一 ==============
代理的目标对象:class com.lance.proxy.demo.service.AdminServiceImpl
代理对象:class com.sun.proxy.$Proxy0
判断用户是否有权限进行操作
查看管理系统数据
记录用户执行操作的用户信息、更改内容和时间等
find 返回对象:class java.lang.Object
----------------------------------
判断用户是否有权限进行操作
修改管理系统数据
记录用户执行操作的用户信息、更改内容和时间等
============ 方法二 ==============
判断用户是否有权限进行操作
查看管理系统数据
记录用户执行操作的用户信息、更改内容和时间等
find 返回对象:class java.lang.Object
----------------------------------
判断用户是否有权限进行操作
修改管理系统数据
记录用户执行操作的用户信息、更改内容和时间等
============ 方法三 ==============
判断用户是否有权限进行操作
查看管理系统数据
记录用户执行操作的用户信息、更改内容和时间等
find 返回对象:class java.lang.Object
----------------------------------
判断用户是否有权限进行操作
修改管理系统数据
记录用户执行操作的用户信息、更改内容和时间等

3.Cglib代理

JDK动态代理要求target对象是一个接口的实现对象,假如target对象只是一个单独的对象,并没有实现任何接口,这时候就会用到Cglib代理(Code Generation Library),即通过构建一个子类对象,从而实现对target对象的代理,因此目标对象不能是final类(报错),且目标对象的方法不能是final或static(不执行代理功能)。
Cglib依赖的jar包

  <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.2.10</version></dependency>

3.1实战

目标对象类AdminCglibService.java

package com.lance.proxy.demo.service;public class AdminCglibService {public void update() {System.out.println("修改管理系统数据");}public Object find() {System.out.println("查看管理系统数据");return new Object();}
}

代理类AdminServiceCglibProxy.java

package com.lance.proxy.demo.service;import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class AdminServiceCglibProxy implements MethodInterceptor {private Object target;public AdminServiceCglibProxy(Object target) {this.target = target;}//给目标对象创建一个代理对象public Object getProxyInstance() {//工具类Enhancer en = new Enhancer();//设置父类en.setSuperclass(target.getClass());//设置回调函数en.setCallback(this);//创建子类代理对象return en.create();}public Object intercept(Object object, Method method, Object[] arg2, MethodProxy proxy) throws Throwable {System.out.println("判断用户是否有权限进行操作");Object obj = method.invoke(target);System.out.println("记录用户执行操作的用户信息、更改内容和时间等");return obj;}}

Cglib代理测试类CglibProxyTest.java

package com.lance.proxy.demo.service;public class CglibProxyTest {public static void main(String[] args) {AdminCglibService target = new AdminCglibService();AdminServiceCglibProxy proxyFactory = new AdminServiceCglibProxy(target);AdminCglibService proxy = (AdminCglibService)proxyFactory.getProxyInstance();System.out.println("代理对象:" + proxy.getClass());Object obj = proxy.find();System.out.println("find 返回对象:" + obj.getClass());System.out.println("----------------------------------");proxy.update();}
}

输出结果:

代理对象:class com.lance.proxy.demo.service.AdminCglibService$$EnhancerByCGLIB$$41b156f9
判断用户是否有权限进行操作
查看管理系统数据
记录用户执行操作的用户信息、更改内容和时间等
find 返回对象:class java.lang.Object
----------------------------------
判断用户是否有权限进行操作
修改管理系统数据
记录用户执行操作的用户信息、更改内容和时间等

总结

理解上述Java代理后,也就明白Spring AOP的代理实现模式,即加入Spring中的target是接口的实现时,就使用JDK动态代理,否是就使用Cglib代理。Spring也可以通过<aop:config proxy-target-class="true">强制使用Cglib代理,使用Java字节码编辑类库ASM操作字节码来实现,直接以二进制形式动态地生成 stub 类或其他代理类,性能比JDK更强

Java代理(Proxy)模式相关推荐

  1. Java 代理(proxy)模式

    代理模式(Proxy Pattern) 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代 ...

  2. 设计模式学习笔记——代理(Proxy)模式

    设计模式学习笔记--代理(Proxy)模式 @(设计模式)[设计模式, 代理模式, proxy] 设计模式学习笔记代理Proxy模式 基本介绍 代理案例 类图 实现代码 Printable接口 Pri ...

  3. 代理(Proxy)模式 vs. 代理(Agency)机构

    有一天,我将设计模式中的代理模式和我们社会中的代理机构联系起来.发现他们之间有非常多的相似的地方,而且可以互相借鉴. 在讨论这个话题之前,我的老板就率先指出了我的缺点.代理是Proxy不是Agency ...

  4. 当Android遇上设计模式之代理(Proxy)模式

    文章目录 1. 代理模式 1.1 代码实现 1.2 使用场景 2. 静态代理与动态代理 设计模式六大原则: 单一职责原则:就一个类仅有一个引起它变化的原因,即类承担的职责单一性: 开放封闭原则:类.模 ...

  5. 设计模式---代理(Proxy)模式

    1 定义 代理模式,为想要访问的对象创建一个代理,使访问原对象变为访问代理对象.代理模式可以提供非常好的访问控制.生活中最多的代理模式例子就是中介. 2 代理模式结构与实现 代理模式通用类图如下所示( ...

  6. Head First 设计模式 —— 13. 代理 (Proxy) 模式

    思考题 如何设计一个支持远程方法调用的系统?你要怎样才能让开发人员不用写太多代码?让远程调用看起来像本地调用一样,毫无瑕疵? P435 已经接触过 RPC 了,所以就很容易知道具体流程:客户端调用目标 ...

  7. 《研磨设计模式》chap11 代理proxy模式

    场景:需要查询所有用户数据,不能翻页都显示出来,只显示姓名,在需要的情况下,点击某个用户的姓名出现详细信息. 1. 正常编码:仅查询当前数据 public static void main(Strin ...

  8. 设计模式--代理(Proxy)模式

    模式定义 为其他对象提供一种代理以控制(隔离,使用接口)对这个对象的访问 类图 要点总结 "增加一层间接层"是软件系统中对许多复杂问题的一种常见解决方法,在面向对象系统中,直接使用 ...

  9. Java设计模式-Proxy代理模式

    问题分析: 什么是代理模式呢?其实我们在生活中并不少见.对于程序员来说最常接触的莫过于代理上网了,连接大力服务器地址,就可以访问网络. 还有每天吃饭赶进度是常事,叫公司的同事帮忙带饭也是一种代理:如果 ...

  10. 如何使用Proxy模式及Java内建的动态代理机制

    http://zhangjunhd.blog.51cto.com/113473/69996 1.Proxy模式 代理模式支持将某些操作从实际的对象中分离出来,通过它的代理类提供处理.这样便于修改和管理 ...

最新文章

  1. vs2015下载 简体中文版/企业版 附邀请码
  2. 干货 | 十年经验PM手机里都装了哪些app?
  3. SAP设置信贷控制范围有什么作用?
  4. python对列表进行分页_python列表分页
  5. 计算机专业论文要交源代码吗,计算机毕业论文源代码.doc
  6. 32位mysql安装包_软件测试基础——Linux系统搭建MySQL数据库
  7. VMware15设置快照回到指定时间的状态
  8. linux常见faq,Linux--FAQ 常见的问题与解答
  9. QoS mechanisms——LLQ(拥塞管理,低延时队列)
  10. why python?
  11. “裸辞” 备战15天三面美团,交叉面却被吊起来锤
  12. “博客之星”年度评选
  13. 牵手腾讯视频,爱普生离年轻人更近了
  14. Python 路径操作
  15. 曾经面试的一个关于文件操作的上机题
  16. 天津大学计算机学院博士生李楠,2015年天津大学各学院博士研究生拟录取名单公示汇总(更新中)...
  17. 2022 主站及创作侧年度总结 - 相信未来、期待未来
  18. 汇编语言ret与call指令
  19. OV7670摄像头的相关参数及时序分析
  20. 关于微信自动回复机器人

热门文章

  1. 实战|朝阳医院药品销售分析案例
  2. SEGGER 的硬件异常 分析
  3. win10便签常驻桌面_在win10桌面上能显示日程表小工具的便签怎么使用?
  4. RTK差分通讯链路---电台
  5. 海思EC6108V9盒子DIY固件打包方法
  6. ricequant量化交易文件如何保存和读取
  7. 记录|斐讯K2拆机使用ttl刷入breed并刷入新固件
  8. MAVEN setting.xml配置文件详解
  9. 什么是敏捷开发?它有什么特点
  10. 大牛总结目前最流行软件开发模式之敏捷开发(scrum)