Spring AOP的实现原理
1. AOP基础
1.1 动态代理
我们都知道java是面向对象语言,服务也被看做对象(比如后端开发中常见的Dao层数据查询对象,Service层的业务对象等)。正常服务间协作,一个对象如果需要使用另一个对象只需要维持一个引用关系就行了,但是这时就有可能出现某个对象被其他大部分对象引用的情况,以日志打印为例。每个业务对象使用都需要创建一个日志对象,并且将打印逻辑嵌在业务代码中(创建一个类组合两个功能也是类似的情况),这无疑增加了开发人员的工作量也增加了不同功能之间的耦合度,不利于后期维护。
我们可以发现这种增加引用关系,增加代码的操作高度相似,那么能不能抽象出一个对象来专门负责这个功能呢?当然是可以的,java动态代理就是很好的实现之一。
提前定义代理要使用的类和接口。
1 2 3
| public interface UserService { public void addUser(String name); }
|
1 2 3 4 5 6
| public class UserServiceImpl implements UserService{ @Override public void addUser(String name) { System.out.println("Adding user: " + name); } }
|
1.2 jdk动态代理
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 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| public class JDKProxyDemo { private UserService target;
public JDKProxyDemo(UserServiceImpl target) { super(); this.target = target; }
public UserService getLoggingProxy() { UserService proxy; ClassLoader loader = target.getClass().getClassLoader(); Class[] interfaces = new Class[]{UserService.class}; InvocationHandler h = new InvocationHandler() {
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); System.out.println("[before] execute method: " + methodName);
Object result = null; try { result = method.invoke(target, args); } catch (NullPointerException e) { e.printStackTrace(); }
System.out.println("[after] execute method: " + methodName + ", return value: " + result); return result; } };
proxy = (UserService) Proxy.newProxyInstance(loader, interfaces, h); return proxy; }
public static void main(String[] args) { UserService userService = new JDKProxyDemo(new UserServiceImpl()).getLoggingProxy(); userService.addUser("name"); } }
|
1.3 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 28 29 30 31 32 33 34 35 36 37 38
| public class CglibProxyDemo implements MethodInterceptor { private Object target;
public Object getUserLogProxy(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); enhancer.setCallback(this); return enhancer.create(); }
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("[before] execute method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
System.out.println("[after] execute method: " + method.getName() + ", return value: " + result); return null; }
public static void main(String[] args) { UserService userService = (UserService) new CglibProxyDemo().getUserLogProxy(new UserServiceImpl());
userService.addUser("test"); } }
|
1.4 两代理区别
JDK是基于接口和反射技术实现的动态代理,动态生成代理类调用接口方法,只能代理类中实现接口的方法。
CGLIB是基于类继承和ASM字节码编程实现的动态代理,动态生成代理类调用被代理类的方法,限制比较小。