深入了解SpringAOP中的jdk动态代理与CGlib
作者:nuomizhende45
这篇文章主要介绍了深入了解SpringAOP中的jdk动态代理与CGlib,一般我们编写程序的思想是纵向的,也就是一个方法代码从该方法第一行开始往下一步一步走,直到走完最后一行代码,也就是说很多业务都需要的比如用户鉴权,资源释放等,需要的朋友可以参考下
理解AOP
一般我们编写程序的思想是纵向的,也就是一个方法代码从该方法第一行开始往下一步一步走,直到走完最后一行代码。
也就是说很多业务都需要的比如用户鉴权,资源释放等我们都要在每个方法里面重复再去调用,如下所示:
public void doMethodOne() { System.out.println("doMethodOne由上往下第一步:用户鉴权"); System.out.println("doMethodOne由上往下第二步:业务逻辑,调用服务1"); System.out.println("doMethodOne由上往下最后一步:释放资源"); } public void doMethodTwo() { System.out.println("doMethodTwo由上往下第一步:用户鉴权"); System.out.println("doMethodTwo由上往下第二步:业务逻辑,调用服务1"); System.out.println("doMethodTwo由上往下最后一步:释放资源"); } public static void main(String[] args) { doMethodOne(); doMethodTwo(); }
AOP(面向切面编程),它可以用来拦截方法前后,来达到增强方法的目的。
所以我理解的AOP的本质是在一系列纵向的控制流程中,把那些相同的子流程提取成一个横向的面,就像下面这张图把相同的逻辑,用户鉴权、资源释放抽取出来,横切到各个需要该场景的方法的开头、中间以及结尾。
SpringAOP中的一些术语
- 通知(Advice): 何时(Before,After,Around,After还有几个变种) 做什么
- 连接点(JoinPoint): 应用对象提供可以切入的所有功能(一般是方法,有时也是参数)
- 切点(PointCut): 通过指定,比如指定名称,正则表达式过滤, 指定某个/些连接点, 切点描绘了 在何地 做
- 切面(Aspect): 通知 + 切点 何时何地做什么
- 引入(Introduction):向现有类添加新的属性或方法
- 织入(Weaving): 就是将切面应用到目标对象的过程
实现方式之JDK的动态代理
JDK动态代理目标是按照接口实现类的形式。
你需要创建一个jdkproxy 类来继承InvocatoinHandler 接口,将你想要增强的代码添加到里面的invoke方法中。
目标类如下
package com.lee.aop.jdkaop; /** * @author lee */ public interface UserServiceInf { void updateUser(); }
package com.lee.aop.jdkaop; /** * @author lee */ public class UserServiceImpl implements UserServiceInf { @Override public void updateUser() { System.out.println("修改用户"); } }
代理类如下:
package com.lee.aop.jdkaop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * @author lee */ public class MyProxy implements InvocationHandler { private Object target ; public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Object createProxy(Object target) { this.target = target ; return Proxy.newProxyInstance(this.target.getClass(). getClassLoader(),this.target.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Method methods = this.target.getClass().getMethod("updateUser",null); System.out.println("用户鉴权"); methods.invoke(this.target,null); return null; } }
测试类:
package com.lee.aop.jdkaop; public class Tester { public static void main(String[] args) { UserServiceImpl userImpl = new UserServiceImpl(); UserServiceInf service = (UserServiceInf) new MyProxy().createProxy(userImpl); service.updateUser(); } }
实现方式之CGlib动态代理
目标类
package com.lee.aop.cglib; /** * @author lee */ public class UserService { public void updateUser(String uid) { System.out.println("获取User" + uid); } }
代理类
package com.lee.aop.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; /** * @author lee */ public class UserProxy implements MethodInterceptor { //通过Enhacer创建一个代理对象 Enhancer proxy = new Enhancer(); public Object getProxy(Class clz) { proxy.setSuperclass(clz); proxy.setCallback(this); return proxy.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("用户鉴权"); methodProxy.invokeSuper(o,objects); return null; } }
测试类
package com.lee.aop.cglib; /** * @author lee */ public class Tester { public static void main(String[] args) { UserProxy proxy = new UserProxy(); UserService userService = (UserService) proxy.getProxy(UserService.class); userService.updateUser("lee"); } }
JDK动态代理与CGlib代理的区别
- JDK动态代理只能对实现了接口的类生成代理,而不能针对类
- CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
- JDK的动态代理是基于类实现了接口,cglib是基于类,没有强制要求目标类一定要是实现接口。
- JDK的核心是实现InvocationHandler接口,使用invoke()方法进行面向切面的处理,调用相应的通知。
- CGLIB的核心是实现MethodInterceptor接口,使用intercept()方法进行面向切面的处理,调用相应的通知。
所以在Spring中当Bean实现接口时,Spring就会用JDK的动态代理,当Bean没有实现接口时,Spring使用CGlib来实现。
到此这篇关于深入了解SpringAOP中的jdk动态代理与CGlib的文章就介绍到这了,更多相关jdk动态代理与CGlib内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!