什么是代理模式?
代理模式就是为其他对象提供一种代理来对该对象进行访问控制。
生活实例:
1)房产中介,他就是一个代理,由房东全权授权中介来进行房产的售前咨询,相关事宜的处理等。
2)滴滴代驾,就是授权代驾可以驾驶你的车辆,并将车辆行驶至目的地,期间代驾可以进行对车辆的一些简单的操作。
代理---“铁三角”:
-
抽象角色:
为“代理角色”和“真实角色”提供的一套对外的公共方法(一般定义为接口)
interface ProxyInterface {
fun confirmAction(inputString :String,name:String);
}
-
真实角色:
真正的业务实现逻辑,他需要实现“抽象角色”中的接口;
class RealInstance : ProxyInterface {
private val TAG = "RealInstance";
override fun confirmAction(inputString: String,name: String) {
Log.e(TAG,"真实实例对象----"+"调用confirmAction()")
}
}
-
代理角色:
他同“真实角色”一样,实现了“抽象角色”中的接口,同时拥有对“真实角色”的引用,然后通过“真实角色”的引用来实现“抽象角色”中的抽象方法,且可以自己在抽象方法中增加自己的一些操作等。
class ProxyInstance(realInstance: RealInstance) : ProxyInterface {
val TAG = "ProxyInstance";
var mRealInstance: RealInstance = realInstance
override fun confirmAction(inputString: String,name:String) {
Log.e(TAG, "我是代理,我的confirmAction被调用")
mRealInstance.confirmAction(inputString,name)
}
}
三者之间的类关系如图所示:
了解了上面的“铁三角”,那相信我们对代理模式就已经完全明白了代理模式了。。。。很简单吧!!!!别高兴的太早了,一步一步带你进去深渊。。。。
代理的用途:
- 通过引入代理对象的方式来间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性;
- 通过代理对象进行对访问的控制;
好,那我们就来聊聊怎么使用? 今天先聊一下静态代理和动态代理。
代理使用:
1)静态代理:
顾名思义,就是我们在实现代理模式时,在编辑阶段就需要将对象的代理者都准备好,在程序运行时使用。
val proxyInstance = ProxyInstance(RealInstance())
proxyInstance.confirmAction("测试代理模式","")
缺点:
1.当需要代理的真实角色多时,我们的代理对象是不是也需要很多,这样就会出现代理对象和代码量变大的情况
2.如果我们想要扩展一下抽象接口的方法,那么真实角色和代理角色都需要维护,这样是不是维护、扩展能力也比较差
既然静态代理有那么明显的缺点,我们有没有办法解决呢,答案是肯定的,这就是我们下面的动态代理。
2)动态代理:
相对于静态代理而言,动态代理则是在程序运行时再创建对象的代理类和实例,也就是说有程序帮我们去创建代理类及其实例,这样效率很明显要低些。
JDK已经为我们提供好了API了,我们直接用JDK API就可以了,如下:
val newProxyInstance = Proxy.newProxyInstance(RealInstance::class.java.classLoader,
arrayOf(ProxyInterface::class.java),
object : InvocationHandler {
override fun invoke(proxy: Any?, method: Method?, args: Array?): Any? {
if (args?.size!! > 1) {
return method?.invoke(RealInstance(), args[0],args[1])
}
return null
}
}
) as ProxyInterface
newProxyInstance.confirmAction("hello","我是代理对象");
上述代码中,有两个关键的API: Proxy和InvocationHandler,下面我们就深入“敌营”来了解一下。
源码剖析:
Proxy 提供了创建动态代理类和实例的静态方法,它也是有这些方法穿件的所有动态代理类的超类。是一个实现在运行时进行创建直接接口列表的类。
先来看看动态代理实现的流程图,
然后再看源码,下面源码已经做了详细的备注。
Proxy 类中的成员变量和方法:
package java.lang.reflect;//在此包下
/////////////////////////////////////////////////////////////////////////////////
//静态成员
private static final Class>[] constructorParams =
{ InvocationHandler.class };
/**
* 返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序。
*----loader - 类加载器来定义代理类---当前真实角色的类加载器
*----interfaces - 代理类实现的接口列表 他是一个数组:因为一个代理可以代理多个实例对象
*----h - 调度方法调用的调用处理函数
*/
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
//复制一份抽象接口类,并保存到数组中
final Class>[] intfs = interfaces.clone();
/*
* Look up or generate the designated proxy class.
* 查找或生成代理类
*/
Class> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
//获取代理类的public构造方法的引用
final Constructor> cons = cl.getConstructor(constructorParams);//constructorParams 静态成员
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
//使用带指定参数:h的构造器cons来生成该构造器所代表的代理类的实例,并将该代理类实例返回
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
///////////////////////////////////////////////////////////
/**
* a cache of proxy classes
代理类的缓存
*/
private static final WeakCache[], Class>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
从缓存中读取代理类,如果存在则直接返回该代理类,否则创建该代理类
*/
private static Class> getProxyClass0(ClassLoader loader,
Class>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
代理的缓存WeakCache
package java.lang.reflect;
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
//使用外部传入的key 生成cacheKey
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
//线程安全的原子操作担保 ConcurrentMap
ConcurrentMap
Invocationhandler接口类
//每一个代理类实例有一个相对应的InvocationHandler句柄,一旦代理类实例调用了其中一个method方法都会触发该句柄的invoke方法,并将相关信息返回
//1 proxy 代理类实例
//2 method ,调用的方法,
//3 args 该用法的参数
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
ProxyClassFactory 最终类通过反射来生成代理类
@Override
public Class> apply(ClassLoader loader, Class>[] interfaces) {
Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
for (Class> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use the default package.
proxyPkg = "";
}
{
// Android-changed: Generate the proxy directly instead of calling
// through to ProxyGenerator.
List methods = getMethods(interfaces);
Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
validateReturnTypes(methods);
List[]> exceptions = deduplicateAndGetExceptions(methods);
Method[] methodsArray = methods.toArray(new Method[methods.size()]);
Class>[][] exceptionsArray = exceptions.toArray(new Class>[exceptions.size()][]);
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
return generateProxy(proxyName, interfaces, loader, methodsArray,
exceptionsArray);
}
}
}
说了半天的动态代理,那么动态代理到底生成的类长啥样呢,我们如何才可以看到呢?
查询动态代理类
- 新建一个java module
- 将上述抽象接口和真实角色的class 考入java module中
- 新建一个ProxyUtils类
public static void generateClassFile(Class clazz,String proxyName)
{
byte[] classFile = ProxyGenerator.generateProxyClass(proxyName, clazz.getInterfaces());
String path = clazz.getResource(".").getPath();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(path + proxyName + ".class");
fos.write(classFile);
fos.flush();
}catch(Exception e) {
e.printStackTrace();
}finally {
try {
fos.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Subject subject=new Subject();//此处为真实角色的对象
ProxyInterface proxy =(ProxyInterface) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
new Class[]{ProxyInterface.class},
new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return null;
}
});
generateClassFile(Subject.class,"SubjectProxy");//第二个参数是生成的代理类名
proxy.confirmAction();
}
- 运行ProxyUtils类的Main函数,则会在build/classes/java/main/com/XXX/proxylib/目录下生成 SubjecProxy.class文件
- 分析一下这个class文件
1.他是一个最终类,并且继承Proxy ,实现了我们自己的抽象接口ProxyInterface
2.有一个public 修饰的构造函数,并且InvocationHandler作为参数
3.重写了Object的equals()、toString()、hasCode()方法
4.实现了抽象接口ProxyInterface的方法,方法体是使用InvocationHandler实例来调用它的invoke方法,并将代理实例、方法、参数作为参数回调回去
5.静态代码区:通过反射实现类名和方法的反射,并将反射的method存放到静态变量中
实际运行生成的代码如下:
public final class SubjectProxy extends Proxy implements ProxyInterface {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public SubjectProxy(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 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 confirmAction() throws {
try {
super.h.invoke(this, m3, (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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.leon.proxylib.ProxyInterface").getMethod("confirmAction");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
到此为止,已经将java的动态代理,代理模式包括相关源码的剖析都已经介绍完了,有需要的同学的可以自己跟着上面的额内容实操一下加强记忆。
知识点总结:
1、设计模式---代理模式
2、调用处理器InvocationHandler
3、Java反射机制
4、Map缓存机制
今天就学习到这里了,欢迎来踩点