代理模式
:
定义:为其他对象提供一种代理以控制对这个对象的访问。通俗的讲就是中介。
【主要角色】
Subject
: 抽象主题角色,是真实主题和它的代理共用的接口,使 RealSubject 和 Proxy 具有一致性。
RealSubject
:真实主题角色,实现了具体业务的方法。
Proxy
:代理角色,提供了与真实主题相同的方法,其内部含有对真实主题的引用。
一、静态代理
代理类在程序运行前就已经存在。通常情况下,静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类。
// 艺人
public interface Artist{
// 展示技能
void showSkills();
}
// 歌手
public class Singer implements Artist{
@Override
public void showSkills(){
System.out.println("歌手唱歌");
}
}
// 经纪人代理类
public class AgentProxy implements Artist{
private Artist artist;
public AgentProxy(final Artist artist){
this.artist = artist;
}
@Override
public void showSkills(){
System.out.println("经纪人处理前期工作");
artist.showSkills();
System.out.println("经纪人处理后期工作");
}
}
// 测试
public class Test{
public static void main(String[] args){
Artist artist = new Singer();
// 直接就唱歌了
artist.showSkills();
// 通过代理,处理与歌手无关的事情
AgentProxy agentProxy = new AgentProxy(artist);
agentProxy.showSkills();
/**
*输出结果如下:
*
*经纪人处理前期工作
*唱歌
*经纪人处理后期工作
*/
}
}
二、动态代理
动态处理器与实现类不存在关联。动态代理是代理类在程序运行时通过反射机制动态创建的。
// 艺人
public interface Artist{
// 展示技能
void showSkills();
}
// 歌手
public class Singer implements Artist{
@Override
public void showSkills(){
System.out.println("歌手唱歌");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyHandler implements InvocationHandler{
private Object obj;
// 创建对象的代理
public Object create(Object obj){
this.obj = obj;
// 传入对象,创建该对象的代理。
Object proxy = Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
this);
return proxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("经纪人处理前期工作");
Object result = method.invoke(obj, args);
System.out.println("经纪人处理后期工作");
return result;
}
}
// 测试
public class Test{
public static void main(String[] args){
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
Artist artist = new Singer();
Artist artistProxy = (Artist)dynamicProxyHandler.create(artist);
artistProxy.showSkills();
}
}
补充一:
InvocationHandler
接口只有 invoke
方法。
每一个动态代理类都必须要实现InvocationHandler
这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由 InvocationHandler
这个接口的 invoke
方法来进行调用。
/**
* {@code InvocationHandler} is the interface implemented by
* the <i>invocation handler</i> of a proxy instance.
*
* <p>Each proxy instance has an associated invocation handler.
* When a method is invoked on a proxy instance, the method
* invocation is encoded and dispatched to the {@code invoke}
* method of its invocation handler.
*
*/
public interface InvocationHandler {
/*
* @param [proxy] the proxy instance that the method was invoked on
*
* @param [method] the {@code Method} instance corresponding to
* the interface method invoked on the proxy instance. The declaring
* class of the {@code Method} object will be the interface that
* the method was declared in, which may be a superinterface of the
* proxy interface that the proxy class inherits the method through.
*
* @param [args] an array of objects containing the values of the
* arguments passed in the method invocation on the proxy instance,
* or {@code null} if interface method takes no arguments.
* Arguments of primitive types are wrapped in instances of the
* appropriate primitive wrapper class, such as
* {@code java.lang.Integer} or {@code java.lang.Boolean}.
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
补充二:
查看 Proxy 类,其中调用了 ProxyGenerator.generateProxyClass() 方法,如下(印证补充一):
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
作如下试验:
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
public class Test{
public static void main(String[] args){
Artist artist = new Singer();
byte[] gengarateProxyClass = ProxyGenerator.generateProxyClass("$Proxy1",
new Class[{ artist.getClass() });
try {
FileOutputStream fos = new FileOutputStream("C:/$Proxy1.class" );
fos.write(gengarateProxyClass);
fos.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
}
得到 $Proxy1.class 文件,反编译结果如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy1 extends Proxy implements Singer {
private static Method m1;
private static Method m8;
private static Method m2;
private static Method m6;
private static Method m3;
private static Method m5;
private static Method m7;
private static Method m9;
private static Method m0;
private static Method m4;
public $Proxy1(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 notify() throws {
try {
super.h.invoke(this, m8, (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 void wait(long var1) throws InterruptedException {
try {
super.h.invoke(this, m6, new Object[]{var1});
} catch (RuntimeException | InterruptedException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
/*当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发
*为由 InvocationHandler 这个接口的 invoke 方法来进行调用。
*/
public final void showSkills() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void wait(long var1, int var3) throws InterruptedException {
try {
super.h.invoke(this, m5, new Object[]{var1, var3});
} catch (RuntimeException | InterruptedException | Error var5) {
throw var5;
} catch (Throwable var6) {
throw new UndeclaredThrowableException(var6);
}
}
public final Class getClass() throws {
try {
return (Class)super.h.invoke(this, m7, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void notifyAll() throws {
try {
super.h.invoke(this, m9, (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);
}
}
public final void wait() throws InterruptedException {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | InterruptedException | 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"));
m8 = Class.forName("Singer").getMethod("notify");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m6 = Class.forName("Singer").getMethod("wait", Long.TYPE);
m3 = Class.forName("Singer").getMethod("showSkills");
m5 = Class.forName("Singer").getMethod("wait", Long.TYPE, Integer.TYPE);
m7 = Class.forName("Singer").getMethod("getClass");
m9 = Class.forName("Singer").getMethod("notifyAll");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m4 = Class.forName("Singer").getMethod("wait");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}