蚂蚁课堂第5期-互联网架构-006:纯手动态代理模式
程序员文章站
2022-06-15 11:33:42
...
1 纯手写JDK动态代理思路分析
课程内容:
1、回顾JDK动态代理与CGLib代理区别
2、JDK动态代理大致原理回顾
3、纯手写Jdk动态代理的思路
4、JavaCompiler编译源文件技术
5、自定义ClassLoader读取class文件到内存中
CGLIB与JDK动态代理区别是什么?
jdk动态代理:被代理类必须实现接口,实现方式,java反射执行
cligb动态代理:使用继承被代理类,继承方式,ASM生成子类
纯手写JDK动态代理 原理思路
1.创建代理类$Proxy0源代码文件实现被代理的接口,使用java反射技术获取该接口下面所有方法;
2.使用JavaCompiler技术编译该$Proxy0文件编译成$Proxy0.class文件;
3.使用ClassLoader将该$Proxy0.class加入到当前JVM内存中
2 简单版本实现Jdk动态代理
MyExtJdkInvocationHandler
public interface MyExtJdkInvocationHandler {
/**
*
* @param proxy 代理类
* @param method 目标方法
* @param args 参数
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
MyJdkInvocationHandler
public class MyJdkInvocationHandler implements MyExtJdkInvocationHandler {
/**
* 目标对象 被代理类 真实访问的类的对象
*/
private Object target;
public MyJdkInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(">>>纯手写jdk动态代理日志开始<<<");
Object result = method.invoke(target, args);// 使用java反射执行
System.out.println(">>>纯手写jdk动态代理日志结束<<<");
return result;
}
}
OrderService
public interface OrderService {
public void order() throws Throwable;
}
OrderServiceImpl
public class OrderServiceImpl implements OrderService {
@Override
public void order() {
System.out.println("数据库订单执行操作..");
}
}
$Proxy0(假设存在)
public class $Proxy0 implements OrderService {
private MyExtJdkInvocationHandler h;
public $Proxy0(MyExtJdkInvocationHandler h){
this.h = h;
}
@Override
public void order() throws Throwable {
// 如何获取到真实目标方法?
Method orderMethod = OrderService.class.getMethod("order", new Class[]{});
this.h.invoke(this, orderMethod, null);
}
}
测试类
public class Test001 {
public static void main(String[] args) throws Throwable {
OrderService orderService = new $Proxy0(new MyJdkInvocationHandler(new OrderServiceImpl()));
orderService.order();
}
}
结果:
3 完全纯手写JDK动态代理01
public class MyProxy {
static String rt = "\r\t";
public static Object newProxyInstance(JavaClassLoader javaClassLoader,
Class<?> classInfo,
MyExtJdkInvocationHandler h) {
try {
// 1.拼接代码类的源代码
Method[] methods = classInfo.getMethods();
String proxyClass = "package com.mayikt.extProxy.ext.proxy;" + rt
+ "import java.lang.reflect.Method;" + rt
+ "import com.mayikt.extProxy.ext.proxy.MyExtJdkInvocationHandler;" + rt
+ "public class $Proxy0 implements " + classInfo.getName() + "{" + rt
+ "MyExtJdkInvocationHandler h;" + rt
+ "public $Proxy0(MyExtJdkInvocationHandler h)" + "{" + rt
+ "this.h= h;" + rt + "}"
+ getMethodString(methods, classInfo) + rt + "}";
// 2.写入到本地文件中..
String filename = "d:/code/$Proxy0.java";
File f = new File(filename);
FileWriter fw = new FileWriter(f);
fw.write(proxyClass);
fw.flush();
fw.close();
// 3.将源代码编译成class文件
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(filename);
JavaCompiler.CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
// 4.使用classLoader 加载到内存中
Class<?> $Proxy0 = javaClassLoader.findClass("$Proxy0");
// 5.指明初始化有参数构造函数
Constructor<?> constructor = $Proxy0.getConstructor(MyExtJdkInvocationHandler.class);
Object o = constructor.newInstance(h);
return o;
}catch (Exception e){
e.printStackTrace();
}
return null;
}
public static String getMethodString(Method[] methods, Class intf) {
String proxyMe = "";
for (Method method : methods) {
proxyMe += "public void " + method.getName() + "() throws Throwable {" + rt
+ "Method md= " + intf.getName() + ".class.getMethod(\"" + method.getName()
+ "\",new Class[]{});" + rt
+ "this.h.invoke(this,md,null);" + rt + "}" + rt;
}
return proxyMe;
}
public static void main(String[] args) {
newProxyInstance(null, OrderService.class, null);// 测试在指定文件夹生成代理类文件
}
}
public class Test001 {
public static void main(String[] args) throws Throwable {
OrderService orderService = (OrderService) MyProxy.newProxyInstance(new JavaClassLoader(), OrderService.class, new MyJdkInvocationHandler(new OrderServiceImpl()));
orderService.order();
}
}
4 完全纯手写JDK动态代理02
JavaClassLoader
public class JavaClassLoader extends ClassLoader {
private File classPathFile;
public JavaClassLoader(){
// String classPath=JavaClassLoader.class.getResource("").getPath();
String classPath="D:\\code";
this.classPathFile=new File(classPath);
}
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
String className= JavaClassLoader.class.getPackage().getName()+"."+name;
if(classPathFile!=null){
File classFile=new File(classPathFile,name.replaceAll("\\.","/")+".class");
if(classFile.exists()){
FileInputStream in=null;
ByteArrayOutputStream out=null;
try {
in=new FileInputStream(classFile);
out=new ByteArrayOutputStream();
byte[] buff=new byte[1024];
int len;
while ((len=in.read(buff))!=-1){
out.write(buff,0,len);
}
return defineClass(className,out.toByteArray(),0,out.size());
}catch (Exception e){
e.printStackTrace();
}finally {
if(in!=null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(out!=null){
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
运行结果:
5 JDK动态代理源码分析
上一篇: PHP的开发工具解决思路
下一篇: PHP自定义大小验证码的方法详解_PHP