JDK和CGlib对比图:
代码实现--准备接口和实现类
public interface UserManager { //新增用户抽象方法 void addUser(String userName,String password); //删除用户抽象方法 void delUser(String userName); } public class UserManagerImpl implements UserManager { @Override public void addUser(String userName, String password) { System.out.println("调用了新增的方法!"); delUser(userName); } @Override public void delUser(String userName) { System.out.println("调用了删除的方法!"); } }
JDK动态代理:
public class JdkProxy implements InvocationHandler{ private Object target;//需要代理的目标对象 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("JDK动态代理,监听开始!"); Object result = method.invoke(target, args); System.out.println("JDK动态代理,监听结束!"); return result; } //定义获取代理对象方法 private Object getJdkProxy(Object targetObject) { this.target = targetObject; return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); } public static void main(String[] args) { System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");//生成字节码文件 JdkProxy jdkProxy = new JdkProxy();//实例化JDKProxy对象 UserManager user = (UserManager) jdkProxy.getJdkProxy(new UserManagerImpl());//获取代理对象 System.out.println(user.getClass()); user.addUser("tester", "root"); } }
运行效果:
此时生成的proxy.class---only one:
它的代理为每一个方法生成对应的实现,并通过调用h也就是InvocationHandler实例变量的invoke的方法去调用,调用的时候只是传入的方法和参数不同而已。在invoke方法里面,通过反射调用,此时target不是代理类,是本类,相当于直接用本类的实例调用方法,不走代理增强。
方法都在Proxy.class中进行了载入:
代码实现--CGLIB---proxy.invokeSuper
public class CglibProxy implements MethodInterceptor{ private Object target;//需要代理的目标对象 @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Cglib动态代理,监听开始!"); proxy.invokeSuper(obj, args); System.out.println("Cglib动态代理,监听结束!"); return obj; // Object invoke = method.invoke(target, args);//方法执行,参数:target 目标对象 args参数数组 // System.out.println("Cglib动态代理,监听结束!"); // return invoke; } //定义获取代理对象方法 public Object getCglibProxy(Object objectTarget){ //为目标对象target赋值 this.target = objectTarget; Enhancer enhancer = new Enhancer(); //设置父类,因为Cglib是针对指定的类生成一个子类,所以需要指定父类 enhancer.setSuperclass(objectTarget.getClass()); enhancer.setCallback(this);// 设置回调 Object result = enhancer.create();//创建并返回代理对象 return result; } public static void main(String[] args) throws Exception { System.out.println(System.getProperty("user.dir")); saveGeneratedCGlibProxyFiles(System.getProperty("user.dir")); CglibProxy cglib = new CglibProxy();//实例化CglibProxy对象 UserManager user = (UserManager) cglib.getCglibProxy(new UserManagerImpl());//获取代理对象 user.addUser("admin", "123123");//执行新增方法 } public static void saveGeneratedCGlibProxyFiles(String dir) throws Exception { Field field = System.class.getDeclaredField("props"); field.setAccessible(true); Properties props = (Properties) field.get(null); System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, dir);//dir为保存文件路径 props.put("net.sf.cglib.core.DebuggingClassWriter.traceEnabled", "true"); } }
运行结果:
此时生成的cglib.class文件---多个
CGLIB依赖ASM的字节码生成库,允许在运行时对字节码进行修改和动态生成。他对所有的方法都进行了增强,每次执行到一个方法 都会从已经增强后的字节码里面查找,找到后执行该方法。当在本类中调用其他方法的时候,其他方法也是增强的。
修改CGLIB增强部分的代码:
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Cglib动态代理,监听开始!"); // proxy.invokeSuper(obj, args); // System.out.println("Cglib动态代理,监听结束!"); // return obj; Object invoke = method.invoke(target, args);//方法执行,参数:target 目标对象 args参数数组 System.out.println("Cglib动态代理,监听结束!"); return invoke; }
此时的cglib.class文件
Confused?
For invokeSuper,当调用到addUser的时候,此时是一个增强类。好像说的是废话。
而且当我们断点到delUser的时候,发现delUser也进入到了MethodInterceptor的intercept方法,delUser也被增强啦。but the reason is invokeSuper; the parameter passed in invokeSuper is a subclass of Cglib proxy, which is equivalent to calling the b() method of this subclass of Target$$EnhanceredByCGLIB, and it will definitely enter the callback again;
但是通过method.invoke传的target不是增强的类。
同样通过下面的方式 传递的target也不是增强的类
public class CglibProxy implements MethodInterceptor{ private Object target;//需要代理的目标对象 public CglibProxy(Object target) { super(); this.target = target; } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Cglib动态代理,监听开始!"); Object res = proxy.invoke(target, args); System.out.println("Cglib动态代理,监听结束!"); return res; } public static void main(String[] args) throws Exception { UserManagerImpl target = new UserManagerImpl(); Enhancer e = new Enhancer(); e.setSuperclass(UserManagerImpl.class); e.setCallback(new CglibProxy(target)); UserManager t=(UserManager) e.create(); t.addUser("tester", "123"); }
也就是说调用 invokeSuper方法的时候传递的是一个增强的类,之后调用的方法都会进行增强。而invoke里面传递的是非增强类,之后调用本类的方法也不会被增强。
关于spring里面的cglib待续。。。
参考文档:
https://zhuanlan.zhihu.com/p/206628333
https://www.programmerall.com/article/5507539399/
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)