Java互联网企业架构技术VIP课程【腾讯课堂每特】
设计模式的分类
Java互联网企业架构技术VIP课程【腾讯课堂每特】
课程内容
站在架构角度,基于装饰模式纯手写设计多级缓存框架
- 如何理解多级缓存框架设计
装饰模式与代理模式之间的区别
3.装饰模式如何在Mybatis、IO流运用
4.基于装饰设计多级缓存框架
5.自定义缓存注解,轻松搞定多级缓存问题
本节课需要知识:动态代理技术+Aop+装饰模式+Redis缓存概念
注意:因为该设计模式比较接近真实案例,需要有SpringBoot基础。
创建型模式
工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
行为模式
策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
彻底搞懂代理模式实现原理
什么是代理模式
代理模式主要对我们方法执行之前与之后实现增强
代理模式应用场景
- 日志的采集
- 权限控制
- 实现aop
- Mybatis mapper
- Spring的事务
- 全局捕获异常
- Rpc远程调用接口
- 代理数据源
代理模式创建方式
静态代理
静态代理需要自己人工编写代理类代码
基于接口实现方式
public class OrderServiceProxy implements OrderService{ private OrderService orderService;
public OrderServiceProxy(OrderService orderService) { this.orderService = orderService; }
public String addOrder(String userName, String userPwd) { System.out.println("使用静态代理类打印日志开始:userName:" + userName + "," + userPwd); String result = orderService.addOrder(userName, userPwd); System.out.println("使用静态代理类打印日志结束:userName:" + userName + "," + userPwd); return result; } }
public interface OrderService { /** * 需要被代理的方法 * @return */ String addOrder(String userName,String userPwd); }
public class Test001 { public static void main(String[] args) { OrderService orderService = new OrderServiceProxy(new OrderServiceImpl()); orderService.addOrder("mayikt","123456"); } }
|
基于继承的实现方式
public class OrderServiceProxy extends OrderServiceImpl { private OrderService orderService;
public OrderServiceProxy(OrderService orderService) { this.orderService = orderService; }
public String addOrder(String userName, String userPwd) { System.out.println("使用静态代理类打印日志开始:userName:" + userName + "," + userPwd); String result = super.addOrder(userName, userPwd); System.out.println("使用静态代理类打印日志结束:userName:" + userName + "," + userPwd); return result; } }
|
动态代理与静态代理的区别
动态代理不需要写代理类对象,通过程序自动生成,而静态代理需要我们自己写代理类对象。
动态代理
动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成 。
Jdk动态代理
JDK动态代理的一般步骤如下:
1.创建被代理的接口和类;
2.实现InvocationHandler接口,对目标接口中声明的所有方法进行统一处理;
3.调用Proxy的静态方法,创建代理类并生成相应的代理对象;
实现原理:利用拦截器机制必须实现InvocationHandler接口中的invoke方法实现对
我们的目标方法增强。
public class JdkInvocationHandler implements InvocationHandler { /** * 目标对象 */ private Object target;
public JdkInvocationHandler(Object target) { this.target = target; }
/** * @param proxy 使用jdk程序生成的代理类 * @param method 目标方法 * @param args 方法需要传递的参数 * @return */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("使用Jdk动态代理打印日志开始" + args[0]); Object result = method.invoke(target, args); System.out.println("使用Jdk动态代理打印日志结束" + args[1]); return result; }
/** * 生成代理类 * * @param <T> * @return */ public <T> T getProxy() { return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); }
}
|
public class JdkInvocationHandler implements InvocationHandler { /** * 目标对象 */ private Object target;
public JdkInvocationHandler(Object target) { this.target = target; }
/** * @param proxy 使用jdk程序生成的代理类 * @param method 目标方法 * @param args 方法需要传递的参数 * @return */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("使用Jdk动态代理打印日志开始" + args[0]); Object result = method.invoke(target, args); System.out.println("使用Jdk动态代理打印日志结束" + args[1]); return result; }
public <T> T getProxy() { return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); }
}
|
JdkInvocationHandler jdkInvocationHandler = new JdkInvocationHandler(new OrderServiceImpl()); OrderServiceImpl orderService = jdkInvocationHandler.getProxy(); orderService.addOrder("mayikt", "meite");
|
加上该代码:
- 获取代理的生成的class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
- 使用反编译工具该Pclass
注意:继承了Proxy类,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类了,不能再继承其他的类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。
纯手写Jdk动态代理
思路分析:
- 定义InvocationHandler类 回调方法
- 使用java反射技术获取接口下所有的方法,拼接 $Proxy0.java代码
- 在将$Proxy0.java编译成class文件,读取到内存中
public class $Proxy0 implements com.mayikt.service.OrderService {
private MayiktJdkInvocationHandler h; private static Method m3;
public $Proxy0(MayiktJdkInvocationHandler mayiktJdkInvocationHandler) { this.h = mayiktJdkInvocationHandler; }
@Override public String addOrder(String ver1, String var2) { try { return (String) h.invoke(this, m3, new Object[]{ver1, var2}); } catch (RuntimeException | Error var4) { throw var4; } catch (Throwable var5) { throw new UndeclaredThrowableException(var5); } }
static { try { m3 = Class.forName("com.mayikt.service.OrderService").getMethod("addOrder", Class.forName("java.lang.String"), Class.forName("java.lang.String")); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
|
public class MyJdkInvocationHandler implements MayiktJdkInvocationHandler { /** * 目标对象 */ 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动态代理打印日志开始" + args[0]); Object result = method.invoke(target, args); System.out.println("使用Jdk动态代理打印日志结束" + args[1]); return result; } public <T> T getProxy() { return (T) new $Proxy0(this); }
}
|
MyJdkInvocationHandler myJdkInvocationHandler = new MyJdkInvocationHandler(new OrderServiceImpl()); OrderService orderService = myJdkInvocationHandler.getProxy(); orderService.addOrder("mayikt", "meite");
|
public class MyProxy { private static String rt = "rt";
public static Object newProxyInstance(JavaClassLoader classLoader, Class classInfo, MayiktInvocationHandler mayiktInvocationHandler) { try { // 1.拼接java代理代理源代码 Method[] methods = classInfo.getMethods(); String proxyClass = "package com.mayikt.service;" + rt + "import java.lang.reflect.Method;" + rt + "import com.mayikt.service.proxy.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.将该源代码写入到本地文件中 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.将class文件加入到内存中 Class proxy0Class = classLoader.findClass("$Proxy0"); //5.使用java反射机制给函数中赋值 Constructor m = proxy0Class.getConstructor(MayiktInvocationHandler.class); Object object = m.newInstance(mayiktInvocationHandler); return object; } catch (Exception e) { 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) { newProxyInstance(null, OrderService.class, null); } }
|
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 MyJdkInvocationHandler implements MayiktJdkInvocationHandler { /** * 目标对象 */ 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动态代理打印日志开始" + args[0]); Object result = method.invoke(target, args); System.out.println("使用Jdk动态代理打印日志结束" + args[1]); return result; }
public <T> T getProxy() { return (T) MyProxy.newProxyInstance(new JavaClassLoader(), target.getClass().getInterfaces()[0], this); } }
|
CGLIB动态代理
利用asm字节码技术,生成子类实现对目标方法实现增强
实现方式
Maven依赖
<dependencies> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.12</version> </dependency> </dependencies>
|
核心代码
public class CglibMethodInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("<<<<<日志收集开始...>>>>>>>"); Object reuslt = proxy.invokeSuper(obj, args); System.out.println("<<<<<日志收集结束...>>>>>>>"); return reuslt; } }
|
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\code"); CglibMethodInterceptor cglibMethodInterceptor = new CglibMethodInterceptor(); Enhancer enhancer = new Enhancer(); // 设置代理类的付类 enhancer.setSuperclass(MemberServiceImpl.class); // 设置回调对象 enhancer.setCallback(cglibMethodInterceptor); // 创建代理对象 MemberServiceImpl orderServiceImpl = (MemberServiceImpl) enhancer.create(); orderServiceImpl.getMember();
|
Cglib动态代理底层源码分析
Cglib依赖于ASM字节码技术,直接生成class文件,在采用类加载器读取到程序中,
使用fastclass对被代理类的方法建立索引文件不需要依赖于反射查找到目标方法,所以效率比Jdk动态代理要高。
public class OrderServiceImpl$$EnhancerByCGLIB$$1dd3a71c extends OrderServiceImpl {
static void CGLIB$STATICHOOK1() throws ClassNotFoundException { Method amethod[]; Method amethod1[]; CGLIB$THREAD_CALLBACKS = new ThreadLocal(); CGLIB$emptyArgs = new Object[0]; Class class1 = Class.forName("com.mayikt.service.impl.OrderServiceImpl$$EnhancerByCGLIB$$1dd3a71c"); Class class2; amethod = ReflectUtils.findMethods(new String[]{ "addOrder", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;" }, (class2 = Class.forName("com.mayikt.service.impl.OrderServiceImpl")).getDeclaredMethods()); Method[] _tmp = amethod; CGLIB$addOrder$0$Method = amethod[0]; CGLIB$addOrder$0$Proxy = MethodProxy.create(class2, class1, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", "addOrder", "CGLIB$addOrder$0"); amethod1 = ReflectUtils.findMethods(new String[]{ "equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;" }, (class2 = Class.forName("java.lang.Object")).getDeclaredMethods()); Method[] _tmp1 = amethod1; CGLIB$equals$1$Method = amethod1[0]; CGLIB$equals$1$Proxy = MethodProxy.create(class2, class1, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1"); CGLIB$toString$2$Method = amethod1[1]; CGLIB$toString$2$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/String;", "toString", "CGLIB$toString$2"); CGLIB$hashCode$3$Method = amethod1[2]; CGLIB$hashCode$3$Proxy = MethodProxy.create(class2, class1, "()I", "hashCode", "CGLIB$hashCode$3"); CGLIB$clone$4$Method = amethod1[3]; CGLIB$clone$4$Proxy = MethodProxy.create(class2, class1, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4"); }
final String CGLIB$addOrder$0(String s, String s1) { return super.addOrder(s, s1); }
final boolean CGLIB$equals$1(Object obj) { return super.equals(obj); }
final String CGLIB$toString$2() { return super.toString(); }
final int CGLIB$hashCode$3() { return super.hashCode(); }
public static void CGLIB$SET_THREAD_CALLBACKS(Callback acallback[]) { CGLIB$THREAD_CALLBACKS.set(acallback); }
public final String addOrder(String paramString1, String paramString2) { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) {
CGLIB$BIND_CALLBACKS(this); } try { MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0; if (tmp17_14 != null) { return (String) tmp17_14.intercept(this, CGLIB$addOrder$0$Method, new Object[]{paramString1, paramString2}, CGLIB$addOrder$0$Proxy); } } catch (Throwable throwable) { throwable.printStackTrace(); } return super.addOrder(paramString1, paramString2); }
public Object newInstance(Callback acallback[]) { CGLIB$SET_THREAD_CALLBACKS(acallback); CGLIB$SET_THREAD_CALLBACKS(null); return new OrderServiceImpl$$EnhancerByCGLIB$$1dd3a71c(); }
public Object newInstance(Callback callback) { CGLIB$SET_THREAD_CALLBACKS(new Callback[]{ callback }); CGLIB$SET_THREAD_CALLBACKS(null); return new OrderServiceImpl$$EnhancerByCGLIB$$1dd3a71c(); }
public void setCallback(int i, Callback callback) { switch (i) { case 0: // ' ' CGLIB$CALLBACK_0 = (MethodInterceptor) callback; break; } }
private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static ThreadLocal CGLIB$THREAD_CALLBACKS = null; private static final Callback CGLIB$STATIC_CALLBACKS[] = null; private MethodInterceptor CGLIB$CALLBACK_0; private static Object CGLIB$CALLBACK_FILTER; private static Method CGLIB$addOrder$0$Method = null; private static MethodProxy CGLIB$addOrder$0$Proxy = null; private static Object[] CGLIB$emptyArgs = null; private static Method CGLIB$equals$1$Method = null; private static MethodProxy CGLIB$equals$1$Proxy = null; private static Method CGLIB$toString$2$Method = null; private static MethodProxy CGLIB$toString$2$Proxy = null; private static Method CGLIB$hashCode$3$Method = null; private static MethodProxy CGLIB$hashCode$3$Proxy = null; private static Method CGLIB$clone$4$Method = null; private static MethodProxy CGLIB$clone$4$Proxy = null;
static { try { CGLIB$STATICHOOK1(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }
public OrderServiceImpl$$EnhancerByCGLIB$$1dd3a71c() { CGLIB$BIND_CALLBACKS(this); }
private void CGLIB$BIND_CALLBACKS(OrderServiceImpl$$EnhancerByCGLIB$$1dd3a71c orderServiceImpl$$EnhancerByCGLIB$$1dd3a71c) { } }
|
FastClass机制
public class MayiktFastclass {
/** * 根据索引查找到目标方法 * * @param index * @param obj * @param args * @return */ public static Object invoke(int index, Object obj, Object[] args) { OrderServiceImpl orderService = (OrderServiceImpl) obj; switch (index) { case 1: return orderService.addOrder(String.valueOf(args[0]), String.valueOf(args[1])); } return null; }
/** * 根据签名简历索引文件 * * @param sign * @return */ public static int getIndex(String sign) { switch (sign.hashCode()) { case 1763340254: return 1; case 20: return 2; } return -1; }
public static void main(String[] args) { System.out.println("addOrder()String,String".hashCode()); Object result = invoke(getIndex("addOrder()String,String"), new OrderServiceImpl(), new String[]{"mayikt", "meite"}); } }
|
Jdk与Cglib动态代理的区别
- Jdk动态代理利用反射技术生成匿名的代理类走InvokeHandler回调方法实现增强,同时也是一种基于接口的方式实现代理。
- Cglib动态代理利用asm字节码技术生成一个子类覆盖其中的方法实现增强,同时采用fastClass机制对整个代理类建立索引比反射效率要高
- 在Spring中如果需要被代理的对象如果实现了接口采用Jdk动态代理,没有实现接口则使用Cglib动态代理。
版权声明:本文来源博客园,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://www.cnblogs.com/itit9696/p/15130080.html
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。