java常用设计模式八:代理模式

时间:2023-03-10 03:31:51
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方法。