001:纯手写Java动态代理模式
1 代理设计模式基本概念与应用场景
课程内容
- 代理模式为何是程序员必备技能
- 静态代理与动态代理实现区别
- Jdk动态代理为何需要InvocationHandler接口
- CGLIB动态代理与Jdk动态代理区别
- 10分钟完全纯手写一个Jdk动态代理
代理设计模式
代理设计模式主要对方法前后实现增强
应用场景
1 打印日志
2 AOP底层通过代理模式封装
3 事务@Transactional 底层AOP
4 Mybatis中的mapper接口
5 全局捕获异常
6 Lcn、Seata、分表分库框架sharding-jdbc 代理数据源
7 自定义注解生效
8 Rpc远程调用技术(通过dubbo调用接口只会引入接口)
代理模式优缺点
优点:实现扩展功能、对方法实现增强、安全性、解决代码冗余提高代码复用机制
缺点:生成非常多的class文件(代理类)
代理模式的分类
静态代理与动态代理
代理模式实现的原理
代理模式主要包含三个角色,即抽象主题角色(Subject)、委托类角色(被代理角色,Proxied)以及代理类角色(Proxy),如图所示:
抽象主题角色:可以是接口,也可以是抽象类;
委托类(被代理类)角色:真实主题角色,业务逻辑的具体执行者;
代理类角色:内部含有对真实对象的引用,负责对真实主题角色的调用,并在真实主题角色处理前后做预处理和后处理。
eg:买房 中介 卖房(被代理类)
2 实现静态代理两种方式
静态代理的实现方式
基于接口实现(Jdk动态代理)和继承模式(Cglib字节码)
1 基于实现接口的方式实现静态代理
public interface OrderService {
String addOrder(String orderId, String orderName);
}
public class OrderServiceImpl implements OrderService {
@Override
public String addOrder(String orderId, String orderName) {
System.out.println("OrderServiceImpl真实方法执行...");
return orderId + "," + orderName;
}
}
public class OrderServiceProxy implements OrderService {
/**
* 被代理类
*/
private OrderServiceImpl orderServiceImpl;
public OrderServiceProxy(OrderServiceImpl orderServiceImpl) {
this.orderServiceImpl = orderServiceImpl;
}
@Override
public String addOrder(String orderId, String orderName) {
System.out.println("采用代理模式统一打印日志 orderId:" + orderId + ",orderName:" + orderName);
return orderServiceImpl.addOrder(orderId, orderName);
}
}
public class Test001 {
public static void main(String[] args) {
OrderService orderServiceProxy = new OrderServiceProxy(new OrderServiceImpl());
orderServiceProxy.addOrder("mayikt", "111");
}
}
运行结果:
2 基于继承的模式实现静态代理
public class OrderServiceProxy extends OrderServiceImpl {
@Override
public String addOrder(String orderId, String orderName) {
System.out.println("采用代理模式统一打印日志 orderId:" + orderId + ",orderName:" + orderName);
return super.addOrder(orderId, orderName);
}
}
public class Test001 {
public static void main(String[] args) {
OrderService orderServiceProxy = new OrderServiceProxy();
orderServiceProxy.addOrder("mayikt", "111");
}
}
3 静态代理与动态代理模式的区别
静态代理模式缺陷:需要人工手写代理类
动态代理方式:采用程序动态生成代理类,不需要程序员人工手写
动态代理实现方式
jdk动态代理和cglib动态代理
4 基于JDK动态代理的使用
Jdk动态代理模式底层实现
public class JdkInvocationHandler implements InvocationHandler {
/**
* 目标对象(被代理类)
*/
private Object target;
public JdkInvocationHandler(Object object) {
this.target = object;
}
/**
* @param proxy jdk动态生成的代理类
* @param method 不是真正的目标方法,接口中的方法,底层通过反射执行真正目标方法
* @param args 代理类参数
* 使用生成的代理类去拦截回调
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk动态代理执行开始>>>" + args[0]);
// 执行目标方法 java反射执行目标方法
Object result = method.invoke(target, args);
System.out.println("jdk动态代理执行结束>>>" + args[0]);
return result;
}
/**
* 使用jdk创建代理类对象
*
* @param <T>
* @return
*/
public <T> T getProxy() {
// ClassLoader 读取代理类class文件
// Class<?>[] interfaces 基于该接口拼接代理类的源代码
// InvocationHandler this
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
public class Test002 {
public static void main(String[] args) {
JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(new OrderServiceImpl());
// 创建代理类
OrderService proxy = jdkInvocationHandler.getProxy();
proxy.addOrder("mayikt", "maplefire");
}
}
运行结果:
5 为什么Jdk动态代理不能用子类接收
获取代理的生成的class文件
System.getProperties().put(“sun.misc.ProxyGenerator.saveGeneratedFiles”, “true”);
Jdk动态生成的代理类:$Proxy0
注意:$Proxy0基于接口的方式实现,不能转换为子类(不能用子类接收)
6 JDK生成的代理类$Proxy源码分析
Java反射机制无法获取方法的参数名称,只可以获取方法的参数类型。
$Proxy0源码分析
public class $Proxy0 implements OrderService {
/**
* 回调类
*/
private InvocationHandler h;
public $Proxy0(InvocationHandler h) {
this.h = h;
}
@Override
public final String addOrder(String var1, String var2) {
try {
// m3 获取orderService接口的addOrder方法
Method m3 = Class.forName("com.mayikt.service.OrderService").getMethod("addOrder", Class.forName("java.lang.String"), Class.forName("java.lang.String"));
return (String) this.h.invoke(this, m3, new Object[]{var1, var2});
} catch (RuntimeException | Error var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
}
public class JdkInvocationHandler implements InvocationHandler {
/**
* 目标对象(被代理类)
*/
private Object target;
public JdkInvocationHandler(Object object) {
this.target = object;
}
/**
* @param proxy jdk动态生成的代理类
* @param method 不是真正的目标方法,接口中的方法,底层通过反射执行真正目标方法
* @param args 代理类参数
* 使用生成的代理类去拦截回调
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk动态代理执行开始>>>" + args[0]);
// 执行目标方法 java反射执行目标方法
Object result = method.invoke(target, args);
System.out.println("jdk动态代理执行结束>>>" + args[0]);
return result;
}
public <T> T getProxy() {
return (T) new $Proxy0(this);
}
}
7 手写JDK动态代理
手写javaJDK动态代理实现思路
- 根据接口信息动态拼接代理类的源代码$Proxy.java
- $ Proxy.java编译为$Proxy.class
- 基于类加载器动态读取$Proxy.class到内存中
- 使用java的反射机制初始化 走有参构造函数
手写javaJDK动态代理实现
public class MyProxy {
private static String rt = "\r\t";
/**
*
* @param classLoader
* @param classInfo
* @param h
* @return
*/
public static Object newProxyInstance(JavaClassLoader classLoader,
Class<?> classInfo,
MayiktInvocationHandler h) {
try {
// 1.根据接口的信息拼接java源代码
Method[] methods = classInfo.getMethods();
String proxyClass = "package com.mayikt.service.proxy;" + rt
+ "import java.lang.reflect.Method;" + rt
+ "import com.mayikt.service.proxy.jdk.MayiktInvocationHandler;" + rt
+ "import java.lang.reflect.UndeclaredThrowableException;" + rt
+ "public class $Proxy0 implements " + classInfo.getName() + "{" + rt
+ "MayiktInvocationHandler h;" + rt
+ "public $Proxy0(MayiktInvocationHandler h)" + "{" + rt
+ "this.h= h;" + rt + "}"
+ getMethodString(methods, classInfo) + rt + "}";
// 2.将java源代码写入到本次磁盘
String filename = "d:/code/$Proxy0.java";
File f = new File(filename);
FileWriter fw = new FileWriter(f);
fw.write(proxyClass);
fw.flush();
fw.close();
// 3.需要将$Proxy.java编译成$Proxy.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.使用类加载器读取该class文件
Class<?> proxy = classLoader.findClass("$Proxy0");
Constructor<?> constructor = proxy.getConstructor(MayiktInvocationHandler.class);
// 5.使用java的反射机制初始化 走有参构造函数
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) {
Class<?>[] parameterTypes = method.getParameterTypes();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < parameterTypes.length; i++) {
sb.append(parameterTypes[i].getName() + " ver" + (i + 1));
if (i < parameterTypes.length - 1) {
sb.append(" ,");
}
}
String parameterStr = sb.toString();
proxyMe = "public " + method.getReturnType().getName() + " " + method.getName() + " ( " + parameterStr + " ) { " +
"try { Method m3 = Class.forName(\"com.mayikt.service.OrderService\").getMethod(\"addOrder\", Class.forName(\"java.lang.String\"), Class.forName(\"java.lang.String\"));" +
"return (String) h.invoke(this, m3, new Object[]{ver1, ver2}); } catch (RuntimeException | Error var4) { throw var4; } catch (Throwable var5) { throw new UndeclaredThrowableException(var5); } " +
"" +
" } ";
}
return proxyMe;
}
public static void main(String[] args) {
MyProxy.newProxyInstance(null, OrderService.class, null);
}
}
public interface MayiktInvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
public class MayiktInvocationHandlerImpl implements MayiktInvocationHandler {
private Object target;
public MayiktInvocationHandlerImpl(Object object) {
this.target = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk动态代理执行开始>>>" + args[0]);
// 执行目标方法 java反射执行目标方法
Object result = method.invoke(target, args);
System.out.println("jdk动态代理执行结束>>>" + args[0]);
return result;
}
public <T> T getProxy() {
return (T) MyProxy.newProxyInstance(new JavaClassLoader(), target.getClass().getInterfaces()[0], this);
}
}
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;
}
}
public class Test003 {
public static void main(String[] args) {
MayiktInvocationHandlerImpl mayiktInvocationHandler = new MayiktInvocationHandlerImpl(new OrderServiceImpl());
OrderService proxy = mayiktInvocationHandler.getProxy();
String s = proxy.addOrder("mayikt", "maplefire");
}
}
运行结果:
生成的$Proxy0.java文件
源码下载地址(mayikt_designPattern_1.rar):
链接:https://pan.baidu.com/s/1wWKZN1MbXICZVW1Vxtwe6A
提取码:fire