本文分析Spring AOP和动态代理原理和实现,Spring版本: 5.2.3.RELEASE
动态代理
1.1 代理模式
代理模式也叫做委托模式,它是一种基本的设计模式,其作用是提供委派角色以控制对真实对象的访问。
典型的代理模式通常包含一下三类角色
- 抽象角色:它的作用是定义一组行为规范。抽象角色一般呈现为接口或抽象类
- 真实角色:也叫做被委托角色、被代理角色
- 代理角色:也叫做委托类,代理角色需要实现抽象角色所定义的行为(即代理类需要实现抽象角色所定义的接口),并且在实现接口方法的时候需要调用真实角色的相应方法
静态代理类依赖于真实类,对每一个真实类作代理都需要对应一个代理类,静态代理大量使用会导致类的急剧膨胀,区别于静态代理在编译期确定代理类和真实类的关系并且生成代理类。动态代理则是在运行期利用JVM的反射机制生成代理类的字节码,并通过类加载器载入执生成代理对象
1.2 JDK动态代理
JDK动态代理是在运行时借助Proxy工具类静态方法创建实现了一组特定接口的代理类和对象,Proxy类是所有被创建的动态代理类的父类,每一个动态代理对象都会与特定的InvocationHandler对象绑定,对任意代理对象实现的接口方法的调用都会最终委派给InvocationHandler#invoke方法
// 定义抽象角色接口
public interface Subject {
void sayHello(String name);
}
// 接口实现
public class RealSubject implements Subject {
@Override
public void sayHello(String name){
System.out.println("hello, "+ name);
}
}
// 编写调用处理类,实现invoke方法(增强逻辑的入口)
public class DynamicInvocationHandler implements InvocationHandler {
private Object subject;
public Object init(Object subject) {
this.subject = subject;
return Proxy.newProxyInstance(this.subject.getClass().getClassLoader(), this.subject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
//前置处理
System.out.println("Before method invoke...");
Object obj = method.invoke(subject, args);
//后置处理
System.out.println("After method invoke...");
return obj;
}
}
// 测试方法
public class Client{
public static void main(String[] args) {
Subject realSubject = new RealSubject();
DynamicInvocationHandler handler = new DynamicInvocationHandler();
Subject proxy = (Subject)handler.init(realSubject);
proxy.sayHello("world");
}
运行结果:
Before method invoke...
hello, world
After method invoke...
从运行结果可以看出,对代理对象方法的调用会进入到自定义DynamicInvocationHandler#invoke方法,并在目标方法执行前后打印出了日志。将Proxy类生成的代理类通过反编译得到如下类文件,可以看到RealSubjectProxy继承自Proxy且实现了Subject接口,它定义了4个方法m0,m1,m2,m3,其中方法m3是对Subject接口sayHello方法的实现
public final class RealSubjectProxy extends Proxy implements Subject {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public RealSubjectProxy(InvocationHandler var1) throws {
super(var1);
}
// 代理方法
public final void sayHello(String var1) throws {
try {
// 将方法处理委派给父类InvocationHandler#invoke方法
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
static {
try {
//m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.example.demo.proxy.Subject").getMethod("sayHello", Class.forName("java.lang.String"));
//m2 = Class.forName("java.lang.Object").getMethod("toString");
//m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
// Proxy类带参构造函数
public class Proxy implements java.io.Serializable {
protected InvocationHandler h;
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
}
Proxy类对外提供了4个静态方法,分别为
public static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces);
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h);
public static boolean isProxyClass(Class<?> cl);
public static InvocationHandler getInvocationHandler(Object proxy);
newProxyInstance通过给定类加载器和接口生成代理对象
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 获取代理类
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 获取带参数InvocationHandler的构造器
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 反射创建代理对象
return cons.newInstance(new Object[]{h});
}
// 省略
}
getProxyClass获取代理类对象
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException {
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
return getProxyClass0(loader, intfs);
}
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 如果缓存包含给定类加载器创建并且实现了特定接口的代理类,则返回该代理类; 否则动态创建此代理类对象
return proxyClassCache.get(loader, interfaces);
}
1.2 Cglib动态代理
JDK动态代理虽然简单易用,但是其只能对实现了接口的类进行代理,而CGLIB以继承的方式动态生成一个被代理类的子类为没有实现接口的类提供代理,为JDK的动态代理提供了很好的补充。CGLIB原理是底层使用了ASM来操作字节码生成新的类,子类重写被代理的类的所有非final的方法。在子类中通过方法拦截器拦截所有父类方法的调用,织入横切逻辑处理。
// 定义Target类
public class Subject {
public void sayHello() {
System.out.println("hello, world!");
}
}
// 定义方法拦截器
public class LogInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable{
System.out.println("before ...");
Object result = methodProxy.invokeSuper(object, args);
System.out.println("after ...");
return result;
} }
public class CglibClient {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
// 设置超类,Cglib通过继承实现
enhancer.setSuperclass(Subject.class);
// 设置方法拦截器回调引用,对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept() 方法进行拦截
enhancer.setCallback(new LogInterceptor());
// 创建cglib 代理类
Subject proxy = (Subject)enhancer.create();
proxy.sayHello();
}
}
控制台输出:
before ...
hello, world!
after ...
Cglib动态代理对象生成Enhancer是CGLIB的字节码增强器,代理类创建入口在Enhancer#create方法
- 生成代理类的二进制字节码文件;
- 加载二进制字节码,生成Class对象;
- 通过反射机制获得实例构造器并创建代理类对象,在实例化代理类对象时执行静态代码块创建MethodProxy
public Object create() {
classOnly = false;
argumentTypes = null;
return createHelper();
}
private Object createHelper() {
validate();
if (superclass != null) {
//设置生成类的名称
setNamePrefix(superclass.getName());
} else if (interfaces != null) {
//设置生成类的名称
setNamePrefix(interfaces[ReflectUtils.findPackageProtected(interfaces)].getName());
}
//生成代理类对象(AbstractClassGenerator#newInstance方法中生成代理类的二进制字节码文件以及加载二进制字节码)
return super.create(KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
ReflectUtils.getNames(interfaces),
filter,
callbackTypes,
useFactory,
interceptDuringConstruction,
serialVersionUID));
}
Cglib创建代理对象会产生如下3个Class文件
首先来看Cglib生成的代理类Subject$$EnhancerByCGLIB$$bc785f22.class,代理类在实例化时会执行其静态方法块,期间会给代理类的成员方法创建一个MethdProxy对象,比如方法CGLIB$sayHello$0与CGLIB$sayHello$0$Proxy,MethdProxy会在拦截器实行被调用
public class Subject$$EnhancerByCGLIB$$bc785f22 extends Subject implements Factory {
private MethodInterceptor CGLIB$CALLBACK_0; //拦截器
private static final Method CGLIB$sayHello$0$Method; //目标方法
private static final MethodProxy CGLIB$sayHello$0$Proxy; //代理方法
// ...省略
static void CGLIB$STATICHOOK1() {
// 加载生成的代理类Class对象
Class var0 = Class.forName("com.example.demo.proxy.cglib.Subject$$EnhancerByCGLIB$$bc785f22");
// 目标类(Subject)Class对象
Class var1;
// 通过反射获取目标类方法sayHello
CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.example.demo.proxy.cglib.Subject")).getDeclaredMethods())[0];
// 创建MethodProxy
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0"); }
// 在拦截器中执行methodProxy.invokeSuper会进入这里
final void CGLIB$sayHello$0() {
super.sayHello();
}
public final void sayHello() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello();
}
}
// ...省略
}
创建MethdProxy对象分析,主要是实例化MethodProxy 和CreateInfo对象,CreateInfo用于拦截器执行时创建FastClass实例
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) {
MethodProxy proxy = new MethodProxy();
// 目标类sayHello方法签名
proxy.sig1 = new Signature(name1, desc);
// 代理类CGLIB$sayHello$0方法签名
proxy.sig2 = new Signature(name2, desc);
// 创建createInfo(CreateInfo是MethodProxy的一个内部类),用来保存类等信息
proxy.createInfo = new CreateInfo(c1, c2);
return proxy;
}
private static class CreateInfo {
// 目标类Subject
Class c1;
// 代理类Subject$$EnhancerByCGLIB$$bc785f22
Class c2;
NamingPolicy namingPolicy;
GeneratorStrategy strategy;
boolean attemptLoad;
public CreateInfo(Class c1, Class c2) {
this.c1 = c1;
this.c2 = c2;
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent();
if (fromEnhancer != null) {
namingPolicy = fromEnhancer.getNamingPolicy();
strategy = fromEnhancer.getStrategy();
attemptLoad = fromEnhancer.getAttemptLoad();
}
}
}
FastClass机制
在讲代理对象方法执行流程前先了解一下Cglib的FastClass机制,它的原理简单来说就是为代理类和被代理类各生成一个Class,这个Class会为代理类或被代理类的方法分配一个index,在方法执行阶段,FastClass机制可以利用方法index直接定位要调用的方法进行调用,省去了反射调用,所以从调用效率上会比JDK动态代理通过反射调用高。之前生成的class文件中Subject$$EnhancerByCGLIB$$bc785f22$$FastClassByCGLIB$$c5058ad4就是代理类的FastClass,而Subject$$FastClassByCGLIB$$a84ac285就是目标类的FastClass。
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
//FastClass并不是跟代理类一块生成的,而是在第一次执行MethodProxy invoke/invokeSuper时生成的并放在了缓存中。
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
private static class FastClassInfo {
FastClass f1;//目标类FastClass
FastClass f2;//代理类FastClass
int i1; //目标类方法index
int i2;//代理类方法index
private FastClassInfo() {
}
}
/MethodProxy invoke/invokeSuper都调用了init()
private void init() {
if(this.fastClassInfo == null) {
Object var1 = this.initLock;
synchronized(this.initLock) {
if(this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
fci.f1 = helper(ci, ci.c1);//如果缓存中就取出,没有就生成新的FastClass
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);//获取方法的index
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
代理对象方法执行流程分析
调用代理对象sayHello方法 → 调用对应的方法拦截器(LogInterceptor) → methodProxy.invokeSuper → 进入代理类CGLIB$sayHello$0方法 → 目标类sayHello方法
public class Subject$$EnhancerByCGLIB$$bc785f22 extends Subject implements Factory {
private MethodInterceptor CGLIB$CALLBACK_0; //拦截器
private static final Method CGLIB$sayHello$0$Method; //被代理方法
private static final MethodProxy CGLIB$sayHello$0$Proxy; //代理方法
static void CGLIB$STATICHOOK1() {
// 加载生成的代理类Class对象
Class var0 = Class.forName("com.example.demo.proxy.cglib.Subject$$EnhancerByCGLIB$$bc785f22");
// 目标类Class对象
Class var1;
// 通过反射获取被代理方法sayHello
CGLIB$sayHello$0$Method = ReflectUtils.findMethods(new String[]{"sayHello", "()V"}, (var1 = Class.forName("com.example.demo.proxy.cglib.Subject")).getDeclaredMethods())[0];
// 创建MethodProxy
CGLIB$sayHello$0$Proxy = MethodProxy.create(var1, var0, "()V", "sayHello", "CGLIB$sayHello$0");
}
// 在拦截器中调用methodProxy.invokeSuper会进入这里
final void CGLIB$sayHello$0() {
super.sayHello();
}
public final void sayHello() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
// 判断拦截器是否为空,不为空调用拦截器intercept方法
if (var10000 != null) {
// @param this 代理对象本身
// @param CGLIB$sayHello$0$Method Subject类sayHello方法Method对象【静态代码块已赋值】
// @param CGLIB$emptyArgs Subject类sayHello方法参数
// @param CGLIB$sayHello$0$Proxy Subject类sayHello方法的代理方法对象【静态代码块已赋值, 即CGLIB$sayHello$0方法】
var10000.intercept(this, CGLIB$sayHello$0$Method, CGLIB$emptyArgs, CGLIB$sayHello$0$Proxy);
} else {
super.sayHello();
}
}
// ...省略
}
接下来,在LogInterceptor的intercept方法中调用的MethodProxy#invokeSuper时,最终就会执行父类Subject#sayHello方法。MethodProxy#invokeSuper的执行逻辑如下
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
//FastClass对象并不是跟代理类对象一块生成的,而是在第一次执行MethodProxy invoke/invokeSuper时生成的并放在了缓存中。
init();
FastClassInfo fci = fastClassInfo;
// 执行代理类对象CGLIB$sayHello$0方法
return fci.f2.invoke(fci.i2, obj, args);
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
private void init()
{
if (fastClassInfo == null)
{
synchronized (initLock)
{
if (fastClassInfo == null)
{
// 获取代理类的创建信息【上面有提过】
CreateInfo ci = createInfo;
// 新建FastClassInfo对象
FastClassInfo fci = new FastClassInfo();
// 生成目标类对应FastClass对象
fci.f1 = helper(ci, ci.c1);
// 生成代理类对应FastClass对象
fci.f2 = helper(ci, ci.c2);
// 根据方法签名,获取目标类中对应sayHello方法在f1中的索引
fci.i1 = fci.f1.getIndex(sig1);
// 根据方法签名,获取代理类中对应CGLIB$sayHello$0方法在f2中的索引
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
/*
* FastClassInfo也是MethodProxy的一个内部类
*/
private static class FastClassInfo {
FastClass f1;//目标类FastClass
FastClass f2;//代理类FastClass
int i1; //目标类sayHello方法index
int i2;//代理类CGLIB$sayHello$0方法index
private FastClassInfo() {
}
}
二、Spring AOP
AOP(Aspect Orient Programming),一般称为面向切面编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。SpringAOP则是Spring提供的一个标准易用的aop框架,依托Spring的IOC容器,提供了极强的AOP扩展增强能力,SpringAOP的实现依靠其底层采用的JDK/CGLIB动态代理。
2.1 AOP核心概念
术语 含义
Aspect 声明切面,类似于类定义,每个Aspect可以包含多个PointCut和Advice
PointCut 切点,用来筛选需要在哪些位置做增强处理
Joinpoint 连接点,通过PointCut筛选出来执行增强的节点,如方法被调用时、异常抛出时等
Advice 连接点处执行的增强逻辑
Target Object 目标对象,被织入Advice的对象
Weaving
将Advice织入到连接点的处理过程,织入可在编译时完成(例如使用AspectJ编译器),而Spring AOP在运行时完成织入处理
为了标准化AOP,Spring引入了一套AOP顶级API(AOP联盟),用来定义和使用AOP。spring-aop jar包中有个目录org.aopalliance,其中存在几个接口是AOP联盟提供的标准AOP的API
2.2 SpringAOP与AOP联盟关系
2.3 SpringAOP的实现思路
在讲Spring AOP核心组件概念前,我们首先通过一个例子直观上理解Spring AOP核心组件作用原理。使用Spring AOP的关键在于配置获取Advisor,在Spring 2.0 版本之前定义Advisor是通过实现Advisor接口(或者IntroductionAdvisor),定义拦截器和拦截规则(切点)。使用SpringAOP大体流程为以下3点:
配置获取Advisor :定义拦截器(Advice)+ 拦截规则(切点),生成Advisor
生成代理:根据Advisor生成代理对象,会生成JdkDynamicAopProxy或CglibAopProxy
方法执行:执行代理方法时从Advisor取出Advice转换为MethodInvocation(连接点),执行拦截器调用
//定义一个Service及实现
public interface DemoService {
}
public class DemoServiceImpl implements DemoService {
@Override
public void echo() {
System.out.println("Echo method invoke...");
}
}
//自定义PointCut,用于筛选DemoService 的echo方法
public class DemoPointCut implements Pointcut {
@Override
public ClassFilter getClassFilter() {
return new ClassFilter() {
@Override
public boolean matches(Class<?> clazz) {
return DemoService.class.isAssignableFrom(clazz);
}
};
}
@Override
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return "echo".equals(method.getName());
}
@Override
public boolean isRuntime() {
return false;
}
@Override
public boolean matches(Method method, Class<?> targetClass, Object... args) {
return false;
}
};
}
}
// 实现Advice接口增加横切逻辑
public class LogInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("Before method invoke ...");
return invocation.proceed();
}
}
// 自定义Advisor
public class DemoAdvisor implements PointcutAdvisor {
@Override
public Advice getAdvice() {
return new LogInterceptor ();
}
@Override
public Pointcut getPointcut() {
return new DemoPointCut();
}
@Override
public boolean isPerInstance() {
return false;
}
}
// 测试方法
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory(new DemoService());
proxyFactory.addAdvisor(new DemoAdvisor());
// 生成代理对象
DemoService proxy = (DemoService)proxyFactory.getProxy();
proxy.echo();
}
//控制台输出:
Before method invoke ...
Echo method invoke...
上面的例子是通过自定义实现API的形式来配置创建Advisor,当然我们也可以借助Spring AOP的内置实现,并把对象交由Spring来管理,让Spring容器帮我们自动生成代理对象,Spring AOP提供了很多类来帮助实现自动创建代理对象,它们有一个共同的父类AbstractAutoProxyCreator,AbstractAutoProxyCreator具体的创建过程后面再分析。这里我们使用DefaultAdvisorAutoProxyCreator演示, 上面的Demo可以改为如下形式,变化基本不大
public class AutoProxyConfig {
@Bean
public DemoService echoService() {
return new DemoServiceImpl();
}
@Bean
public LogInterceptor logInterceptor() {
return new LogInterceptor();
}
@Bean
public Advisor advisor() {
NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
advisor.setMappedName("echo");
advisor.setAdvice(logInterceptor());
return advisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator autoProxyCreator() {
return new DefaultAdvisorAutoProxyCreator();
}
}
测试方法:
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AutoProxyConfig.class);
// 获取代理对象
DemoService demoService = context.getBean(DemoService.class);
demoService.echo();
}
控制台输出:
Before method invoke ...
Echo method invoke...
当Spring 2.0发布以后,Spring AOP集成了AspectJ增加了新的使用方式,即通过AspectJ注解方式(如@Aspect和@Around)定义Aspect和Adivce, 但是Spring AOP只是引入了其注解功能(提供注解驱动的AOP),底层的实现和织入方式还是1.x原先的实现体系。上面的Demo可以改为如下形式,这也是现在我们使用AOP最常用的形式
@Aspect
@Component
public class LogAspect {
@Pointcut(value = "execution(* com.example.demo.service..*.*(..))")
public void pointCut() {
}
@Before("pointCut()")
public void logStart(JoinPoint joinPoint){
System.out.println("Before method invoke ...");
}
}
2.4 核心组件概念
2.4.1 Advice
通知(增强器)顶级接口,通过PointCut筛选出Jointpoint时,我们就需要在这些Jointpoint上增加横切逻辑,这些横切逻辑被称为Advice。Advice主要分成两类普通Advice与Interceptor/MethodInterceptor,无论通过aop命名空间/AspectJ注解注释的方法, 其最终都将解析成对应的Advice,所有的Advice会在最终代理方法执行阶段转换适配成MethodInterceptor被执行
使用AspectJ注解定义切面时常用到的五个注解,每个注解会分别被包装为以下Advice, 它们实际上是对以上Advice的实现
2.4.2 Interceptor
Interceptor是继承自Advice的中间接口,它表示以拦截器方式实现增强效果,Interceptor得子接口有两个:MethodInterceptor和ConstructorInterceptor,但是Spring没有提供ConstructorInterceptor的实现类,而MethodInterceptor则表示通过拦截方法的执行来实现增强效果,上述基于AspectJ注解对应的五个Advice,本质上都是实现了MethodInterceptor(或者在执行阶段被转换为MethodInterceptor),比如实现环绕通知Advice类(AspectJAroundAdvice)就实现了MethodInterceptor
前置通知AspectJMethodBeforeAdvice没有实现MethodInterceptor,但是会在执行阶段被包装为MethodBeforeAdviceInterceptor,执行包装的是MethodBeforeAdviceAdapter
2.4.3 Jointpoint
通过Pointcut筛选出需要增强处理的地方就是Jointpoint。 在方法执行阶段可以通过Joinpoint实现类中获取增强器等信息,比如使用Cglib生成代理对象,在代理方法执行时就是通过CglibMethodInvocation(Joinpoint实现)获得拦截器(MethodInterceptor)并链式执行。在AOP理念中很多地方可以增加横切逻辑,如方法执行,字段设置等。Spring目前只支持方法执行这一种Joinpoint,Spring提供的Joinpoint实现如下
public interface Joinpoint {
// 执行此拦截点,并进入到下一个连接点
Object proceed() throws Throwable;
// 返回保存当前连接点静态部分,这里一般指target对象
Object getThis();
// 返回此静态连接点 一般就为当前的Method
AccessibleObject getStaticPart();
}
public interface Invocation extends Joinpoint {
// 返回方法参数
Object[] getArguments();
public interface MethodInvocation extends Invocation {
// 返回当前Method对象,效果同父类的getStaticPart方法
Method getMethod();
}
SpringAOP在AOP Alliance基础上增加了几个类,丰富了AOP定义及使用概念,包括
Advisor:包含Advice和PointCut,Spring内部使用AOP的顶级接口
Pointcut: 匹配哪些类哪些方法需要被切面处理,包含一个ClassFilter和一个MethodMatcher
ClassFilter:类过滤器,定义类过滤规则,用于筛选哪些类对象需要使用AOP
MethodMatcher:方法匹配器,定义方法匹配规则,用于筛选哪些方法需要使用AOP
2.4.4 Advisor
在AOP设计理念中通过Aspect来声明切面,每个Aspect可以包含多个Pointcut和Advice。在Spring AOP中,Aspect对应的实现为Advisor。Advisor是Pointcut和Advice的容器,但是一个Advisor只能包含一个Pointcut和Advice。配置定义Advisor是使用Spring AOP的关键。
public interface Advisor {
// Spring5以后才有的空通知,一般当作默认值
Advice EMPTY_ADVICE = new Advice() {
};
// 该Advisor 持有的通知器
Advice getAdvice();
boolean isPerInstance();
}
Advisor是顶级接口,但是没有给出过滤匹配切点的方式,两个主要的扩展接口IntroductionAdvisor(引介增强)和PointcutAdvisor,区别在IntroductionAdviso只能应用于类级别的拦截,只能使用Introduction型的Advice,而PointcutAdvisor定义了class类型+方法匹配过滤方式,可以使用任何类型的Pointcut以及几乎任何类型的Advice,PointcutAdvisor功能更强大,IntroductionAdvisor平时较少用到,这里不做介绍,Spring提供的PointcutAdvisor实现非常多,这里列举其中部分实现:
- AspectJPointcutAdvisor:Spring解析aop命名空间时生成的Advisor,对应的Advice是AspectJMethodBeforeAdvice、AspectJAfterAdvice,、AspectJAfterReturningAdvice,、AspectJAfterThrowingAdvice和AspectJAroundAdvice,Pointcut则是AspectJExpressionPointcut,对于这个类的解析是在 ConfigBeanDefinitionParser
- InstantiationModelAwarePointcutAdvisorImpl:Spring解析被@AspectJ注释的类时生成的Advisor,这个Advisor中的 Pointcut与Advice都是由ReflectiveAspectJAdvisorFactory来解析生成的(与之对应的Advice和Pointcut同AspectJPointcutAdvisor),具有延迟初始化策略
- DefaultPointcutAdvisor Spring提供的通用的,也被认为是最强大的Advisor。它可以组合任意的两个Advice和Pointcut
- BeanFactoryCacheOperationSourceAdvisor:Spring缓存注解@Cacheable相关
- AsyncAnnotationAdvisor:Spring异步方法调用注解@Async相关
- NameMatchMethodPointcutAdvisor:基于方法名是否匹配来执行Advice,其中的Pointcut 默认是NameMatchMethodPointcut
- RegexpMethodPointcutAdvisor:基于正则表达式来匹配执行Advice,其中的Pointcut 默认是JdkRegexpMethodPointcut
- BeanFactoryTransactionAttributeSourceAdvisor:在注解式事务编程时, 主要是由BeanFactoryTransactionAttributeSourceAdvisor、AnnotationTransactionAttributeSource和TransactionInterceptor组合起来进行事务的操作
2.4.5 PointCut
定义切面的匹配点,简单的说就是去切哪些类、哪些方法,在Spring Aop中匹配的点主要是class与method,对应于为ClassFilter与MethodFilter
public interface Pointcut {
// 类过滤器, 可以知道哪些类需要拦截
ClassFilter getClassFilter();
// 方法匹配器, 可以知道哪些方法需要拦截
MethodMatcher getMethodMatcher();
// 匹配所有对象的 Pointcut
Pointcut TRUE = TruePointcut.INSTANCE;
}
Spring提供的部分PointCut实现列举:
NameMatchMethodPointcut:基于方法名进行匹配。 (其中ClassFilter = ClassFilter.TRUE)
ComposablePointcut:组合模式的 Pointcut, 主要分成两种: 1.组合中所有都匹配算成功 2. 组合中都不匹配才算成功
JdkRegexpMethodPointcut:通过正则表达式来匹配方法(ClassFilter = ClassFilter.TRUE)
AspectJExpressionPointcut:通过 AspectJ 包中的组件进行方法的匹配(切点表达式)
TransactionAttributeSourcePointcut:Spring注解式事务的Pointcut。通过匹配方法上@Transactional标签来确定方法是否匹配
2.6 Spring AOP自动动态代理
使用Aspectj 提供的注解定义切面,Spring只是引入了其注解形底层的实现和织入方式还是1.x原先的实现体系,由Spring解析配置生成Advisor,这里以在SpringBoot工程使用AOP为例说明Spring是如何自动解析配置Advisor并生成代理对象的。这也是目前我们使用AOP的常用方式,以日志切面为例,定义Aspect如下
整体处理流程如下
1.@EnableAspectJAutoProxy注解会开启AOP功能,并在项目启动时往IOC容器中注册组件 AnnotationAwareAspectJAutoProxyCreator,它实现了BeanPostProcessor
- AnnotationAwareAspectJAutoProxyCreator会拦截Bean的创建过程, 判断Bean是否需要增强,如需要就会配置包装增强器(Advisor),并借助动态代理将增强逻辑织入创建的代理对象
- 方法执行阶段,对方法调用会被代理对象拦截器拦截(以Cglib为例),执行者是CglibAopProxy.DynamicAdvisedInterceptor#intercept方法,在该方法中会通过代理对象中保存的增强器,目标对象等信息生成目标方法的拦截器链(即将增强器包装成拦截器MethodInterceptor),利用拦截器的链式机制,依次进入每一个拦截器进行执行,AnnotationAwareAspectJAutoProxyCreator类关系图
SpringBoot 启动时refresh方法中调用this.registerBeanPostProcessors(beanFactory) 实例化和注册实现了后置处理器(BeanPostProcessor)的Bean,在初始化AnnotationAwareAspectJAutoProxyCreator时会调用BeanFactoryAware接口方法setBeanFactory将BeanFactory注入组件,同时初始化AspectJAdvisorFactory和BeanFactoryAspectJAdvisorsBuilderAdapter,BeanFactoryAspectJAdvisorsBuilderAdapter封装了工厂类AspectJAdvisorFactory,其核心的逻辑在其方法buildAspectJAdvisors中,该方法查找容器中所有@AspectJ注解的Bean,然后将其中每个advice方法包装成Advisor
@Override
public void setBeanFactory(BeanFactory beanFactory) {
super.setBeanFactory(beanFactory);
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
throw new IllegalArgumentException(
"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
}
initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
}
@Override
protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.initBeanFactory(beanFactory);
if (this.aspectJAdvisorFactory == null) {
this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
}
this.aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}
Spring Bean创建都会进入BeanPostProcessor的处理过程,Spring AOP自动配置Advisor并通过动态代理创建Proxy对象织入增强逻辑入口也正是在AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInitialization方法,整体流程图
代码处理入口在AbstractAutoProxyCreator#postProcessAfterInitialization方法
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 根据需要包装Bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// TargetSource是对被代理对象target的封装,代理对象从TargetSource获取target
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 如果已经被增强处理过,直接返回
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 判断bean的类型是否为基础类:Advice,Pointcut,Advisor,AopInfrastructureBean
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 获取方法拦截器(Advisor集合),如果Advisor不为空则创建代理对象
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
获取 Advisor集合方法入口(AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean)
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 步骤1. 用于获取所有的Advisor, 包括直接配置得Advisor和用AspectJ定义的Advisor,即把AspectJ定义的bean转化为Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 步骤2. 遍历获取到的Advisor,逐一从Advisor拿到PointCut, 通过PointCut判断Advisor是否适用于当前Bean
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
// 拓展Advisor
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
// 对Advisor排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
// 步骤1处会进入AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
protected List<Advisor> findCandidateAdvisors() {
// 获取直接配置的Advisor,实现Advisor接口的bean组件
List<Advisor> advisors = super.findCandidateAdvisors();
// 获取标注@Aspect组件的bean ,并解析bean标注了@Before, @After, @AfterReturning, @AfterThrowing的方法转换为Advisor
if (this.aspectJAdvisorsBuilder != null) {
// aspectJAdvisorsBuilder在注册AnnotationAwareAspectJAutoProxyCreator组件时生成,
// 它会在BeanFactory中查找带有@Aspect注解的Bean, 并通过AspectJAdvisorFactory为每一个Advice方法生成一个Advisor
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
// 步骤2处findAdvisorsThatCanApply方法最终进入以下方法判断
public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
// PointCut中类过滤器是否匹配目标类
if (!pc.getClassFilter().matches(targetClass)) {
return false;
}
// 省略 ...
// 创建方法匹配器
IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
}
Set<Class<?>> classes = new LinkedHashSet<>();
if (!Proxy.isProxyClass(targetClass)) {
classes.add(ClassUtils.getUserClass(targetClass));
}
classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
for (Class<?> clazz : classes) {
Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
// 遍历方法对象
for (Method method : methods) {
if (introductionAwareMethodMatcher != null ?
// 存在某一方法匹配,则返回true
introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
methodMatcher.matches(method, targetClass)) {
return true;
}
}
}
return false;
}
在讲代理创建前,先了解一下ProxyFactory,前面的例子中可以看到创建代理对象走的是ProxyFactory.getProxy(getProxyClassLoader()), 但真正创建代理对象是通过AopProxyFactory。ProxyFactory继承自ProxyCreatorSupport和AdvisedSupport,ProxyCreatorSupport默认构造函数初始化了一个默认的 AopProxyFactory(即DefaultAopProxyFactory,Spring唯一实现),AdvisedSupport用于保存Advisor、目标对象和接口等属性,ProxyFactory#getProxy方法实际上是调用了DefaultAopProxyFactory#createAopProxy(AdvisedSupport config)
Spring Aop创建代理对象并织入切面逻辑的入口AbstractAutoProxyCreator#createProxy方法
protected Object createProxy(Class<?> beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// 创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 将需要织入的切面逻辑都转换为Advisor对象
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
// 提供的hook方法,供子类实现对代理工厂的定制
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 生成代理类
return proxyFactory.getProxy(getProxyClassLoader());
}
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
// 从父类ProxyCreatorSupport拿到代理类工厂DefaultAopProxyFactory,并将自身( ProxyFactory继承AdvisedSupport)作为参数传入,作为创建的代理对象属性
// AdvisedSupport会作为后续方法执行时获取Advisor,目标对象和接口等构造拦截器链的来源
return getAopProxyFactory().createAopProxy(this);
}
Spring AOP生成代理对象用了工厂模式
AopProxyFactory创建代理对象
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
// 判断当前类是否需要进行运行时优化,或者是指定了使用Cglib代理的方式,再或者是目标类没有用户提供的相关接口,则使用Cglib代理
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代理生成的类,此时还是使用Jdk代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
// 返回Cglib代理生成对象
return new ObjenesisCglibAopProxy(config);
} else {
// 返回JDK代理生成对象
return new JdkDynamicAopProxy(config);
}
}
以下主要分析使用Cglib方式生成代理实现代理逻辑的织入
public Object getProxy(@Nullable ClassLoader classLoader) {
try {
Class<?> rootClass = this.advised.getTargetClass();
Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");
// 判断当前类是否是已经通过Cglib代理生成的类,如果是的,则获取其原始父类,
// 并将其接口设置到需要代理的接口中
Class<?> proxySuperClass = rootClass;
if (ClassUtils.isCglibProxyClass(rootClass)) {
// 获取父类
proxySuperClass = rootClass.getSuperclass();
// 获取父类实现的接口,并将其设置到需要代理的接口中
Class<?>[] additionalInterfaces = rootClass.getInterfaces();
for (Class<?> additionalInterface : additionalInterfaces) {
this.advised.addInterface(additionalInterface);
}
}
// 对目标类进行检查,主要检查点有三个:
// 1. 目标方法不能使用final修饰;
// 2. 目标方法不能是private类型的;
// 3. 目标方法不能是包访问权限的;
// 这三个点满足任何一个,当前方法就不能被代理,此时该方法就会被略过
validateClassIfNecessary(proxySuperClass, classLoader);
// 创建Enhancer对象,并且设置ClassLoader
Enhancer enhancer = createEnhancer();
if (classLoader != null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
// 这里AopProxyUtils.completeProxiedInterfaces()方法的主要目的是为要生成的代理类增加SpringProxy,Advised这两个需要实现的接口。这里两个接口的作用如下:
// 1. SpringProxy:是一个空接口,用于标记当前生成的代理类是Spring生成的代理类;
// 2. Advised:Spring生成代理类所使用的属性都保存在该接口中,包括Advisor,目标对象等属性;
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
// 获取代理类中各个方法将要使用的Interceptor(这里的Interceptor与aopaliance中的Interceptor不是同一接口), 其中就包括(DynamicAdvisedInterceptor)
Callback[] callbacks = getCallbacks(rootClass);
Class<?>[] types = new Class<?>[callbacks.length];
for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// 设置拦截器过滤器,用于筛选各个方法将要使用的Interceptor,这里的ProxyCallbackFilter.accept()方法返回的整型值正好一一对应上面Callback数组中各个拦截器的下标
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap,
this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// 生成代理对象
return createProxyClassAndInstance(enhancer, callbacks);
} catch (CodeGenerationException | IllegalArgumentException ex) {
// 省略
} catch (Throwable ex) {
throw new AopConfigException("Unexpected AOP exception", ex);
}
}
目标方法的执行
代理对象创建好后,其实最终的拦截工作都是交给了MethodInvocation,JDK交给ReflectiveMethodInvocation,Cglib交给CglibMethodInvocation(继承自ReflectiveMethodInvocation),执行过程图示
这里以Cglib说明执行的大体过程:
- 对目标方法调用实际上会进入代理对象方法的执行,如前面Cglib动态代理部分分析,通过Cglib生成代理对象的方法执行最终会进入CglibAopProxy.DynamicAdvisedInterceptor#intercept方法
- 在DynamicAdvisedInterceptor#intercept方法中通过代理对象持有的ProxyFactory(继承自AdvisedSupport)将代理对象保存的Advisor转化为拦截器链
- 同时构造CglibMethodInvocation作为拦截器链调用入口,CglibMethodInvocation继承自ReflectiveMethodInvocation,入口方法proceed实际上会进入ReflectiveMethodInvocation#proceed方法
- 在ReflectiveMethodInvocation#proceed中获取每一个方法拦截器并执行其invoke方法(若当前拦截器不是最后一个),每一个拦截器会等待下一个拦截器执行完成返回以后再继续执行,在拦截器执行invoke方法前后执行增强处理;如果为最后一个拦截器则调用目标方法
- 拦截器链的机制,保证增强处理方法与目标方法的执行顺序
链式调用机制
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
// 目标对象源
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 拿到目标对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 将代理对象保存的Advisor转化为拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
//没有增强器,同时该方法是public得 就直接调用目标方法(不拦截)
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// 构造CglibMethodInvocation作为拦截器链调用入口并执行调用
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
// 处理返回值
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。