本文提供相关源码,请放心食用,详见网页侧边栏或底部,有疑问请评论或 Issue
一、前言
AOP
(Aspect Oriented Programming),即面向切面编程
,最主要的思想就是纵向重复,横向抽取 。要想实现 AOP,其底层实现是使用了动态代理技术
,在 Spring 中,动态代理技术分为传统的 JDK 动态代理
和 Cglib 动态代理
。这两种代理机制区别是:
假设我们有一个 UserService 接口,其中具有 CRUD 方法:
1 2 3 4 5 6 public interface UserService { void save () ; void delete () ; void update () ; void query () ; }
它有一个实现类,只是简单的输出了信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class UserServiceImpl implements UserService { @Override public void save () { System.out.println("save" ); } @Override public void delete () { System.out.println("delete" ); } @Override public void update () { System.out.println("update" ); } @Override public void query () { System.out.println("query" ); } }
如果我们想要对这四个方法进行增强,例如在每个方法开头和结尾开启和提交事务,例如:
1 2 3 4 5 public void delete () { System.out.println("开启事务" ); System.out.println("delete" ); System.out.println("提交事务" ); }
如果不使用 AOP 思想或动态代理技术,要写很多的冗余代码。
二、JDK 动态代理
Step1: 要有一个实现 InvocationHandler
接口的类,编写 MyInvocationHandler
类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class MyInvocationHandler implements InvocationHandler { private Object targetObj; public MyInvocationHandler (Object targetObj) { this .targetObj = targetObj; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开启事务" ); Object invoke = method.invoke(targetObj, args); System.out.println("提交事务" ); return invoke; } }
Step2: 编写 UserService 的动态代理类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class UserServiceProxy { private UserService userService; public UserServiceProxy (UserService userService) { this .userService = userService; } public UserService getUserServiceProxy () { MyInvocationHandler myInvocationHandler = new MyInvocationHandler(userService); UserService userServiceProxy = (UserService) Proxy.newProxyInstance(UserServiceProxy.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), myInvocationHandler); return userServiceProxy; } }
Step3: 编写测试方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class JdkProxyTest { public static void main (String[] args) { UserService us = new UserServiceImpl(); UserServiceProxy userServiceProxy = new UserServiceProxy(us); UserService usProxy = userServiceProxy.getUserServiceProxy(); usProxy.delete(); } }
三、Cglib 动态代理
Step0: 导入 Cglib 依赖包:
1 2 3 4 5 <dependency > <groupId > cglib</groupId > <artifactId > cglib</artifactId > <version > 3.2.4</version > </dependency >
Step1: 编写 userService 实现 MethodInterceptor
接口的 Cglib 动态代理类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class UserServiceProxy2 implements MethodInterceptor { public UserService getUserServiceProxy () { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback(this ); UserService us = (UserService) enhancer.create(); return us; } @Override public Object intercept (Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("开启事务" ); Object invoke = methodProxy.invokeSuper(o, args); System.out.println("提交事务" ); return invoke; } }
Step2: 编写测试方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class CglibProxyTest { public static void main (String[] args) { UserServiceProxy2 userServiceProxy2 = new UserServiceProxy2(); UserService usProxy = userServiceProxy2.getUserServiceProxy(); usProxy.query(); usProxy.save(); usProxy.update(); usProxy.delete(); } }
四、总结
(1)JDK 的动态代理
代理对象和目标对象实现了共同的接口
拦截器必须实现 InvocationHanlder
接口
(2)Cglib 的动态代理
代理对象是目标对象的子类
拦截器必须实现 MethodInterceptor
接口