动态代理设计模式的原理:使用一个代理对象将原对象(目标对象)包装起来,然后利用该代理对象取代原对象。
任何对原对象的调用都要经过代理。代理对象决定是否以及何时将方法调用转到原对象上。
1 基于接口的动态代理 : 如 JDk 提供的代理
2 基于继承的动态代理 : 如第三方包 Cglib,javassist 动态代理
(1)创建被代理接口
package com.zzq.mybatis.proxy.jdk;
/**
* 接口
*/
public interface Person {
void sayHello(String say);
}
(2)创建被代理类(目标类)
package com.zzq.mybatis.proxy.jdk;
/**
* 目标类(被代理对象)
*/
public class Student implements Person {
@Override
public void sayHello(String say) {
System.out.println("student say :" + say);
}
}
(3)创建InvocatoinHanler的实现类
package com.zzq.mybatis.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 代理 handler
*/
public class PersonHandler implements InvocationHandler {
//代理的目标对象
private T target;
public PersonHandler(T target) {
this.target = target;
}
/***
*
* proxy : 动态代理对象
* method : 目标对象的方法
* args : 目标对象的方法参数
*
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" 动态代理对象 : " + proxy.getClass());
System.out.println(" 正在被调用的方法方法对象 : " + method);
System.out.println(" 正在被调用的方法方法名 : " + method.getName());
System.out.println(" 正在被调用的方法参数 : " + Arrays.asList(args));
// 调用开始前的操作
ProxyUtil.start();
// 调用方法,通过反射的形式来调用 target 的 method
Object object = method.invoke(this.target, args);
// 调用结束后的操作
ProxyUtil.finish();
return object;
}
}
(4)ProxyUtil
package com.zzq.mybatis.proxy.jdk;
/**
* ProxyUtil 类
*/
public class ProxyUtil {
public static void start() {
System.out.println("ProxyUtil.start()");
}
public static void finish() {
System.out.println("ProxyUtil.finish()");
}
}
(5)测试类
package com.zzq.mybatis.proxy.jdk;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//创建需要被代理对象(目标对象)
Person person = new Student();
//获取被代理类(目标对象)类加载器
ClassLoader loader = Person.class.getClassLoader();
//指明被代理对象(目标对象)的接口
Class>[] interfaces = person.getClass().getInterfaces();
//创建一个代理对象处理类
PersonHandler h = new PersonHandler<>(person);
/***
*
* Proxy : 所有动态代理对象的父类,专门用于生成代理类对象或者代理对象
* loader : 目标对象的类加载器
* interfaces :目标对象的接口
* h :代理对象的执行处理器
*
*/
//这里创建代理对象,使得代理对象和目标对象拥有相同的方法行为,h是代理对象调用处理执行的方法。
Person proxy = ( Person ) Proxy.newProxyInstance(loader, interfaces, h);
proxy.sayHello(" hello proxy");
}
}
1、创建被代理接口和类
2、创建InvocatoinHanler的实现类,在invoke方法实现代理逻辑
3、通过Proxy静态方法newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h)创建一个代理对象
4、使用代理对象
入口
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*
*/
//查找或生成指定的代理类
Class> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//获取代理类的实例
final Constructor> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
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);
}
}
getProxyClass0
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
// JDK对代理进行了缓存,如果已经存在相应的代理类,则直接返回,否则才会通过ProxyClassFactory来创建代理
return proxyClassCache.get(loader, interfaces);
}
点击proxyClassCache
/**
* a cache of proxy classes
*/
private static final WeakCache[], Class>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
点击ProxyClassFactory
/**
* A factory function that generates, defines and returns the proxy class given
* the ClassLoader and array of interfaces.
*/
private static final class ProxyClassFactory
implements BiFunction[], Class>>
{
// prefix for all proxy class names
// 所有代理类名字的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
//生成一个数字,保证唯一性,用于代理类的名称
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@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.
*/
//验证类加载器中是否有当前接口intf的对象
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.
*/
//判断是否有非Public的接口,这样包名就使用非公共接口的包名,否则使用公共默认包名
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");
}
}
}
//当不存在非公共接口时,使用默认包名 com.sun.proxy
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
//选择要生成的代理类的名称
//默认情况下,代理类的完全限定名为:com.sun.proxy.$Proxy0,com.sun.proxy.$Proxy1……依次递增
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
//生成指定的代理类文件
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//返回代理类class对象
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
JDK动态代理代理类文件查看
执行在d盘生成一个$Proxy0.class文件
package com.zzq.mybatis.proxy.jdk;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Proxy;
import sun.misc.ProxyGenerator;
public class DynamicProxyTest {
public static void main(String[] args) {
Person target = new Student();
PersonHandler handler = new PersonHandler(target);
//第一个参数是指定代理类的类加载器(我们传入当前测试类的类加载器)
//第二个参数是代理类需要实现的接口(我们传入被代理类实现的接口PersonHandler样生成的代理类和被代理类就实现了相同的接口)
//第三个参数是invocation handler,用来处理方法的调用。这里传入我们自己实现的handler
Person proxyObject = (Person) Proxy.newProxyInstance(DynamicProxyTest.class.getClassLoader(),
target.getClass().getInterfaces(), handler);
proxyObject.sayHello("zzq");
String path = "D:/$Proxy0.class";
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", Student.class.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
利用反编译软件jd-gui.exe编译
import com.zzq.mybatis.proxy.jdk.Person;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class Proxy0 extends Proxy
implements Person
{
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public Proxy0()
throws
{
super(paramInvocationHandler);
}
public final boolean equals()
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void sayHello()
throws
{
try
{
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return ((String)this.h.invoke(this, m2, null));
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.zzq.mybatis.proxy.jdk.Person").getMethod("sayHello", new Class[] { Class.forName("java.lang.String") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
JVM生成代理对象过程
1、使用java自带api,将java代码编译成字节码
2、通过Classloader将class文件加载到jvm内存中
3、创建InvocationHandler对象
4、根据加载到的class信息去创建代理对象,并将invocationHandler对象传入
参考 : https://segmentfault.com/a/1190000019600172