java常用设计模式八:代理模式
一、概述
代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。 其特征是代理类与委托类有同样的接口,真正的核心业务逻辑还是在实际对象里面。
二、为什么要使用代理模式
- 当客户端不想直接调用实际对象,或是客户端直接调用实际对象有困难。
- 比如:想在实际对象的业务方法执行前或执行后额外处理一些事情。但是又不能修改原来的实际对象的方法,这时候也可以用代理模式。
三、代理模式的分类
1、静态代理(在程序运行前,代理类的.class文件已经存在,所以称为静态代理)
1)原业务接口
public interface SourceObject {
void operation();
}
2)原业务接口的实现类
public class SourceObjectImpl implements SourceObject {
public void operation() {
System.out.println("这是原业务核心方法");
}
}
3)静态代理类
public class StaticProxy implements SourceObject {
private SourceObjectImpl srcObj;
public StaticProxy(SourceObjectImpl srcObj){
this.srcObj = srcObj;
}
public void operation() {
System.out.println("原业务方法执行前:记录处理中日志");
srcObj.operation();
System.out.println("原业务方法执行前:记录完成日志");
}
}
public class StaticProxy implements SourceObject {
private SourceObject srcObj;
public StaticProxy(SourceObject srcObj){
this.srcObj = srcObj;
}
public void operation() {
System.out.println("原业务方法执行前:记录处理中日志");
srcObj.operation();
System.out.println("原业务方法执行前:记录完成日志");
}
}
4)测试类
public class Client {
public static void main(String[] args){
SourceObject srcObj = new SourceObjectImpl();
StaticProxy staticProxy = new StaticProxy(srcObj);
staticProxy.operation();
}
}
原业务方法执行前:记录处理中日志
这是原业务核心方法
原业务方法执行前:记录完成日志
由以上的结构可知:每个接口(SourceObject)有一个与之对应的代理类(StaticProxy),如果再有一个接口,那么就要同时新增一个代理类,这种情况在接口很多的时候,就会产生很多代理类。是否能只有一个代理类呢?当然是可以的,就是动态代理
2、动态代理(在程序运行前,代理类的.class文件不存在,是运行时序由Java反射机制动态生成)
动态代理主要是借助 类Proxy、接口InvocationHandler 来实现的。下面以一个具体的例子来说明 动态代理的过程
1)原业务接口
public interface SourceObject {
void operation();
}
2)原业务接口的实现类
public class SourceObjectImpl implements SourceObject {
public void operation() {
System.out.println("这是原业务核心方法");
}
}
3)新建动态代理类处理器(注意,该类并不是SourceObject的代理类,它并没有实现于接口SourceObject,因此它不能调用operation()方法,这是与静态代理 最大的不同之处,代理类是程序运行的时候才动态产生的。)
public class DynamicProxyHandler implements InvocationHandler {
private Object srcObj;//被代理的实际对象,定义为Object类型表明,可以是任意对象 /**
* 该方法负责动态创建代理类,并返回代理类的实例,这个实例的类继承于java.lang.reflect.Proxy,还实现了传入进来的srcObject的原业务接口。
*
* @param srcObj
* @return
*/
public Object getProxyInstance(Object srcObj) {
this.srcObj = srcObj;
return Proxy.newProxyInstance(srcObj.getClass().getClassLoader(), srcObj.getClass().getInterfaces(), this);
} /**
* 注意:客户端不会真正的显示调用该方法,当通过getProxyInstance取得的实例执行真正的方法时,该方法会执行。
*
* @param proxy 参数传递的是动态生成的代理类的实例,本方法并没有使用它
* @param method 是调用的方法,即需要执行的方法
* @param args 是执行方法的参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("原业务方法执行前:记录处理中日志");
System.out.println("invoke 方法的第一个参数proxy 的类是:" + proxy.getClass().toString());
method.invoke(srcObj, args);
System.out.println("原业务方法执行前:记录完成日志");
return null;
}
}
4)测试类
public class Client {
public static void main(String[] args){
SourceObject srcObj = new SourceObjectImpl();
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
//为什么这里可以用SourceObject来接收getProxyInstance返回的实例呢?从后面的结果可知道动态产生的代理类实质上是继承于Proxy类,并实现于SourceObject
SourceObject dynamicProxyInstance = (SourceObject)dynamicProxyHandler.getProxyInstance(srcObj);
System.out.println("dynamicProxyInstance 的类是:================="+dynamicProxyInstance.getClass().toString());
System.out.println("dynamicProxyInstance 的父类是:==============="+dynamicProxyInstance.getClass().getSuperclass());
System.out.println("dynamicProxyInstance 实现的接口如下:===========");
Class<?>[] interfaces=dynamicProxyInstance.getClass().getInterfaces();
for(Class<?> i:interfaces){
System.out.println(i.getName());
}
System.out.println("dynamicProxyInstance 的方法有:===============");
Method[] method=dynamicProxyInstance.getClass().getDeclaredMethods();
for(Method m:method){
System.out.println(m.getName());
}
//执行真正的核心业务方法
System.out.println("dynamicProxyInstance 执行原业务方法:===============");
dynamicProxyInstance.operation(); //以下的代码是将动态生成的代理类保存到target的classes里面,便于查看。
byte[] bts = ProxyGenerator.generateProxyClass("$Proxy0", interfaces);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(new File("target/classes/proxy/demo/$Proxy0.class"));
fos.write(bts);
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
dynamicProxyInstance 的类是:=================class com.sun.proxy.$Proxy0
dynamicProxyInstance 的父类是:===============class java.lang.reflect.Proxy
dynamicProxyInstance 实现的接口如下:===========
proxy.demo.SourceObject
dynamicProxyInstance 的方法有:===============
equals
toString
hashCode
operation
dynamicProxyInstance 执行原业务方法:===============
原业务方法执行前:记录处理中日志
invoke 方法的第一个参数proxy 的类是:class com.sun.proxy.$Proxy0
这是原业务核心方法
原业务方法执行前:记录完成日志
由以上结果可知:程序运行时动态生成了一个代理类com.sun.proxy.$Proxy0,它的父类是Proxy,并且还实现了接口SourceObject。这个代理类是由Proxy的 newProxyInstance 方法生成的。生成的代理类的源代码如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
// import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import proxy.demo.SourceObject; public final class $Proxy0 extends Proxy implements SourceObject {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0; public $Proxy0(InvocationHandler var1) throws {
super(var1);
} public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
} public final void operation() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
} static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("proxy.demo.SourceObject").getMethod("operation");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
当调用 dynamicProxyInstance.operation() 的时候,实质上就是调用了以上生成的代理类中红色标注的方法。
super.h.invoke(this, m3, (Object[])null);
super就是指父类Proxy,h就是指InvocationHandler的实例,这里应该是传入的子类DynamicProxyHandler 的实例,所以h.invoke方法,就是执行DynamicProxyHandler的invoke方法。
java常用设计模式八:代理模式的更多相关文章
- Java设计模式11:常用设计模式之代理模式(结构型模式)
1. Java之代理模式(Proxy Pattern) (1)概述: 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象 ...
- Java基础-设计模式之-代理模式Proxy
代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理 ...
- 基于JAVA的设计模式之代理模式
概念 王宝强有一个经纪人叫宋喆,这个经纪人很吊,可以代理王宝强做一系列的事情,与粉丝活动.王宝强的微博维护.安排王宝强的行程以及什么什么等等.如果王宝强一个人做岂不是累死.通过这个代理人为王宝强节省了 ...
- Java常见设计模式之代理模式
指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其它相关业务的处理.比如生活中的通过代理访问网络,客户通过网络代理连接网络(具体业务),由代理服务器完成用户权限和访问限制等与 ...
- java常用设计模式总览
一.java的设计模式大体上分为三大类: 创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式. 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组 ...
- Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景
我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...
- 夜话JAVA设计模式之代理模式(Proxy)
代理模式定义:为另一个对象提供一个替身或者占位符以控制对这个对象的访问.---<Head First 设计模式> 代理模式换句话说就是给某一个对象创建一个代理对象,由这个代理对象控制对原对 ...
- Java设计模式:代理模式(转)
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一 ...
- java设计模式6——代理模式
java设计模式6--代理模式 1.代理模式介绍: 1.1.为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc) 1.2.代理模式的分类: 静态代 ...
随机推荐
- maven 常用参数使用详解
前言 作为java开发按人员,使用maven构建似乎成为了工作中平常的事情,但有时会遇到一些问题,感到困惑,于是我整理出来,方便其他同学更好的使用,以后会慢慢更新这个文章. 命令介绍 -DskipTe ...
- php解析优酷网上的视频资源去广告
1.过程原理解析: 一.准备工作 所谓工欲善其事必先利其器,做好破解的准备工作会令你事半功倍. 1.首先准备一个Http抓包工具,PC上推荐Fiddler或者Postman,iOS上推荐Surge 2 ...
- BTC和BCH 区别和联系?
在比特币刚刚出现的时期,中本聪对区块的大小限制在1M.这种限制既保障性能较弱的个人电脑能够参与其中,同时也起到了防止攻击者让比特币网络超载的风险发生,毕竟那时系统还很脆弱.在1M的限制下,10分钟一个 ...
- python multiprocessing 和tcp
#用类方法 服务端 from socket import *from multiprocessing import Processimport os class Myprocess(Process): ...
- 深入理解HTTP协议及原理分析
1. 基础概念篇 1.1 介绍 HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写.它的发展是万维网协会(World Wide Web Consortium)和 ...
- 关于opencv中的颜色模型转换之CV_BGR2HSV
1.opencv函数cvCvtColor(rgb_im,hsv_im,CV_BGR2HSV)中使用的RGB颜色空间转到HSV算法: max=max(R,G,B) min=min(R,G,B) if R ...
- c#devexpres窗体划分 以及panelcontrol 相关操作
想模仿flashfxp 做一个svn上传的客户端 左侧为本地目录,右侧为svn服务器目录 准备用devexpress 的 控件实现,顺便练习一下devexpress 相关使用. 1:要实现菜单栏工具 ...
- matlab函数拟合
1 函数拟合 函数拟合在工程(如采样校正)和数据分析(如隶属函数确定)中都是非常有用的工具.我这里将函数拟合分为三类:分别是多项式拟合,已知函数类型的拟合和未知函数类型的拟合.matlab中关于函数的 ...
- Hyperscan与Snort的集成方案
概况 Hyperscan作为一款高性能的正则表达式匹配库,非常适用于部署在诸如DPI/IPS/IDS/NGFW等网络解决方案中.Snort (https://www.snort.org) 是目前应用最 ...
- N! (数组)
#include <iostream> using namespace std; ; int f[MAXN]; int main(){ int n; cin >> n; f[] ...