您的位置:首页 > 其它

我需要了解的动态代理

2018-02-25 00:46 183 查看

一.说明

动态代理的思想是:代理模式+反射。

静态代理,代理者的代码是由程序员自己或者通过一些自动化工具生成,然后再进行编译。

动态代理则正好相反,通过反射机制动态的生成代理对象。

代理模式可参考下面的文章链接:

http://blog.csdn.net/a910626/article/details/50760980

反射可参考下面的文章链接:

http://blog.csdn.net/a910626/article/details/51111918

动态代理涉及的相关类:

动态代理主要的Java 类有java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler,下面是动态代理的UML类图。



java.lang.reflect.Proxy它提供了一组静态方法来为一组接口生成代理类和对象。

// 根据一组接口和类加载器来生成代理类的Class对象
public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces)
// 用来获取该代理类对象所关联的处理器
public static InvocationHandler getInvocationHandler(Object proxy)
// 用来判断是否是代理类
public static boolean isProxyClass(Class<?> cl)
//生成代理对象
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)


二.源码分析

Java的动态代理通过调用Proxy.newProxyInstance()方法生成代理对象。这个方法通过传入的三个参数类加载器、接口数组、调用处理器来生成动态代理对象。

public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}

/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, interfaces);

/*
* Invoke its constructor with the designated invocation handler.
*/
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
return newInstance(cons, h);
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}


1.getProxyClass0(loader, interfaces);

这个方法有些长,抽取关键地方分析

1)先抽取被代理类实现的接口Interface,检测是否符合要求

/* collect interface names to use as key for proxy class cache */
String[] interfaceNames = new String[interfaces.length];

// for detecting duplicates
Set<Class<?>> interfaceSet = new HashSet<>();

for (int i = 0; i < interfaces.length; i++) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
String interfaceName = interfaces[i].getName();
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(interfaceName, false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != interfaces[i]) {
throw new IllegalArgumentException(
interfaces[i] + " 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.contains(interfaceClass)) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
interfaceSet.add(interfaceClass);

interfaceNames[i] = interfaceName;
}


2)查看代理对象缓存中是否有我们要创建的代理类,如果有,直接获取;没有则创建

如果有则: return proxyClassCache.get(loader, interfaces);

没有则通过ProxyClassFactory创建。

这个类比较核心的方法如下:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);


我猜大致意思就是全转为字节码,运行时(runtime)生成代理对象字节码。

2.cl.getConstructor(constructorParams);

根据上一步生成的代理类Class对象,来获取到构造器。

3.newInstance(cons, h);

创建代理实例,将

newInstance(cons, ih);//将InvocationHandler h传入代理对象中

说明:

怎么看生成的代理对象的源码是什么样的呢?

可参考链接:

查看JDK动态代理生成的类的内容

http://blog.csdn.net/zknxx/article/details/77919332

以下是Proxy0的源码

public final class $Proxy0 extends Proxy implements Manager {

private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;

static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
m3 = Class.forName("com.ml.test.Manager").getMethod("modify",
new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}

public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}

@Override
public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))
.booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}

@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}

public final void modify() {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}

@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}


即生成的代理类的每个方法中都会调用InvocationHandler的invoke方法,并且会把方法名、代理对象、参数回调回去,我们可以在InvocationHandler的invoke方法中增加一些代码等效于在方法前后插入代码。

三.一个栗子

1.简单代理模式写法

public interface Subject {
void request();
}


public class RealSubject implements Subject {

@Override
public void request() {
System.out.println("---realsubject---");
}
}


public class ProxySubject implements Subject {
private RealSubject mRealSubject;

public ProxySubject(RealSubject realSubject) {
mRealSubject = realSubject;
}

@Override
public void request() {
mRealSubject.request();
}
}


public class Client {
public static void main(String[] args) {
ProxySubject proxySubject = new ProxySubject(new RealSubject());
proxySubject.request();
}
}


2.动态代理模式写法

public interface Subject {
void request();
}


public class ProxyHandler implements InvocationHandler {
private Subject mSubject;

public ProxyHandler(Subject subject) {
mSubject = subject;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("---before---");
Object result = method.invoke(mSubject, args);
System.out.print("---end---");
return result;
}
}


public class RealSubject implements Subject {

@Override
public void request() {
System.out.println("---realsubject---");
}
}


public class Client {
public static void main(String[] args) {
//        ProxySubject proxySubject = new ProxySubject(new RealSubject());
//        proxySubject.request();
RealSubject realSubject = new RealSubject();
ProxyHandler handler = new ProxyHandler(realSubject);
Subject proxyInstance = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), handler);
proxyInstance.request();
}
}


不过动态代理可以不用具体的实现类,直接代理接口类。

public class Client {
public static void main(String[] args) {
//        ProxySubject proxySubject = new ProxySubject(new RealSubject());
//        proxySubject.request();
//        RealSubject realSubject = new RealSubject();
//        ProxyHandler handler = new ProxyHandler(realSubject);
//        Subject proxyInstance = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), handler);
//        proxyInstance.request();

Subject subject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(),
new Class<?>[] { Subject.class },
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("dynamic Proxy");
return null;
}
}
);
subject.request();

}
}


这个动态代理的好处是你连RealSubject都不需要。

参考资料

Java 动态代理机制分析及扩展,第 1 部分

https://www.ibm.com/developerworks/cn/java/j-lo-proxy1/index.html

动态代理解析

http://blog.csdn.net/kyosky110/article/details/51911463

java 动态代理深度学习(Proxy,InvocationHandler),含$Proxy0源码

http://lijingshou.iteye.com/blog/1949134

戏说代理模式和Java动态代理

https://www.jianshu.com/p/0d919e54eef0
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: