AOP (Aspect-Oriented Programming ,面向切面编程)是一种编程范式,旨在通过横切关注点(Cross-cutting Concerns )的抽象和模块化,将系统的功能和非功能需求分离,从而提高代码的可维护性、可重用性和灵活性
代理模式 AOP的这种模式,底层就是基于代理模式实现
代理模式 (Proxy Pattern )是一种结构型设计模式,也叫委托模式 ,它允许通过一个代理对象来控制对另一个对象的访问。代理对象充当另一个对象的接口,以控制对该对象的访问,并在必要时添加额外的逻辑。代理模式主要用于对目标对象的访问进行控制,可以用于实现懒加载、访问控制、缓存、日志记录等功能
代理模式一般分为以下三个角色:
抽象主题 (Subject):定义了目标对象和代理对象的共同接口,这样在任何使用目标对象的地方都可以使用代理对象
真实主题 (Real Subject):也称为被代理对象或目标对象,它是代理模式中的真正业务逻辑的实现
代理 (Proxy):代理对象,它持有对真实主题的引用,并实现了抽象主题的接口。代理对象通常在客户端与真实主题之间起到中介的作用,它可以在调用真实主题之前或之后执行一些附加操作
代理模式实现 下面是一个简单的Java中代理模式的实现示例,使用了静态代理方式:
定义抽象主题接口(Subject):
1 2 3 4 public interface Subject { void doSomething () ; }
定义真实主题类(RealSubject):
1 2 3 4 5 6 7 public class RealSubject implements Subject { @Override public void doSomething () { System.out.println("RealSubject is doing something..." ); } }
定义代理类(Proxy):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Proxy implements Subject { private RealSubject realSubject; public Proxy () { realSubject = new RealSubject (); } @Override public void doSomething () { System.out.println("Proxy is doing something before the RealSubject..." ); realSubject.doSomething(); System.out.println("Proxy is doing something after the RealSubject..." ); } }
客户端代码:
1 2 3 4 5 6 7 8 public class Client { public static void main (String[] args) { Subject proxy = new Proxy (); proxy.doSomething(); } }
输出结果:
1 2 3 Proxy is doing something before the RealSubject...RealSubject is doing something...Proxy is doing something after the RealSubject...
在上面的示例中,抽象主题(Subject)定义了一个接口,真实主题(RealSubject)实现了这个接口,代理类(Proxy)也实现了这个接口,并在方法中调用了真实主题对象的方法,同时添加了一些额外的操作。客户端通过代理对象来访问真实主题,而无需直接与真实主题交互。这样,代理对象就控制了对真实主题的访问,并且可以在调用前后添加一些自定义的逻辑
动态代理 动态代理与静态代理的区别,首先要了解两个前置知识点:Java程序的执行以及类加载机制
Java程序的执行过程
编写源代码:首先,开发人员使用Java编程语言编写源代码,源代码通常以.java
为扩展名
编译源代码:使用Java编译器(javac)对源代码进行编译,将源代码转换为字节码文件。字节码文件以.class
为扩展名,并包含Java虚拟机(JVM)可执行的中间代码
执行.class
文件
类加载机制
加载 (loading):通过一个类的全限定名来获取定义此类的二进制字节流,将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;在内存中生成一个代表这个类的 java.lang.class
对象,作为方法区这个类的各种数据访问入口
连接 (Linking): 类加载的连接阶段包括三个子阶段:
验证(Verification):对加载的类进行验证,确保其符合Java虚拟机规范和安全要求
准备(Preparation):为类的静态变量分配内存空间,并设置默认初始值
解析(Resolution):将类的符号引用(常量池中的符号)解析为直接引用,建立对其他类的引用关系
初始化 (Initialization):
在初始化阶段,执行类的静态代码块和静态初始化语句,对类的静态变量进行初始化
初始化阶段是类加载的最后一个阶段,在此阶段完成后,Java类对象被完全初始化,可以被使用
动态代理和静态代理是两种不同的代理模式实现方式,它们在代理对象的创建和使用方式上存在一些区别
创建时机和方式:
静态代理:在编译阶段就需要创建代理类,代理类是由开发者手动编写的。对于每一个被代理的类,都需要创建一个相应的代理类
动态代理:在运行时动态生成代理类,无需手动编写代理类。代理类是在程序运行时根据接口或类信息动态创建的
代理对象与目标对象的关系:
静态代理:代理对象和目标对象之间的关系是静态的,即在编译时就已经确定了。每个代理类只能代理一个目标类,代理类与目标类是一一对应的关系
动态代理:代理对象和目标对象之间的关系是动态的,即在程序运行时根据需要动态生成代理类。一个动态代理类可以代理多个目标类,代理对象的关联是在运行时决定的
实现方式:
静态代理:通过手动编写代理类来实现,需要为每一个目标类创建一个代理类
动态代理:使用Java的反射机制,在运行时动态生成代理类。Java提供了两种动态代理的方式:基于接口的代理(JDK动态代理)和基于类的代理(CGLIB动态代理)
灵活性:
静态代理:代理类的创建和目标类的绑定是在编译时确定的,因此在程序运行时无法动态改变代理关系。
动态代理:由于代理类是在运行时生成的,因此可以根据需要动态地改变代理关系,更加灵活。
总体而言,静态代理需要手动编写代理类,对于少量目标类的代理是可行的,但当目标类数量较多时会产生大量重复代码。而动态代理通过在运行时动态生成代理类,避免了手动编写代理类的繁琐过程,适用于代理对象较多、代理关系动态变化的情况
JDK动态代理 JDK动态代理是Java中实现动态代理的一种机制,它是Java标准库(java.lang.reflect
包)提供的一种代理方式。JDK动态代理基于接口的代理方式,通过在运行时动态生成代理类来实现代理功能。JDK动态代理使用了Java的反射机制来实现,可以在运行时创建代理对象,无需手动编写代理类
JDK动态代理的核心类是java.lang.reflect.Proxy
,它提供了静态方法newProxyInstance()
来创建代理对象。newProxyInstance()
方法接收三个参数:
ClassLoader
:用于加载动态生成的代理类的类加载器。
Class[] interfaces
:代理类要实现的接口数组,代理对象将实现这些接口。
InvocationHandler
:代理对象的调用处理程序,它定义了代理对象在执行方法时的行为。
以下是一个使用JDK动态代理的简单示例:
定义抽象主题接口(Subject):
1 2 3 4 public interface Subject { void doSomething () ; }
定义真实主题类(RealSubject):
1 2 3 4 5 6 7 public class RealSubject implements Subject { @Override public void doSomething () { System.out.println("RealSubject is doing something..." ); } }
定义代理处理程序(MyInvocationHandler):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;public class MyInvocationHandler implements InvocationHandler { private Object realSubject; public MyInvocationHandler (Object realSubject) { this .realSubject = realSubject; } @Override public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Proxy is doing something before the RealSubject..." ); Object result = method.invoke(realSubject, args); System.out.println("Proxy is doing something after the RealSubject..." ); return result; } }
客户端代码:
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 import java.lang.reflect.Proxy;public class Client { public static void main (String[] args) { Subject realSubject = new RealSubject (); MyInvocationHandler handler = new MyInvocationHandler (realSubject); ClassLoader classLoader = realSubject.getClass().getClassLoader(); Class[] interfaces = realSubject.getClass().getInterfaces() Subject proxy = (Subject) Proxy.newProxyInstance( classLoader, interfaces, handler); proxy.doSomething(); } }
输出结果:
1 2 3 Proxy is doing something before the RealSubject... RealSubject is doing something... Proxy is doing something after the RealSubject...
在上面的示例中,我们通过 Proxy.newProxyInstance()
方法创建了一个代理对象,该代理对象实现了Subject
接口,并在调用方法时通过 MyInvocationHandler
中定义的逻辑来进行增强操作。这样,我们就实现了一个基于JDK动态代理的简单代理功能
JDK动态代理分析 Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)
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 public static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) { Objects.requireNonNull(h); final Class<?>[] intfs = interfaces.clone(); Class<?> cl = getProxyClass0(loader, intfs); try { if (sm != null ) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } 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}); } ... }
最后来到 ProxyClassFactory
的 apply()
方法,代理类就是在这里生成的
CGLib动态代理 CGLib动态代理是另一种实现动态代理的方式,它与JDK动态代理不同,不基于接口,而是对类进行代理。CGLib是一个强大的代码生成库,它能够在运行时扩展Java类和实现代理功能。CGLib动态代理的原理是通过生成目标类的子类来实现代理,因此被代理的类不能是final类,且代理的方法不能是final或static的。两者的区别有以下几点:
Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承);CGLIB能够代理普通类。
Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效;CGLIB 使用ASM框架直接对字节码进行操作,在类的执行过程中比较高效。
CGLib动态代理的核心类是 net.sf.cglib.proxy.Enhancer
,它是CGLib库中的代理增强类,用于生成代理类的实例。使用CGLib动态代理需要依赖CGLib库。
以下是一个使用CGLib动态代理的简单示例:
定义目标类(RealSubject
):
1 2 3 4 5 6 public class RealSubject { public void doSomething () { System.out.println("RealSubject is doing something..." ); } }
定义代理处理程序(MyMethodInterceptor
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept (Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Proxy is doing something before the RealSubject..." ); Object result = proxy.invokeSuper(obj, args); System.out.println("Proxy is doing something after the RealSubject..." ); return result; } }
intercept
方法四个参数的含义如下: obj
: 代理类对象。 method
: 被代理的类中的方法。 args
: 调用方法需要的参数。 proxy
: 生成的代理类对方法的代理引用
用户需要实现MethodInterceptor
接口,实现对方法的拦截。这一点与JDK动态代理中用户需要实现InvocationHandler
接口类似
客户端代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import net.sf.cglib.proxy.Enhancer;public class Client { public static void main (String[] args) { MyMethodInterceptor interceptor = new MyMethodInterceptor (); Enhancer enhancer = new Enhancer (); enhancer.setSuperclass(RealSubject.class); enhancer.setCallback(interceptor); RealSubject proxy = (RealSubject) enhancer.create(); proxy.doSomething(); } }
输出结果:
1 2 3 Proxy is doing something before the RealSubject... RealSubject is doing something... Proxy is doing something after the RealSubject...
在上面的示例中使用CGLib的 Enhancer
类来创建了一个代理对象,该代理对象继承了 RealSubject
类,并在调用方法时通过 MyMethodInterceptor
中定义的逻辑来进行增强操作。这样就实现了一个基于CGLib动态代理的简单代理功能
需要注意的是,CGLib动态代理相比于JDK动态代理的优点在于它可以代理没有实现接口的类,而且在一些场景下由于继承的方式,可以更高效地执行代理。然而,CGLib动态代理也有一些限制,例如无法代理 final
类和 final
方法
CGLib动态代理分析 生成指定类Class对象字节数组 ,CGLib动态代理会选择目标类(被代理类)作为父类,然后生成代理类的字节码——首先创建Enhancer
对象,设置SuperClass
父类(被代理类),然后调用Enhancer
对象的create()
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public Object create () { this .classOnly = false ; this .argumentTypes = null ; return this .createHelper(); }private Object createHelper () { this .preValidate(); Object key = KEY_FACTORY.newInstance(this .superclass != null ? this .superclass.getName() : null , ReflectUtils.getNames(this .interfaces), this .filter == ALL_ZERO ? null : new WeakCacheKey (this .filter), this .callbackTypes, this .useFactory, this .interceptDuringConstruction, this .serialVersionUID); this .currentKey = key; Object result = super .create(key); return result; }
然后到了 Enhance 继承的 AbstractClassGenerator 类中的 create() 方法,这一步就是为了得到动态类的Class对象,之后通过反射 生成具体的类的对象
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 protected Object create (Object key) { try { ClassLoader loader = this .getClassLoader(); Map<ClassLoader, ClassLoaderData> cache = CACHE; ClassLoaderData data = (ClassLoaderData)cache.get(loader); if (data == null ) { Class var5 = AbstractClassGenerator.class; synchronized (AbstractClassGenerator.class) { cache = CACHE; data = (ClassLoaderData)cache.get(loader); if (data == null ) { Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap (cache); data = new ClassLoaderData (loader); newCache.put(loader, data); CACHE = newCache; } } } this .key = key; Object obj = data.get(this , this .getUseCache()); return obj instanceof Class ? this .firstInstance((Class)obj) : this .nextInstance(obj); } catch (Error | RuntimeException var9) { throw var9; } catch (Exception var10) { throw new CodeGenerationException (var10); } }
ClassLoaderData.get() 方法
1 2 3 4 5 6 7 8 9 public Object get (AbstractClassGenerator gen, boolean useCache) { if (!useCache) { return gen.generate(this ); } else { Object cachedValue = this .generatedClasses.get(gen); return gen.unwrapCachedValue(cachedValue); } }
进到 AbstractClassGenerator 的 generate() 方法
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 protected Class generate (ClassLoaderData data) { Class gen; Object save = CURRENT.get(); CURRENT.set(this ); try { ClassLoader classLoader = data.getClassLoader(); if (classLoader == null ) { throw new IllegalStateException ("ClassLoader is null while trying to define class " + getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " + "Please file an issue at cglib's issue tracker." ); } synchronized (classLoader) { String name = generateClassName(data.getUniqueNamePredicate()); data.reserveName(name); this .setClassName(name); } if (attemptLoad) { try { gen = classLoader.loadClass(getClassName()); return gen; } catch (ClassNotFoundException e) { } } byte [] b = strategy.generate(this ); String className = ClassNameReader.getClassName(new ClassReader (b)); ProtectionDomain protectionDomain = getProtectionDomain(); synchronized (classLoader) { gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain, contextClass); } return gen; } catch (RuntimeException | Error ex) { throw ex; } catch (Exception ex) { throw new CodeGenerationException (ex); } finally { CURRENT.set(save); } }
这里第三步的 strategy.generate() 方法是 DefaultGeneratorStrategy 中的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 public class DefaultGeneratorStrategy implements GeneratorStrategy { public static final DefaultGeneratorStrategy INSTANCE = new DefaultGeneratorStrategy (); public DefaultGeneratorStrategy () { } public byte [] generate(ClassGenerator cg) throws Exception { DebuggingClassWriter cw = this .getClassVisitor(); this .transform(cg).generateClass(cw); return this .transform(cw.toByteArray()); } ... }
这里的 getClassVistor
调用了asm的接口,生成了一个 DebuggingClassWriter
对象,这里的cg就是之前的 Enhancer
实例,点进 generateClass()
方法,又回到 Enhance
类:
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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 public void generateClass (ClassVisitor v) throws Exception { Class sc = (superclass == null ) ? Object.class : superclass; if (TypeUtils.isFinal(sc.getModifiers())) throw new IllegalArgumentException ("Cannot subclass final class " + sc.getName()); List constructors = new ArrayList (Arrays.asList(sc.getDeclaredConstructors())); filterConstructors(sc, constructors); List actualMethods = new ArrayList (); List interfaceMethods = new ArrayList (); final Set forcePublic = new HashSet (); getMethods(sc, interfaces, actualMethods, interfaceMethods, forcePublic); List methods = CollectionUtils.transform(actualMethods, new Transformer () { public Object transform (Object value) { Method method = (Method) value; int modifiers = Constants.ACC_FINAL | (method.getModifiers() & ~Constants.ACC_ABSTRACT & ~Constants.ACC_NATIVE & ~Constants.ACC_SYNCHRONIZED); if (forcePublic.contains(MethodWrapper.create(method))) { modifiers = (modifiers & ~Constants.ACC_PROTECTED) | Constants.ACC_PUBLIC; } return ReflectUtils.getMethodInfo(method, modifiers); } }); ClassEmitter e = new ClassEmitter (v); if (currentData == null ) { e.begin_class(Constants.V1_8, Constants.ACC_PUBLIC, getClassName(), Type.getType(sc), (useFactory ? TypeUtils.add(TypeUtils.getTypes(interfaces), FACTORY) : TypeUtils.getTypes(interfaces)), Constants.SOURCE_FILE); } else { e.begin_class(Constants.V1_8, Constants.ACC_PUBLIC, getClassName(), null , new Type []{FACTORY}, Constants.SOURCE_FILE); } List constructorInfo = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance()); e.declare_field(Constants.ACC_PRIVATE, BOUND_FIELD, Type.BOOLEAN_TYPE, null ); e.declare_field(Constants.ACC_PUBLIC | Constants.ACC_STATIC, FACTORY_DATA_FIELD, OBJECT_TYPE, null ); if (!interceptDuringConstruction) { e.declare_field(Constants.ACC_PRIVATE, CONSTRUCTED_FIELD, Type.BOOLEAN_TYPE, null ); } e.declare_field(Constants.PRIVATE_FINAL_STATIC, THREAD_CALLBACKS_FIELD, THREAD_LOCAL, null ); e.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_CALLBACKS_FIELD, CALLBACK_ARRAY, null ); if (serialVersionUID != null ) { e.declare_field(Constants.PRIVATE_FINAL_STATIC, Constants.SUID_FIELD_NAME, Type.LONG_TYPE, serialVersionUID); } for (int i = 0 ; i < callbackTypes.length; i++) { e.declare_field(Constants.ACC_PRIVATE, getCallbackField(i), callbackTypes[i], null ); } e.declare_field(Constants.ACC_PRIVATE | Constants.ACC_STATIC, CALLBACK_FILTER_FIELD, OBJECT_TYPE, null ); if (currentData == null ) { emitMethods(e, methods, actualMethods); emitConstructors(e, constructorInfo); } else { emitDefaultConstructor(e); } emitSetThreadCallbacks(e); emitSetStaticCallbacks(e); emitBindCallbacks(e); if (useFactory || currentData != null ) { int [] keys = getCallbackKeys(); emitNewInstanceCallbacks(e); emitNewInstanceCallback(e); emitNewInstanceMultiarg(e, constructorInfo); emitGetCallback(e, keys); emitSetCallback(e, keys); emitGetCallbacks(e); emitSetCallbacks(e); } e.end_class(); }
回到前面 AbstractClassGenerator#create
方法
1 2 3 4 5 ...if (obj instanceof Class) { return firstInstance((Class) obj); } ...
点进 firstInstance()
方法里,来到 Enhancer#firstInstance
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 protected Object firstInstance (Class type) throws Exception { if (classOnly) { return type; } else { return createUsingReflection(type); } }private Object createUsingReflection (Class type) { setThreadCallbacks(type, callbacks); try { if (argumentTypes != null ) { return ReflectUtils.newInstance(type, argumentTypes, arguments); } else { return ReflectUtils.newInstance(type); } } finally { setThreadCallbacks(type, null ); } }
这里使用了 ReflectUtils
反射工具类中的方法,完成了动态代理对象的生成
反射 动态代理里讲到了反射,在Java中,动态代理主要通过Java反射机制实现,可以在程序运行时动态创建代理对象,无需手动编写代理类
反射 是Java语言中的一种机制,允许程序在运行时动态地获取、检查和操作类的信息以及对象的属性和方法。Java反射API位于java.lang.reflect
包中,它提供了一组类和接口,用于实现反射功能。反射机制为开发者提供了在编译时无法确定的类结构信息,从而实现一些灵活、动态的操作
反射的基础知识包括以下几个关键概念:
Class类 :java.lang.Class
是Java反射机制的核心类,它代表一个Java类的运行时信息。通过Class类,可以获取类的结构信息,如字段、方法、构造函数、父类、实现的接口等。
获取Class对象 :可以通过三种方式来获取一个类的Class对象:
使用Class.forName(String className)
:根据类的全限定名获取Class对象。需要处理ClassNotFoundException
异常。
使用.class
语法:例如,String.class
获取String类的Class对象。
使用Object.getClass()
方法:通过对象的getClass()
方法获取对象所属类的Class对象。
获取类的信息 :通过Class对象的方法,可以获取类的结构信息,例如:
getFields()
:获取类的公共字段。
getMethods()
:获取类的公共方法。
getConstructors()
:获取类的公共构造函数。
getDeclaredFields()
:获取类的所有字段(包括私有字段)。
getDeclaredMethods()
:获取类的所有方法(包括私有方法)。
创建对象 :通过Class对象的newInstance()
方法,可以创建类的实例。
访问字段和方法 :通过反射可以动态地访问和修改类的字段值和调用类的方法。
反射机制的优点在于它提供了动态性和灵活性,使得开发者能够在运行时动态地获取和操作类的信息,避免了在编译时固定的限制。然而,由于反射涉及到动态生成代码和动态检查类型,其性能可能较低,不宜频繁地使用,最好在需要时再使用
反射原理 反射(Reflection )和类加载(Class Loading )是Java中两个重要的概念,它们之间有一定的关系。反射是Java语言提供的一种机制,允许在运行时动态地获取、检查和操作类的信息 ,而类加载 是Java虚拟机在将类字节码加载到内存并生成类对象的过程
类加载是反射的基础 ,反射的操作都是基于类加载完成的。在使用反射之前,需要先将类加载到内存中,然后通过类的Class对象来进行反射操作,java类的执行需要经历以下过程:
编译 :java文件编译后生成 .class
字节码文件
类加载 :
Java的反射就是利用上面第二步加载到jvm中的 .class
文件来进行操作。具体来说,在Java虚拟机对类进行加载和连接的过程中,反射主要在解析阶段进行 ,其中解析的主要目标是将类、字段、方法的符号引用转换为直接引用,建立类之间的关联关系
以下是一个使用反射调用方法的简单示例:
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 import java.lang.reflect.Method;public class MyClass { public void sayHello () { System.out.println("Hello, World!" ); } public int add (int a, int b) { return a + b; } public static void main (String[] args) throws Exception { Class<?> clazz = MyClass.class; Method sayHelloMethod = clazz.getMethod("sayHello" ); sayHelloMethod.invoke(clazz.newInstance()); Method addMethod = clazz.getMethod("add" , int .class, int .class); int result = (int ) addMethod.invoke(clazz.newInstance(), 10 , 20 ); System.out.println("Result: " + result); } }
输出结果:
1 2 Hello , World!Result : 30
需要注意的是,在使用反射调用方法时,要确保方法的名称、参数类型和调用的方法是一致的,否则会抛出 NoSuchMethodException
或 IllegalArgumentException
异常
接下来主要解析一下获取 Method
对象和 Method.invoke()
方法
获取 Method 对象 在Java的反射机制中,可以通过Class
对象获取Method
对象,Method
对象代表了类中的方法。通过Method
对象可以在运行时动态地调用类的方法。Java反射中获取Method
对象的方法主要有以下两个:
getMethod(String name, Class<?>... parameterTypes)
:
用于获取类的公共方法(包括从父类继承的公共方法)。
参数name
是要获取的方法的名称。
参数parameterTypes
是方法的参数类型数组,用于指定方法的参数类型。如果方法有参数,需要将参数类型以Class对象的形式传递进去。如果方法没有参数,可以不传递该参数。
返回值是一个Method对象,表示与指定名称和参数类型匹配的公共方法。如果未找到对应的方法,则抛出NoSuchMethodException
异常。
getDeclaredMethod(String name, Class<?>... parameterTypes)
:
用于获取类自身声明的方法(包括私有方法)。
参数name
是要获取的方法的名称。
参数parameterTypes
是方法的参数类型数组,用于指定方法的参数类型。如果方法有参数,需要将参数类型以Class对象的形式传递进去。如果方法没有参数,可以不传递该参数。
返回值是一个Method对象,表示与指定名称和参数类型匹配的类自身声明的方法。如果未找到对应的方法,则抛出NoSuchMethodException
异常。
上述两个方法都有获取复数个的方法,区别就是方法名后有 “s ” 后缀
注意事项 :
当获取私有方法时,使用getDeclaredMethod()
方法;当获取公共方法时,使用getMethod()
方法。
如果获取的方法是私有方法,需要通过setAccessible(true)
方法将其设置为可访问,以允许访问私有方法。
其实不管是getMethod
还是getDeclaredMethod
,底层都调用了同一个方法:privateGetDeclaredMethods
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 private Method privateGetMethodRecursive (String name, Class<?>[] parameterTypes, boolean includeStaticMethods, MethodArray allInterfaceCandidates) { Method res; if ((res = searchMethods(privateGetDeclaredMethods(true ), name, parameterTypes)) != null ) { if (includeStaticMethods || !Modifier.isStatic(res.getModifiers())) return res; } if (!isInterface()) { Class<? super T> c = getSuperclass(); if (c != null ) { if ((res = c.getMethod0(name, parameterTypes, true )) != null ) { return res; } } } Class<?>[] interfaces = getInterfaces(); for (Class<?> c : interfaces) if ((res = c.getMethod0(name, parameterTypes, false )) != null ) allInterfaceCandidates.add(res); return null ; }
然后在看看 searchMethods()
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 private static Method searchMethods (Method[] methods, String name, Class<?>[] parameterTypes) { Method res = null ; String internedName = name.intern(); for (int i = 0 ; i < methods.length; i++) { Method m = methods[i]; if (m.getName() == internedName && arrayContentsEq(parameterTypes, m.getParameterTypes()) && (res == null || res.getReturnType().isAssignableFrom(m.getReturnType()))) res = m; } return (res == null ? res : getReflectionFactory().copyMethod(res)); }
其中循环了 Method[] methods 这个数组,而这个参数是由 privateGetDeclaredMethods(boolean publicOnly ) 获得的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private Method[] privateGetDeclaredMethods(boolean publicOnly) { checkInitted(); Method[] res; ReflectionData<T> rd = reflectionData(); if (rd != null ) { res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods; if (res != null ) return res; } res = Reflection.filterMethods(this , getDeclaredMethods0(publicOnly)); if (rd != null ) { if (publicOnly) { rd.declaredPublicMethods = res; } else { rd.declaredMethods = res; } } return res; }
其中的 ReflectionData<T>
是类Class
的静态内部类,<T>
表示泛型,为具体的类对象。该缓存数据结构中存储了类的所有信息。redefinedCount
是类的重定义次数,可以理解为缓存的版本号,每一个类对象理论上都会有(被垃圾回收或从来没被加载过就没没有)一个ReflectionData<T>
的缓存,通过 reflectionData()
获取:
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 private ReflectionData<T> reflectionData () { SoftReference<ReflectionData<T>> reflectionData = this .reflectionData; int classRedefinedCount = this .classRedefinedCount; ReflectionData<T> rd; if (useCaches && reflectionData != null && (rd = reflectionData.get()) != null && rd.redefinedCount == classRedefinedCount) { return rd; } return newReflectionData(reflectionData, classRedefinedCount); }private ReflectionData<T> newReflectionData (SoftReference<ReflectionData<T>> oldReflectionData, int classRedefinedCount) { if (!useCaches) return null ; while (true ) { ReflectionData<T> rd = new ReflectionData <>(classRedefinedCount); if (Atomic.casReflectionData(this , oldReflectionData, new SoftReference <>(rd))) { return rd; } oldReflectionData = this .reflectionData; classRedefinedCount = this .classRedefinedCount; if (oldReflectionData != null && (rd = oldReflectionData.get()) != null && rd.redefinedCount == classRedefinedCount) { return rd; } } }
Method.invoke() 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public Object invoke (Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; if (ma == null ) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args); }
这里会获取 MethodAccessor
,这个在之前 searchMethods()
最后会调用 Method#copy
会给 Method
的 methodAccessor
赋值,如果为空则去创建 MethodAccessor
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 private MethodAccessor acquireMethodAccessor () { MethodAccessor tmp = null ; if (root != null ) tmp = root.getMethodAccessor(); if (tmp != null ) { methodAccessor = tmp; } else { tmp = reflectionFactory.newMethodAccessor(this ); setMethodAccessor(tmp); } return tmp; }public MethodAccessor newMethodAccessor (Method var1) { checkInitted(); if (noInflation && !ReflectUtil.isVMAnonymousClass(var1.getDeclaringClass())) { return (new MethodAccessorGenerator ()).generateMethod(var1.getDeclaringClass(), var1.getName(), var1.getParameterTypes(), var1.getReturnType(), var1.getExceptionTypes(), var1.getModifiers()); } else { NativeMethodAccessorImpl var2 = new NativeMethodAccessorImpl (var1); DelegatingMethodAccessorImpl var3 = new DelegatingMethodAccessorImpl (var2); var2.setParent(var3); return var3; } }
这里会先查找 root 的 MethodAccessor
,这里的 root 在上面 Method#copy
中设置过。如果还是没有找到,就去创建 MethodAccessor
在 newMethodAccessor()
方法里可以看到一共有三种 MethodAccessor
:
MethodAccessorImpl
NativeMethodAccessorImpl
DelegatingMethodAccessorImpl
采用哪种 MethodAccessor
根据 noInflation
进行判断,noInflation
默认值为 false
,只有指定了 sun.reflect.noInflation
属性为 true
,才会采用 MethodAccessorImpl
,所以默认会调用 NativeMethodAccessorImpl
MethodAccessorImpl
是通过动态生成字节码来进行方法调用的,是 Java 版本的 MethodAccessor
DelegatingMethodAccessorImpl
就是单纯的代理,真正的实现还是 NativeMethodAccessorImpl
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class DelegatingMethodAccessorImpl extends MethodAccessorImpl { private MethodAccessorImpl delegate; DelegatingMethodAccessorImpl(MethodAccessorImpl delegate) { setDelegate(delegate); } public Object invoke (Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { return delegate.invoke(obj, args); } void setDelegate (MethodAccessorImpl delegate) { this .delegate = delegate; } }
NativeMethodAccessorImpl
是 Native 版本的 MethodAccessor
实现。
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 class NativeMethodAccessorImpl extends MethodAccessorImpl { public Object invoke (Object obj, Object[] args) throws IllegalArgumentException, InvocationTargetException { if (++numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { MethodAccessorImpl acc = (MethodAccessorImpl) new MethodAccessorGenerator (). generateMethod(method.getDeclaringClass(), method.getName(), method.getParameterTypes(), method.getReturnType(), method.getExceptionTypes(), method.getModifiers()); parent.setDelegate(acc); } return invoke0(method, obj, args); } private static native Object invoke0 (Method m, Object obj, Object[] args) ; }
在 NativeMethodAccessorImpl
的实现中,我们可以看到,有一个 numInvocations
阀值控制,numInvocations
表示调用次数。如果 numInvocations
大于 15(默认阀值是 15),那么就使用 Java 版本的 MethodAccessorImpl
。 为什么采用这个策略呢,可以 JDK 中的注释:
1 2 3 4 5 6 7 8 9 10 11 12 private static boolean noInflation = false ;
比起通过本地代码进行的首次调用,方法和构造函数的首次调用要快3-4倍(虽然后续的调用已经经过基准测试,速度可以达到原来的20倍以上)。然而,这个过程会增加某些密集使用反射(但每个类仅一次)来引导自身的应用程序的启动时间。为了避免这种性能损耗,我们在方法和构造函数的前几次调用中重用现有的JVM入口点,然后切换到基于字节码的实现
Method.invoke()
的最后,调用 MethodAccessor#invoke
实现方法的调用
AOP 说完了前置知识,终于可以开始正题了
在传统的面向对象编程中,系统的功能通常以对象的形式组织,但某些功能可能会散布在整个应用程序中,而不局限于单个对象或类。这些功能被称为横切关注点,如日志记录、安全性、事务处理等。AOP的目标就是通过把这些横切关注点从核心业务逻辑中分离出来,形成独立的模块,并通过特定的方式将其织入到应用程序中。通俗一点表达就是:AOP 要实现的是在我们原来写的代码的基础上,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理
作为 Java 开发者都很熟悉 AspectJ 这个词,甚至于在提到 AOP 的时候,想到的往往就是 AspectJ。这里简单的将 AspectJ 和 Spring AOP 做个对比:
Spring AOP:
它基于动态代理来实现。默认来说,如果使用接口,它会采用 JDK 提供的动态代理实现,如果没有接口,则会使用 CGLib 实现
Spring 3.2 以后,spring-core 直接就把 CGLIB 和 ASM 的源码包括进来了,所以平时开发时不需要显式引入这两个依赖
如果你是 web 开发者,有些时候可能需要的是一个 Filter 或一个 Interceptor,而不一定是 AOP
Spring AOP 只能作用于 Spring 容器中的 Bean,它是使用纯粹的 Java 代码实现的,只能作用于 bean 的方法
Spring 提供了 AspectJ 的支持,但一般来说只用 Spring AOP 就够
很多人会对比 Spring AOP 和 AspectJ 的性能,Spring AOP 是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好
AspectJ:
AspectJ 出身也是名门,来自于 Eclipse 基金会,https://www.eclipse.org/aspectj
属于静态织入,它是通过修改代码来实现的,它的织入时机可以是:
Compile-time weaving :编译期织入,如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
Post-compile weaving :也就是已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。
Load-time weaving :指的是在加载类的时候进行织入,要实现这个时期的织入,有几种常见的方法。1、自定义类加载器来干这个,这个应该是最容易想到的办法,在被织入类加载到 JVM 前去对它进行加载,这样就可以在加载的时候定义行为了。2、在 JVM 启动的时候指定 AspectJ 提供的 agent:-javaagent:xxx/xxx/aspectjweaver.jar
。
AspectJ 能干很多 Spring AOP 干不了的事情,它是 AOP 编程的完全解决方案 。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。
因为 AspectJ 在实际代码运行前完成了织入,所以大家会说它生成的类是没有额外运行时开销的
AOP的关键概念:
切面(Aspect):切面是横切关注点的抽象表示,它包含了与某个横切关注点相关的一组通用功能。比如,日志记录是一个切面,它可以包含日志输出的功能
连接点(Join Point):连接点是应用程序中可能被切面影响的点。在Java中,连接点通常表示为方法的执行或异常的抛出
通知(Advice):通知是切面在特定连接点上执行的具体动作。通知包括前置通知(Before)、后置通知(After)、返回通知(After Returning)、异常通知(After Throwing)和环绕通知(Around)等
切点(Pointcut):切点是一组连接点的集合,它定义了切面在哪些连接点上起作用。切点使用表达式来匹配连接点,从而确定在哪些连接点上应用通知
引入(Introduction):引入允许在不修改代码的情况下向现有类添加新的方法和属性
织入(Weaving):织入是将切面应用到目标对象并创建新的代理对象的过程。织入可以在编译时、类加载时或运行时进行
Spring AOP 这里介绍的 Spring AOP 是纯的 Spring 代码,和 AspectJ 没什么关系,但是 Spring 延用了 AspectJ 中的概念,包括使用了 AspectJ 提供的 jar 包中的注解,但是不依赖于其实现功能
后面介绍的如 @Aspect、@Pointcut、@Before、@After 等注解都是来自于 AspectJ,但是功能的实现是纯 Spring AOP 自己实现的
在 Spring 的容器中,我们面向的对象是一个个的 bean 实例。我们可以简单理解 bean 是 BeanDefinition 的实例,Spring 会根据 BeanDefinition 中的信息为我们生产合适的 bean 实例出来
当我们需要使用 bean 的时候,通过 IOC 容器的 getBean()
方法从容器中获取 bean 实例,只不过大部分的场景下,我们都用了依赖注入,所以很少手动调用 getBean()
方法
Spring AOP 的原理很简单,就是动态代理 ,它和 AspectJ 不一样,AspectJ 是直接修改掉你的字节码
代理模式很简单,接口 + 真实实现类 + 代理类 ,其中 真实实现类 和 代理类 都要实现接口,实例化的时候要使用代理类。所以,Spring AOP 需要做的是生成这么一个代理类 ,然后替换掉 真实实现类来对外提供服务
替换 这个操作在 Spring IOC 容器中非常容易实现,就是在 getBean()
的时候返回的实际上是代理类的实例,而这个代理类我们自己没写代码,它是 Spring 采用 JDK Proxy 或 CGLIB 动态生成的
Spring 2.0 @AspectJ 配置 在 Spring 2.0 之后引入了 @AspectJ
和 Schema-based
的两种配置方式,这里仅介绍 AspectJ
注解的方式。首先,我们需要依赖 aspectjweaver.jar
这个包,这个包来自于 AspectJ
:
并不是说基于 AspectJ 实现的,而仅仅是使用了 AspectJ 中的概念,包括使用的注解也是直接来自于 AspectJ 的包
1 2 3 4 5 <dependency > <groupId > org.aspectj</groupId > <artifactId > aspectjweaver</artifactId > <version > 1.8.11</version > </dependency >
如果是使用 Spring Boot 的话,添加以下依赖即可:
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-aop</artifactId > </dependency >
首先,我们需要开启 @AspectJ
的注解配置方式:
使用 @EnableAspectJAutoProxy
1 2 3 4 5 @Configuration @EnableAspectJAutoProxy public class AppConfig { }
一旦开启了上面的配置,那么所有使用 @Aspect 注解的 bean 都会被 Spring 当做用来实现 AOP 的配置类 ,我们称之为一个 Aspect
注意,@Aspect
注解要作用在 bean 上面,不管是使用 @Component
等注解方式,还是在 xml 中配置 bean,首先它需要是一个 bean
有些时候并不需要 加这个注解就能使AOP生效,原因是依赖中直接或者间接的引入了 spring-boot-autoconfigure
,这是自动装配的依赖,也就是会读取其下的 spring.factories
文件,在该文件中有下面的配置
1 2 3 4 org.springframework.boot.autoconfigure.EnableAutoConfiguration =\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.**AopAutoConfiguration**
则会加载 AopAutoConfiguration
类
1 2 3 4 5 6 @Configuration(proxyBeanMethods = false) @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) public class AopAutoConfiguration { .... }
默认等同于 @EnableAspectJAutoProxy
创建一个接口和实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 public interface UserService { void addUser (String username) ; }public class UserServiceImpl implements UserService { @Override public void addUser (String username) { System.out.println("User added: " + username); } }
创建一个切面类,用于添加横切逻辑,并定义Pointcut 表达式:
1 2 3 4 5 6 7 8 9 10 11 12 13 import org.aspectj.lang.annotation.After;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.springframework.stereotype.Component;@Aspect @Component public class LoggingAspect { @Pointcut("execution(* com.example.UserService.*(..))") public void userServiceMethods () {} }
我们看到,@Pointcut
中使用了 execution 来正则匹配方法签名,这也是最常用的,除了 execution,我们再看看其他的几个比较常用的匹配方式:
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 execution(public * *(..)) execution(* set*(..)) execution(* com.xyz.service.AccountService.*(..)) execution(* com.xyz.service.*.*(..)) execution(* com.xyz.service..*.*(..)) within(com.xyz.service.*) within(com.xyz.service..*)this (com.xyz.service.AccountService) target(com.xyz.service.AccountService) args(java.io.Serializable) @target (org.springframework.transaction.annotation.Transactional)@within (org.springframework.transaction.annotation.Transactional) @annotation (org.springframework.transaction.annotation.Transactional) @args (com.xyz.security.Classified) bean(tradeService) bean(*Service)
此外Spring 支持如下三个逻辑运算符来组合切入点表达式
1 2 3 &&:要求连接点同时匹配两个切入点表达式 ||:要求连接点匹配任意个切入点表达式 !::要求连接点不匹配指定的切入点表达式
Spring AOP 用户可能会经常使用 execution 切入点指示符。执行表达式的格式如下:
1 execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws -pattern?)
ret-type-pattern 返回类型模式, name-pattern名字模式和param-pattern参数模式是必选的, 其它部分都是可选的。返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是*
,它代表了匹配任意的返回类型 。
declaring-type-pattern, 一个全限定的类型名将只会匹配返回给定类型的方法。
name-pattern 名字模式匹配的是方法名。 你可以使用*
通配符作为所有或者部分命名模式。
param-pattern 参数模式稍微有点复杂:()匹配了一个不接受任何参数的方法, 而(..)匹配了一个接受任意数量参数的方法(零或者更多)。 模式()匹配了一个接受一个任何类型的参数的方法。 模式( ,String)匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型
上面匹配中,通常 “.” 代表一个包名,”..” 代表包及其子包,方法参数任意匹配使用两个点 “..”
配置 Advice
1 2 3 4 5 6 7 8 9 @Aspect public class AdviceExample { @After("com.javadoop.aop.LoggingAspect.userServiceMethods()") public void logAfterExecution () { System.out.println("Method execution completed." ); } }
创建一个简单的Main类来测试:
1 2 3 4 5 6 7 8 9 10 11 import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main { public static void main (String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext ("applicationContext.xml" ); UserService userService = (UserService) context.getBean("userService" ); userService.addUser("John Doe" ); } }
在运行Main类时,你将看到类似以下输出:
1 2 User added: John DoeMethod execution completed .
这表明 addUser
方法执行后,切面中定义的 logAfterExecution
方法被调用。使用 Pointcut
,你可以更细粒度地控制切入点,而不是直接在特定方法上定义切面逻辑
如果 Advice
方法需要获取入参,Spring 提供了非常简单的获取入参的方法,使用 org.aspectj.lang.JoinPoint
作为 Advice
的第一个参数即可,如:
1 2 3 4 @Before("com.javadoop.aop.LoggingAspect.userServiceMethods()") public void logArgs (JoinPoint joinPoint) { System.out.println("方法执行前,打印入参:" + Arrays.toString(joinPoint.getArgs())); }
注意 org.aspectj.lang.JoinPoint
的使用方法:
必须放置在第一个参数上
如果是 @Around,我们通常会使用其子类 ProceedingJoinPoint
,因为它有 procceed()
/ procceed(args[])
方法。
AOP的原理 所以理解Spring AOP的初始化必须要先理解Spring IOC的初始化
基于注解的切面代理创建 这里直接从之前说到的 @EnableAspectJAutoProxy
切入,它 @import 了 AspectJAutoProxyRegistrar.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions ( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); ... }
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)
这个方法点进去
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 public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary (BeanDefinitionRegistry registry) { return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null ); }public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary ( BeanDefinitionRegistry registry, @Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source); }private static BeanDefinition registerOrEscalateApcAsRequired ( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null" ); if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null ; } RootBeanDefinition beanDefinition = new RootBeanDefinition (cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order" , Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition; }
总结下来就是注册了一个名为 org.springframework.aop.config.internalAutoProxyCreator
的 BeanDefinition
,我们称之为代理创建器(ProxyCreator )。这里使用的默认实现为 AnnotationAwareAspectJAutoProxyCreator.class
类,如果存在多个候选实现,则选择优先级最高的进行注册
然后是 AspectJAutoProxyRegistrar#registerBeanDefinitions
后面省略的部分是:
1 2 3 4 5 6 7 8 if (enableAspectJAutoProxy != null ) { if (enableAspectJAutoProxy.getBoolean("proxyTargetClass" )) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); } if (enableAspectJAutoProxy.getBoolean("exposeProxy" )) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); } }
这里配置的 proxy-target-class
和 expose-proxy
属性添加到对应 BeanDefinition 的属性列表中
这是 AnnotationAwareAspectJAutoProxyCreator
的继承关系图:
看得出它实现了两类接口:BeanPostProcessor
和 Aware
BeanPostProcessor
接口我们知道在容器启动过程中会在初始化 bean 实例的前后分别调用 BeanPostProcessor
中定义的 postProcessBeforeInitialization()
和 postProcessAfterInitialization()
两个方法。针对这两个方法的实现主要位于继承链的 AbstractAutoProxyCreator
类中,并且主要是 实现了 BeanPostProcessor#postProcessAfterInitialization
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 @Override public Object postProcessAfterInitialization (@Nullable Object bean, String beanName) { if (bean != null ) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this .earlyProxyReferences.remove(cacheKey) != bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }
该方法的核心在于调用 AbstractAutoProxyCreator#wrapIfNecessary
方法,尝试基于 AOP 配置对当前 bean 进行增强,并返回增强后的代理对象。方法 AbstractAutoProxyCreator#wrapIfNecessary
的实现如下:
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 protected Object wrapIfNecessary (Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this .targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this .advisedBeans.get(cacheKey))) { return bean; } if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) { this .advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } 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; }
上述方法主要的工作是对 bean 实例进行筛选,过滤掉那些已经增强过的、支持 AOP 基础运行的,以及指定不需要被代理的 bean 实例。对于剩下的 bean 实例来说,首先会调用 AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
方法获取适用于当前 bean 的增强器(Advisor ),并基于这些增强器调用 AbstractAutoProxyCreator#createProxy
方法为当前 bean 创建增强后的代理对象
筛选适用于 bean 的增强器 首先来看一下筛选适用于当前 bean 的合格增强器的过程,实现位于 AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 protected Object[] getAdvicesAndAdvisorsForBean( Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) { List<Advisor> advisors = this .findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); }protected List<Advisor> findEligibleAdvisors (Class<?> beanClass, String beanName) { List<Advisor> candidateAdvisors = this .findCandidateAdvisors(); List<Advisor> eligibleAdvisors = this .findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); this .extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors = this .sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }
整个方法的执行流程很简单,获取所有的候选增强器,并从中找出适用于当前 bean 的增强器。首先来看获取所有候选增强器的过程,实现位于 AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors
方法中:
1 2 3 4 5 6 7 8 9 protected List<Advisor> findCandidateAdvisors () { List<Advisor> advisors = super .findCandidateAdvisors(); if (this .aspectJAdvisorsBuilder != null ) { advisors.addAll(this .aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }
方法首先调用了父类的实现,这主要是为了兼容父类查找候选增强器的规则,例如我们的示例中使用的是注解方式定义的增强,但是父类却是基于 XML 配置的方式查找增强器,这里的兼容能够让我们在以注解方式编程时兼容其它以 XML 配置的方式定义的增强。下面还是将主要精力放在解析注解式增强定义上,该过程位于 BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors
方法中。不过该方法实现比较冗长,但是逻辑却很清晰,所以这里主要概括一下其执行流程:
获取所有类型 bean 实例对应的 beanName 集合;
过滤不是切面类型的 bean 对应的 beanName,即没有被 @Aspect
注解,或包含以 ajc$
开头的字段,同时支持覆盖 BeanFactoryAspectJAdvisorsBuilder#isEligibleBean
方法扩展过滤规则;
对于切面 bean 类型,获取 bean 中定义的所有切点,并为每个切点生成对应的增强器;
缓存解析得到的增强器,避免重复解析。
上述流程中我们重点看一下过程 3,实现位于 ReflectiveAspectJAdvisorFactory#getAdvisors
方法中:
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 public List<Advisor> getAdvisors (MetadataAwareAspectInstanceFactory aspectInstanceFactory) { Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName(); this .validate(aspectClass); MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator (aspectInstanceFactory); List<Advisor> advisors = new ArrayList <>(); for (Method method : this .getAdvisorMethods(aspectClass)) { Advisor advisor = this .getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName); if (advisor != null ) { advisors.add(advisor); } } if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor (lazySingletonAspectInstanceFactory); advisors.add(0 , instantiationAdvisor); } for (Field field : aspectClass.getDeclaredFields()) { Advisor advisor = this .getDeclareParentsAdvisor(field); if (advisor != null ) { advisors.add(advisor); } } return advisors; }
上述实现的整体执行流程如代码注释。拿到一个切面定义,Spring 首先会遍历获取切面中的增强方法,即被 @Around
、@Before
、@After
、@AfterReturning
,以及 @AfterThrowing
注解的方法,并调用 ReflectiveAspectJAdvisorFactory#getAdvisor
方法为每一个增强方法生成对应的增强器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public Advisor getAdvisor (Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrderInAspect, String aspectName) { this .validate(aspectInstanceFactory.getAspectMetadata().getAspectClass()); AspectJExpressionPointcut expressionPointcut = this .getPointcut( candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass()); if (expressionPointcut == null ) { return null ; } return new InstantiationModelAwarePointcutAdvisorImpl ( expressionPointcut, candidateAdviceMethod, this , aspectInstanceFactory, declarationOrderInAspect, aspectName); }
上述实现首先对当前切面定义执行合法性校验,如果切面配置合法则获取目标方法上的切点注解定义,并封装成 AspectJExpressionPointcut 对象。该过程位于 ReflectiveAspectJAdvisorFactory#getPointcut
方法中,实现比较简单。
拿到切点注解定义之后,方法会依据切点的配置信息使用 InstantiationModelAwarePointcutAdvisorImpl 实现类创建对应的增强器。类 InstantiationModelAwarePointcutAdvisorImpl 的实例化过程除了初始化了一些基本属性之外,主要是调用了 InstantiationModelAwarePointcutAdvisorImpl#instantiateAdvice
方法,依据增强类型对增强器实施相应的初始化操作:
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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 private Advice instantiateAdvice (AspectJExpressionPointcut pointcut) { Advice advice = this .aspectJAdvisorFactory.getAdvice( this .aspectJAdviceMethod, pointcut, this .aspectInstanceFactory, this .declarationOrder, this .aspectName); return (advice != null ? advice : EMPTY_ADVICE); }public Advice getAdvice (Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); this .validate(candidateAspectClass); AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null ) { return null ; } if (!this .isAspect(candidateAspectClass)) { throw new AopConfigException ("Advice must be declared inside an aspect type: " + "Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]" ); } AbstractAspectJAdvice springAdvice; switch (aspectJAnnotation.getAnnotationType()) { case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'" ); } return null ; case AtAround: springAdvice = new AspectJAroundAdvice (candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break ; case AtBefore: springAdvice = new AspectJMethodBeforeAdvice (candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break ; case AtAfter: springAdvice = new AspectJAfterAdvice (candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break ; case AtAfterReturning: springAdvice = new AspectJAfterReturningAdvice (candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break ; case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice ( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break ; default : throw new UnsupportedOperationException ("Unsupported advice type on method: " + candidateAdviceMethod); } springAdvice.setAspectName(aspectName); springAdvice.setDeclarationOrder(declarationOrder); String[] argNames = this .parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames != null ) { springAdvice.setArgumentNamesFromStringArray(argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; }
方法的整体执行流程如代码注释,逻辑比较清晰,Spring 会依据具体的增强注解类型,选择相应的增强类对切点定义进行封装。这里我们以 @Before
为例说明一下增强的执行流程,AspectJMethodBeforeAdvice 增强类关联注册的处理器是 MethodBeforeAdviceInterceptor,当我们调用一个被前置增强的目标方法时,MethodBeforeAdviceInterceptor#invoke
方法会被触发:
1 2 3 4 5 6 public Object invoke (MethodInvocation mi) throws Throwable { this .advice.before(mi.getMethod(), mi.getArguments(), mi.getThis()); return mi.proceed(); }
这里执行的增强方法就对应着 AspectJMethodBeforeAdvice#before
方法,该方法会依据切点配置将相应的参数绑定传递给我们自定义的增强方法,并最终通过反射调用触发执行。
上面分析了普通方法级别增强的处理过程,对于另外一类增强(引介增强),方法 ReflectiveAspectJAdvisorFactory#getAdvisors
则使用专门的 DeclareParentsAdvisor 类创建对应的增强器:
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 for (Field field : aspectClass.getDeclaredFields()) { Advisor advisor = this .getDeclareParentsAdvisor(field); if (advisor != null ) { advisors.add(advisor); } }private Advisor getDeclareParentsAdvisor (Field introductionField) { DeclareParents declareParents = introductionField.getAnnotation(DeclareParents.class); if (declareParents == null ) { return null ; } if (DeclareParents.class == declareParents.defaultImpl()) { throw new IllegalStateException ("'defaultImpl' attribute must be set on DeclareParents" ); } return new DeclareParentsAdvisor ( introductionField.getType(), declareParents.value(), declareParents.defaultImpl()); }
对于引介增强来说,Spring 会注入 DelegatePerTargetObjectIntroductionInterceptor 处理器对其进行专门的处理,思想上与前面分析前置增强大同小异,这里不再展开。
继续回到 AbstractAdvisorAutoProxyCreator#findEligibleAdvisors
方法,上面的过程我们分析了获取所有类型增强器的过程,但是这些增强器不一定都适用于当前 bean 实例,我们需要依据切点配置信息对其进行筛选。这一过程位于 AbstractAdvisorAutoProxyCreator#findAdvisorsThatCanApply
方法中:
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 protected List<Advisor> findAdvisorsThatCanApply ( List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null ); } }public static List<Advisor> findAdvisorsThatCanApply (List<Advisor> candidateAdvisors, Class<?> clazz) { if (candidateAdvisors.isEmpty()) { return candidateAdvisors; } List<Advisor> eligibleAdvisors = new ArrayList <>(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) { eligibleAdvisors.add(candidate); } } boolean hasIntroductions = !eligibleAdvisors.isEmpty(); for (Advisor candidate : candidateAdvisors) { if (candidate instanceof IntroductionAdvisor) { continue ; } if (canApply(candidate, clazz, hasIntroductions)) { eligibleAdvisors.add(candidate); } } return eligibleAdvisors; }
方法首先会使用类过滤器(ClassFilter)筛选引介增强器,除了我们手动注册的类过滤器外,这里默认还会使用 TypePatternClassFilter 类过滤器执行过滤操作。然后,方法会过滤筛选其它类型的增强器,这里除了使用类过滤器外,考虑方法级别增强的定义形式,还会使用方法匹配器(MethodMatcher)进行筛选。如果增强器适用于当前 bean 类型,则将其加入到集合中用于下一步为当前 bean 创建增强代理对象。如果没有任何一个增强器适用于当前 bean 类型,则方法 AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean
最终会返回值为 null 的 DO_NOT_PROXY
数组对象,表示当前 bean 不需要被增强。
为 bean 创建增强代理对象 完成了对于当前 bean 增强器的筛选,接下来我们继续回到 AbstractAutoProxyCreator#wrapIfNecessary
方法,看一下基于前面筛选出的增强器为当前 bean 创建增强代理对象的过程,实现位于 AbstractAutoProxyCreator#createProxy
方法中:
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 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 (this .shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true ); } else { this .evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors = this .buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); this .customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this .freezeProxy); if (this .advisorsPreFiltered()) { proxyFactory.setPreFiltered(true ); } return proxyFactory.getProxy(this .getProxyClassLoader()); }
方法的执行流程如代码注释。下面我们主要分析将拦截器封装成 Advisor 对象的过程,以及基于 ProxyFactory 创建增强代理对象的过程。
Spring 定义了非常多的拦截器、增强器,以及增强方法等,这里通过 AbstractAutoProxyCreator#buildAdvisors
方法统一将他们封装成 Advisor 对象,从而简化代理的创建过程。封装的核心步骤由 DefaultAdvisorAdapterRegistry#wrap
方法实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public Advisor wrap (Object adviceObject) throws UnknownAdviceTypeException { if (adviceObject instanceof Advisor) { return (Advisor) adviceObject; } if (!(adviceObject instanceof Advice)) { throw new UnknownAdviceTypeException (adviceObject); } Advice advice = (Advice) adviceObject; if (advice instanceof MethodInterceptor) { return new DefaultPointcutAdvisor (advice); } for (AdvisorAdapter adapter : this .adapters) { if (adapter.supportsAdvice(advice)) { return new DefaultPointcutAdvisor (advice); } } throw new UnknownAdviceTypeException (advice); }
接下来我们重点分析一下通过代理工厂 ProxyFactory 创建增强代理对象的过程,实现位于 ProxyFactory#getProxy
方法中:
1 2 3 4 public Object getProxy (@Nullable ClassLoader classLoader) { return this .createAopProxy() .getProxy(classLoader); }
该方法的执行过程可以拆分成两个步骤:
创建 AOP 代理,Spring 默认提供了两种 AOP 代理实现,即 java 原生代理和 CGLib 代理;
基于 AOP 代理创建目标类的增强代理对象。
我们首先来看一下步骤 1 的实现,位于 ProxyCreatorSupport#createAopProxy
方法中:
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 protected final synchronized AopProxy createAopProxy () { if (!this .active) { this .activate(); } return this .getAopProxyFactory().createAopProxy(this ); }public AopProxy createAopProxy (AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || this .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." ); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy (config); } return new ObjenesisCglibAopProxy (config); } else { return new JdkDynamicAopProxy (config); } }
这部分代码清晰说明了 Spring 在生成代理对象时如何在 java 原生代理和 CGLib 代理之间进行选择,可以概括如下:
如果目标类实现了接口,则 Spring 默认会使用 java 原生代理。
如果目标类未实现接口,则 Spring 会使用 CGLib 生成代理。
如果目标类实现了接口,但是在配置时指定了 proxy-target-class=true
,则使用 CGLib 生成代理。
下面分别对基于 java 原生代理和 CGLib 代理生成增强代理对象的过程进行分析。
基于 Java 原生代理创建增强代理对象 首先来看一下基于 Java 原生代理生成增强代理对象的过程,位于 JdkDynamicAopProxy
类中。Java 原生代理要求代理类实现 InvocationHandler
接口,并在 InvocationHandler#invoke
方法中实现代理增强逻辑。JdkDynamicAopProxy
正好实现了该接口,对应的 JdkDynamicAopProxy#invoke
方法实现如下:
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 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 public Object invoke (Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null ; boolean setProxyContext = false ; TargetSource targetSource = this .advised.targetSource; Object target = null ; try { if (!this .equalsDefined && AopUtils.isEqualsMethod(method)) { return this .equals(args[0 ]); } else if (!this .hashCodeDefined && AopUtils.isHashCodeMethod(method)) { return this .hashCode(); } else if (method.getDeclaringClass() == DecoratingProxy.class) { return AopProxyUtils.ultimateTargetClass(this .advised); } else if (!this .advised.opaque && method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAssignableFrom(Advised.class)) { return AopUtils.invokeJoinpointUsingReflection(this .advised, method, args); } Object retVal; if (this .advised.exposeProxy) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true ; } target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null ); List<Object> chain = this .advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); if (chain.isEmpty()) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else { MethodInvocation invocation = new ReflectiveMethodInvocation (proxy, target, method, args, targetClass, chain); retVal = invocation.proceed(); } Class<?> returnType = method.getReturnType(); if (retVal != null && retVal == target && returnType != Object.class && returnType.isInstance(proxy) && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) { throw new AopInvocationException ( "Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target != null && !targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); } } }
由上述方法实现,我们可以概括出整个增强代理的执行过程,如下:
特殊处理 Object#equals
、Object#hashCode
、DecoratingProxy#getDecoratedClass
,以及 Advised 类及其父类中定义的方法;
如果配置了 expose-proxy 属性,则记录当前代理对象,以备在内部间调用时实施增强;
获取当前方法的拦截器链;
如果没有拦截器定义,则直接反射调用增强方法,否则先逐一执行拦截器方法,最后再应用增强方法;
处理返回值。
重点来看一下步骤 4 中应用拦截器方法的实现,位于 ReflectiveMethodInvocation#proceed
方法中:
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 public Object proceed () throws Throwable { if (this .currentInterceptorIndex == this .interceptorsAndDynamicMethodMatchers.size() - 1 ) { return this .invokeJoinpoint(); } Object interceptorOrInterceptionAdvice = this .interceptorsAndDynamicMethodMatchers.get(++this .currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class<?> targetClass = (this .targetClass != null ? this .targetClass : this .method.getDeclaringClass()); if (dm.methodMatcher.matches(this .method, targetClass, this .arguments)) { return dm.interceptor.invoke(this ); } else { return this .proceed(); } } else { return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this ); } }
拦截器方法的执行流程如上述代码注释,是一个递归调用的过程,并在最后应用增强方法。
完成了对于 AOP 代理对象 JdkDynamicAopProxy
的创建,最后来看一下获取该对象的过程,实现位于 JdkDynamicAopProxy#getProxy
方法中:
1 2 3 4 5 6 7 8 public Object getProxy (@Nullable ClassLoader classLoader) { Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this .advised, true ); this .findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this ); }
这里的逻辑也就是 Java 原生代理的模板代码,如果对 Java 代理比较熟悉的话,应该不难理解
基于 CGLib 代理创建增强代理对象 基于 CGLib 代理生成增强代理对象的过程位于 ObjenesisCglibAopProxy
类中,该类继承自 CglibAopProxy
类。获取 CGLib 代理类对象的方法定义在 CglibAopProxy
中,即 CglibAopProxy#getProxy
方法。该方法基于 CGLib 的 Enhancer
类创建代理对象,属于 CGLib 的标准使用模式,因为有多个 callback
实现,所以这里使用了 CallbackFilter
模式,依据场景选择并应用对应的 callback
拦截器。
我们重点关注 callback
的实现,位于 CglibAopProxy#getCallbacks
方法中。受制于 CGLib 在执行时一次只允许应用一个 callback
的约束,所以该方法依据参数配置实现了一组 callback
,以覆盖不同的场景。核心的 AOP callback 实现是 DynamicAdvisedInterceptor
类,它实现了 MethodInterceptor
接口,对应的 DynamicAdvisedInterceptor#intercept
方法实现如下:
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 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) { oldProxy = AopContext.setCurrentProxy(proxy); setProxyContext = true ; } target = targetSource.getTarget(); Class<?> targetClass = (target != null ? target.getClass() : null ); List<Object> chain = this .advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); Object retVal; if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) { Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args); retVal = methodProxy.invoke(target, argsToUse); } else { 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) { AopContext.setCurrentProxy(oldProxy); } } }
可以看出上述方法在实现流程上与前面介绍的 JdkDynamicAopProxy#invoke
方法是一致的,只是这里是基于 CGLib 实现
参考 https://my.oschina.net/wangzhenchao/blog/4279608
总结
@EnableAspectJAutoProxy
开启AOP功能
@EnableAspectJAutoProxy
会给容器中注册一个组件 AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator
是一个 InstantiationAwareBeanPostProcessor
类型后置处理器,功能可以概括为:
从容器中获取所有的切面定义
筛选适用于当前 bean 的增强器集合
依据增强器集合基于动态代理机制生成相应的增强代理对象
Spring AOP 的实现本质上是一个动态代理的过程,Spring 引入了 Java 原生代理和 CGLib 代理,并依据场景选择基于哪种代理机制对目标对象进行增强。Spring 容器在完成对 bean 对象的创建之后会执行初始化操作,而 AOP 初始化的过程就发生在 bean 的后置初始化阶段