AOP是Spring最重要的功能之一,通过切面实现对象增强,降低对业务的侵入,把核心业务代码和周边公共代码解耦。
比如,在方法上加上@Transactional注解,就能够使用Spring的默认事务机制,通过TransactionInterceptor实现切面,在before时提供调用点,决定业务方法是否需要开启一个新的独立事务,在after时确定事务被提交、回滚、还是继续运行。这就不需要在每个方法里都重复写一遍事务操作的相关代码。
AOP通过动态创建代理对象实现,动态代理的方式分为JDK动态代理和CGLIB,以下简述这两种代理方式的使用
JDK动态代理
先看使用,需要通过Proxy类的 newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法来生成指定类型的代理对象,该类必须有实现的接口。
使用举例:
public interface IUserInfoService {
Integer saveUserInfo(UserInfo userInfo);
}
public class UserInfoServiceImpl implements IUserInfoService {
@Override
public Integer saveUserInfo(UserInfo userInfo) {
System.out.println(userInfo.getUserName());
return userInfo.getId();
}
}
public static void main(String[] arg) {
UserInfo userInfo = new UserInfo();
userInfo.setId(1);
userInfo.setUserName("小明");
IUserInfoService userInfoService = new UserInfoServiceImpl();
//创建代理对象
IUserInfoService userInfoServiceProxy = (IUserInfoService) Proxy.newProxyInstance(userInfoService.getClass().getClassLoader(),
//传入要代理的接口
userInfoService.getClass().getInterfaces(),
//传入InvocationHandler接口实现类,提供切面逻辑
(proxy, method, args) -> {
//实现增强
System.out.println("方法执行前");
Object obj = method.invoke(userInfoService, args);
System.out.println("方法执行后");
return obj;
});
System.out.println("Id:" + userInfoServiceProxy.saveUserInfo(userInfo));
}
主要原理是,通过代理类生成器ProxyGenerator直接生成代理类的Class文件而不需要再通过虚拟机再加载。
生成过程是根据Class文件结构拼接而成的,源码分析可以参考:https://www.cnblogs.com/liuyun1995/p/8157098.html
生成的代理类默认继承Porxy类,实现传入的接口。
这也就解释了被代理的类需要实现接口,才能让代理类收集到需要代理的方法。
拿到Class文件后,通过getConstrucator()方法创建只有InvocationHandler类型参数的构造函数,然后通过newInstance()方法生成代理对象实例。
代理方法会调用InvocationHandler的invoke()方法,为被代理类的方法实现增强。
CGLIB
CGLIB全称Code Generation Library,意为代码生成库。
CGLIB代理也是通过生成字节码文件生成新的代理对象,它的思想是通过继承代理类的非final方法,然后在重写方法时写入增强。
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserInfoServiceImpl.class);
enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
//实现增强
System.out.println("方法执行前");
Object obj = methodProxy.invokeSuper(o, objects);
System.out.println("方法执行后");
return obj;
});
//创建被代理对象
UserInfoServiceImpl userInfoService = (UserInfoServiceImpl) enhancer.create();
System.out.println("Id:" + userInfoService.saveUserInfo(userInfo));
Enhancer相当于JDK代理中的Proxy,但它既能代理普通类,也能够代理接口。
这两种代理相比之下,一般认为CGLIB代理方式创建慢执行快,JDK动态代理创建快执行较慢。
AOP
Spring根据策略判断使用JDK动态代理和还是CGLIB
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// config.isProxyTargetClass() 目标类本身被代理而不是目标类的接口
// hasNoUserSuppliedProxyInterfaces() 是否存在代理接口
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); }
//目标是接口或是代理类时,使用JDK动态代理 if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else {
//默认使用JDK动态代理 return new JdkDynamicAopProxy(config); } }