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.代理模式的分类: 静态代 ...
随机推荐
- UVa 10129 Play on Words(有向图欧拉路径)
Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to s ...
- c++实现中的一些注意 事项
1,尽可能延后对象中的变量定义式的出现,这样可以增加程序的清晰度,尽量少的调用构造,如果有定义变量最好在末尾定义并给予初值,这样就避免了默认构造函数的调用. 2 尽量少做转型操作. const_cas ...
- java实现rabbitMQ延时队列详解以及spring-rabbit整合教程
在实际的业务中我们会遇见生产者产生的消息,不立即消费,而是延时一段时间在消费.RabbitMQ本身没有直接支持延迟队列功能,但是我们可以根据其特性Per-Queue Message TTL和 Dead ...
- swift4.2 - UIDynamic
1. SB放上俩 imageview,拖线成类属性 import UIKit class ViewController: UIViewController { @IBOutlet weak var b ...
- ReactPHP── PHP版的Node.js(转)
原文地址:http://www.csdn.net/article/2015-10-12/2825887 摘要:ReactPHP作为Node.js的PHP版本.在实现思路,使用方法,应用场景上的确有很多 ...
- css兼容性写法大全
淘宝初始化代码 body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, pre, form, fieldset ...
- Sobel Derivatives
https://docs.opencv.org/2.4/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.html ...
- .NET通用工具——正则表达式
正则表达式就是一组字符串运算规则,你需要先把元字符记熟,然后就可以随意组合获得你想要的结果.把一些常用的正则表达式背下来也是一种方法,再加以变化获得你想要的结果. 正则表达式不需要刻意的去学习,当用到 ...
- docker-ce-17.09 网络基础配置
一.端口映射实现访问容器 1.我们先从pull一个nginx镜像,然后后台运行该镜像 > docker pull nginx > docker run -d -P nginx:latest ...
- JS正则表达式验证是否为11位有效手机号码
function isPoneAvailable($poneInput) { var myreg=/^[1][3,4,5,7,8][0-9]{9}$/; if (!myreg.test($poneIn ...