JDK动态代理#
public interface ClothesFactory {
void makeClothes ( ) ;
}
public class ClothesFactoryImpl implements ClothesFactory {
@Override
public void makeClothes ( ) {
System . out. println ( "I make clothes!" ) ;
}
}
public Object getProxyInstance ( ClothesFactory factory) {
return Proxy . newProxyInstance ( factory. getClass ( ) . getClassLoader ( ) , factory. getClass ( ) . getInterfaces ( ) , new InvocationHandler ( ) {
@Override
public Object invoke ( Object proxy, Method method, Object [ ] args) throws Throwable {
System . out. println ( "fire" ) ;
method. invoke ( factory, args) ;
return null ;
}
} ) ;
}
@Test
public void proxyTest ( ) {
ClothesFactoryImpl factory = new ClothesFactoryImpl ( ) ;
ClothesFactory proxyInstance = ( ClothesFactory ) getProxyInstance ( factory) ;
proxyInstance. makeClothes ( ) ;
}
直观的感受就是先获取到了实际被代理接口的method
,将method
作为参数传入到invoke
方法,然后在method.invoke
前面和后面写逻辑
Proxy.newProxyInstance
是如何返回一个被代理接口的实例?
代理实现中如何获取到了被代理接口的method
?
java.lang.reflect.Proxy.ProxyClassFactory
是java.lang.reflect.Proxy
的内部类
private static final class ProxyClassFactory
implements BiFunction < ClassLoader , Class < ? > [ ] , Class < ? > >
{
private static final String proxyClassNamePrefix = "$Proxy" ;
private static final AtomicLong nextUniqueNumber = new AtomicLong ( ) ;
@Override
public Class < ? > apply ( ClassLoader loader, Class < ? > [ ] interfaces) {
. . . . . .
byte [ ] proxyClassFile = ProxyGenerator . generateProxyClass (
proxyName, interfaces, accessFlags) ;
try {
return defineClass0 ( loader, proxyName,
proxyClassFile, 0 , proxyClassFile. length) ;
. . . . . .
}
}
@Test
public void defineClass ( ) throws InvocationTargetException , IllegalAccessException , InstantiationException , NoSuchMethodException , IOException
{
Method defineClass0 = Proxy . class . getDeclaredMethod ( "defineClass0" , new Class [ ] { ClassLoader . class , String . class , byte [ ] . class , int . class , int . class } ) ;
Constructor < Proxy > declaredConstructor = Proxy . class . getDeclaredConstructor ( ) ;
declaredConstructor. setAccessible ( true ) ;
String proxyName = "com.wangfan.proxy.MyProxy" ;
byte [ ] proxyClassFile = ProxyGenerator . generateProxyClass ( proxyName, new Class [ ] { ClothesFactory . class } , Modifier . PUBLIC ) ;
outPutToFile ( proxyClassFile) ;
Class proxyClass = ( Class ) defineClass0. invoke ( declaredConstructor. newInstance ( ) , ClothesFactory . class . getClassLoader ( ) , proxyName, proxyClassFile, 0 , proxyClassFile. length) ;
ClothesFactoryImpl clothesFactory = new ClothesFactoryImpl ( ) ;
Constructor constructor = proxyClass. getConstructor ( new Class [ ] { InvocationHandler . class } ) ;
constructor. setAccessible ( true ) ;
ClothesFactory factory = ( ClothesFactory ) constructor. newInstance ( new Object [ ] { ( InvocationHandler ) ( proxy, method, args) -> {
System . out. println ( "fire" ) ;
method. invoke ( clothesFactory, args) ;
return null ;
} } ) ;
factory. makeShoes ( ) ;
}
private void outPutToFile ( byte [ ] proxyClassFile) throws IOException {
String filepath = "D:\\Code\\Study\\MyProxy.class" ;
File file = new File ( filepath) ;
if ( file. exists ( ) ) {
file. delete ( ) ;
}
FileOutputStream fos = new FileOutputStream ( file) ;
fos. write ( proxyClassFile, 0 , proxyClassFile. length) ;
fos. flush ( ) ;
fos. close ( ) ;
}
package com. wf. proxy ;
import com. wf. proxy. jdk. ClothesFactory ;
import java. lang. reflect. InvocationHandler ;
import java. lang. reflect. Method ;
import java. lang. reflect. Proxy ;
import java. lang. reflect. UndeclaredThrowableException ;
public class MyProxy extends Proxy implements ClothesFactory {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public MyProxy ( 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 makeShoes ( ) throws {
try {
super . h. invoke ( this , m3, ( 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 makeClothes ( ) throws {
try {
super . h. invoke ( this , m4, ( 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 ( "com.wf.proxy.jdk.ClothesFactory" ) . getMethod ( "makeShoes" ) ;
m2 = Class . forName ( "java.lang.Object" ) . getMethod ( "toString" ) ;
m4 = Class . forName ( "com.wf.proxy.jdk.ClothesFactory" ) . getMethod ( "makeClothes" ) ;
m0 = Class . forName ( "java.lang.Object" ) . getMethod ( "hashCode" ) ;
} catch ( NoSuchMethodException var2) {
throw new NoSuchMethodError ( var2. getMessage ( ) ) ;
} catch ( ClassNotFoundException var3) {
throw new NoClassDefFoundError ( var3. getMessage ( ) ) ;
}
}
}
JDK动态代理实际上是通过根据代理类全限定名和被代理接口,生成一个byte[]
类型的proxyClassFile
文件,然后再通过本地方法defineClass0
加载类到JVM
中,classLoader
与被代理接口用的同一个AppClassLoader
,然后InvocationHandler
对象是作为代理类的成员域,通过构造函数参数传入
当代理类调用被代理接口中的方法的时候,最终调用到的是InvocationHandler
对象的invoke
方法,方法的参数包含被代理接口的方法
生成代理类的参数
classLoader :被代理类的类加载器
interface :被代理类的顶层接口
invocationHandler :InvocationHandler 的实现类,主要实现invoke 方法增强的作用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程