1、什么是动态代理
使用jdk的反射机制,创建java对象的能力。创建的是代理类的对象。
在程序执行时,调用jdk提供的方法动态的指定要代理目标类。
2、动态代理能做什么
在不改变原有目标方法功能的前提下,在代理中增强自己的功能代码。
3、实现类
java.lang.reflect 反射包下3个类:
-
public interface InvocationHandler 接口:你的代理需要做什么)
invoke() 方法:代理需要做的具体功能
/**
* Object proxy: jdk创建的额代理对象
* Method method: 目标对象的方法
* Object[] args: 目标对象的方法的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
- public final class Method 类:可以执行目标类中的方法;method.invoke(目标对象, 方法参数);
- public class Proxy 类:创建的代理对象;Proxy.newProxyInstance();
/**
* 创建动态代理对象 等用于new
* ClassLoader loader: 目标对象的类加载器
* Class<?>[] interfaces: 目标对象的实现的接口
* InvocationHandler h: 代理类要做什么
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
4、具体步骤
- 创建功能的接口,定义目标类要完成的功能方法
- 创建目标接口的实现类,实现功能方法
- 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能 【调用目标类的功能方法 + 增强功能(补充的功能)】
- 使用Proxy类的静态方法newProxyInstance,创建代理对象。 并把返回值转为接口类型。
5、代码
//创建功能的接口
public interface HelloService {
//定义目标类要完成的功能方法
String sayHello(String s);
}
//创建目标接口的实现类
public class HelloWorldImpl implements HelloService {
//实现功能方法
@Override
public String sayHello(String s) {
return s + " hello world";
}
}
//创建InvocationHandler接口的实现类
public class HelloInvocationHandler implements InvocationHandler {
//目标对象
public Object target;
//通过构造方法,将目标对象传入
public HelloInvocationHandler(Object target) {
this.target = target;
}
//在invoke方法中完成代理类的功能
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用目标方法
//target:目标对象,args:方法参数
Object result = method.invoke(target, args);
//增强功能
if (result != null) {
String s = (String)result;
result = s.concat(",hello java");
}
return result;
}
}
//启动类
public class HelloMain {
public static void main(String[] args) {
//目标对象
HelloService helloService = new HelloWorldImpl();
HelloInvocationHandler handler = new HelloInvocationHandler(helloService);
//使用Proxy类的静态方法newProxyInstance,创建代理对象。 并把返回值转为接口类型
//创建动态代理对象 等用于new
//参数1 类加载器,目标对象的类加载器
//参数2 接口,目标对象的实现的接口
//参数3 处理器,代理类要完成的功能
HelloService proxy = (HelloService)Proxy.newProxyInstance(
helloService.getClass().getClassLoader(),
helloService.getClass().getInterfaces(),
handler);
//使用代理对象的方法
String say = proxy.sayHello("say");
System.out.println(say);
}
}
6、原理
分析 Proxy.newProxyInstance 具体做了什么
java.lang.reflect.Proxy newProxyInstance() 方法
关注: Class<?> cl = getProxyClass0(loader, intfs);
//java.lang.reflect.Proxy
@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.
* 调用getProxyClass0方法生成代理类的字节码文件 【跳转到getProxyClass0()方法】
*/
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<Void>() {
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);
}
}
java.lang.reflect.Proxy getProxyClass0 方法
关注: return proxyClassCache.get(loader, interfaces)
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
// 如果缓存中已经存在相应接口的代理类,直接返回;否则,使用ProxyClassFactory创建代理类【跳转到get()方法】
return proxyClassCache.get(loader, interfaces);
}
java.lang.reflect.WeakCache get() 方法
//此处为缓存逻辑,可以不看,具体看使用ProxyClassFactory创建代理类【跳转ProxyClassFactory】
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
java.lang.reflect.Proxy ProxyClassFactory 静态内部类
关注: byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
//实现了BiFunction接口,实现了BiFunction接口中的apply方法。
//当WeakCache中没有缓存相应接口的代理类,则会调用ProxyClassFactory类的apply方法来创建代理类。
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], 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<Class<?>, 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 com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
* 生成代理类的字节码文件
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
//使用类加载器将代理类的字节码文件加载到JVM中
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());
}
}
}
sun.misc.ProxyGenerator generateProxyClass 方法
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
从generateProxyClass() 方法可以看出,这是实际生成class字节码文件的地方,于是我们手动调用这个方法,将字节码内容写入文件中
手动触发字节码内容写入文件
public static void main(String[] args) {
byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", HelloWorldImpl.class.getInterfaces());
String path = "F:\\IDEAProject\\Practice\\src\\main\\java\\com.sun.proxy\\HelloWorldImpl.class";
try (FileOutputStream fileOutputStream = new FileOutputStream(path);) {
fileOutputStream.write(bytes);
fileOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("class 写入完毕");
}
字节码文件生成
字节码文件具体内容
//
// 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.HelloService;
public final class $Proxy0 extends Proxy implements HelloService {
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 String sayHello(String var1) throws {
try {
return (String)super.h.invoke(this, m3, 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 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.HelloService").getMethod("sayHello", Class.forName("java.lang.String"));
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());
}
}
}
分析
- 继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
- 提供了一个使用InvocationHandler作为参数的构造方法。
生成静态代码块来初始化接口中方法的Method对象,以及Object类的equals、hashCode、toString方法。 - 重写了Object类的equals、hashCode、toString,它们都只是简单的调用了InvocationHandler的invoke方法,即可以对其进行特殊的操作,也就是说JDK的动态代理还可以代理上述三个方法。
- 代理类实现代理接口的sayHello方法中,只是简单的调用了InvocationHandler的invoke方法,我们可以在invoke方法中进行一些特殊操作,甚至不调用实现的方法,直接返回。
问题
1)为什么jdk动态代理必须要基于接口来完成?
JDK动态代理生成的对象默认是继承Proxy,Java不支持多继承
2)代理类名称是包名结构?
3)jdk动态代理与cglib动态代理 区别?
4)在目标对象的方法A内部调用目标对象的其他方法B,此时动态代理并不会对方法B进行增强。
5)@Transactional @Async 注解失效?
在Spring项目中,通过@Transactional来声明事务时,出现了事务不生效的情况,以及@Async等案例,在同一个类的两个方法中开启异步,然后在方法内部进行互相调用,最终导致异步失效的问题。
注解是通过Spring AOP 实现的,如果动态代理使用的是JDK动态代理,那么在方法的内部调用该方法中其他带有该注解的方法,由于此时调用的不是动态代理对象,所以注解失效。
6)JDK动态代理中,目标对象调用自己的另一个方法时,会经过代理对象么?
内部调用方法使用的对象是目标对象本身,被调用的方法不会经过代理对象。
7、下一篇文章
介绍 cglib 动态代理