在上边一篇文章中我们介绍了Spring AOP的基本概念,今天我们就来学习一下与AOP实现相关的修饰者模式和Java Proxy相关的原理,以及AOP的源码分析。
修饰者模式
Java设计模式中的修饰者模式能动态地给目标对象增加额外的职责(Responsibility)。它使用组合(object composition),即将目标对象作为修饰者对象(代理)的成员变量,由修饰者对象决定调用目标对象的时机和调用前后所要增强的行为。
装饰模式包含如下组成部分:
- Component: 抽象构件,也就是目标对象所实现的接口,有operation函数
- ConcreteComponent: 具体构件,也就是目标对象的类
- Decorator: 抽象装饰类,也实现了抽象构件接口,也就是目标类和装饰类都实现了相同的接口
- ConcreteDecorator: 具体装饰类,其中addBeavior函数就是增强的行为,装饰类可以自己决定addBeavior函数和目标对象函数operation函数的调用时机。
修饰者模式调用的时序图如下图所示。程序首先创建目标对象,然后创建修饰者对象,并将目标对象传入作为其成员变量。当程序调用修饰者对象的operation函数时,修饰者对象会先调用目标对象的operation函数,然后再调用自己的addBehavior函数。这就是类似于AOP的后置增强器,在目标对象的行为之后添加新的行为。
Spring AOP的实现原理和修饰者模式类似。在上一篇文章中说到AOP的动态代理有两种实现方式,分别是JDK Proxy和cglib。
如下图所示,JDK Proxy的类结构和上文中修饰者的类图结构类似,都是代理对象和目标对象都实现相同的接口,代理对象持有目标对象和切面对象,并且决定目标函数和切面增强函数的调用时机。
而cglib的实现略有不同,它没有实现实现相同接口,而是代理对象继承目标对象类。
本文后续就讲解一下JDK Proxy的相关源码分析。
JDK Proxy
JDK提供了Proxy类来实现动态代理的,可通过它的newProxyInstance函数来获得代理对象。JDK还提供了InvocationHandler类,代理对象的函数被调用时,会调用它的invoke函数,程序员可以在其中实现所需的逻辑。
JDK Proxy的基本语法如下所示。先构造一个InvocationHandler的实现类,然后调用Proxy的newProxyInstance函数生成代理对象,传入类加载器,目标对象的接口和自定义的InvocationHandler实例。
public class CustomInvocationHandler implements InvocationHandler {
private Object target;
public CustomInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Before invocation");
Object retVal = method.invoke(target, args);
System.out.println("After invocation");
return retVal;
}
}
CustomInvocationHandler customInvocationHandler = new CustomInvocationHandler(
helloWord);//通过Proxy.newProxyInstance生成代理对象
ProxyTest proxy = (ProxyTest) Proxy.newProxyInstance(
ProxyTest.class.getClassLoader(),
proxyObj.getClass().getInterfaces(), customInvocationHandler);
生成代理对象
我们首先来看一下Proxy的newProxyInstance函数。newProxyInstance函数的逻辑大致如下:
- 首先根据传入的目标对象接口动态生成代理类
- 然后获取代理类的构造函数实例
- 最后将InvocationHandler作为参数通过反射调用构造函数实例,生成代理类对象。
具体源码如下所示。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 1 动态生成代理对象的类
Class<?> cl = getProxyClass0(loader, intfs);
// ... 代码省略,下边代码其实是在try catch中的
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 2 获取代理类的构造函数
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;
}
});
}
// 3调用构造函数,传入InvocationHandler对象
return cons.newInstance(new Object[]{h});}
getProxyClass0函数的源码如下所示,通过代理类缓存获取代理类信息,如果不存在则会生成代理类。
// 生成代理类private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 如果已经有Proxy类的缓存则直接返回,否则要进行创建
return proxyClassCache.get(loader, interfaces);}
生成代理类
JDK Proxy通过ProxyClassFactory生成代理类。其apply函数大致逻辑如下:
- 校验接口是否符合规范· 生成代理类的名称和包名
- 生成代理类字节码
- 根据字节码生成代理类Class
// 生成代理类的工厂类
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>{
// 所有代理类名的前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 生成唯一类名的原子Long对象
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new
IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
// 通过loader找到接口对应的类信息。
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
// 判断找出来的类确实是一个接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 判断接口是否重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
// 代理类的包路径
String proxyPkg = null;
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
// 记录非公开的代理接口,以便于生成的代理类和原来的类在同一个路径下。
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
// 如果没有非公开的Proxy接口,使用com.sun.proxy报名
if (proxyPkg == null) {
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
long num = nextUniqueNumber.getAndIncrement();
// 默认情况下,代理类的完全限定名为:com.sun.proxy.$Proxy0,$Proxy1……依次递增
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成代理类字节码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 根据字节码返回相应的Class实例
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
其中关于字节码生成的部分逻辑我们就暂时不深入介绍了,感兴趣的同学可以自行研究。
$Proxy反编译
我们来看一下生成的代理类的反编译代码。代理类实现了Object的基础函数,比如toString、hasCode和equals,也实现了目标接口中定义的函数,比如说ProxyTest接口的test函数。
$Proxy中函数的实现都是直接调用了InvocationHandler的invoke函数。
public final class $Proxy0 extends Proxy
implements ProxyTest // 会实现目标接口,但是由于集成了Proxy,所以无法再集成其他类{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
// 构造函数要传入一个InvocationHandler对象
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
// equal函数
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[]
{ paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
// test函数,也就是ProxyTest接口中定义的函数
public final void test(String paramString)
throws
{
try
{
// 调用InvocationHandler的invoke函数
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
// 获取各个函数的Method对象
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("com.proxy.test2.HelloTest").getMethod("say", new Class[] { Class.forName("java.lang.String") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
}
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
Spring AOP是Spring的两大基石之一,接下来是源码的解析。
从代码执行角度来看,Spring AOP的执行过程分为四大步骤:
- 步骤一:Spring框架生成Advisor实例,可以是@Aspect,@Async等注解生成的实例,也可以是程序员自定义的AbstractAdvisor子类的实例.
- 步骤二:Spring框架在目标实例初始化完成后,也就是使用BeanPostProcessor的postProcessAfterInitialization方法,根据Advisor实例中切入点Pointcut的定义,选择出适合该目标对象的Advisor实例。
- 步骤三:Spring框架根据Advisor实例生成代理对象。
- 步骤四:调用方法执行过程时,Spring框架执行Advisor实例的通知Advice逻辑。
由于这四个步骤涉及的源码量较大,一篇文章无法直接完全讲解完,本篇文章只讲解第一步Advisor实例生成的源码分析。接下来我们就依次讲解一下后续步骤中比较关键的逻辑。
Advisor类架构
Spring中有大量的机制都是通过AOP实现的,比如说@Async的异步调用和@Transational。此外,用户也可以使用@Aspect注解定义切面或者直接继承AbstractPointcutAdvisor来提供切面逻辑。上述这些情况下,AOP都会生成对应的Advisor实例。
我们先来看一下Advisor的相关类图。首先看一下org.aopalliance包下的类图。aopalliance是AOP组织下的公用包,用于AOP中方法增强和调用,相当于一个jsr标准,只有接口和异常,在AspectJ、Spring等AOP框架中使用。
aopalliance定义了AOP的通知Advice和连接点Joinpoint接口,并且还有继承上述接口的MethodInterceptor和MethodInvocation。这两个类相信大家都很熟悉。
然后我们来看一下Spring AOP中Advisor相关的类图。Advisor是Spring AOP独有的概念,比较重要的类有AbstractPointcutAdvisor和InstantiationModelAwarePointcutAdvisor。相关的讲解都在图中表明了,如果这张图中的概念和类同学们都熟识,那么对AOP的了解就已经很深入了。
获取所有Advisor实例
AOP生成Advisor实例的函数入口是AbstractAdvisorAutoProxyCreator的findCandidateAdvisors函数。
// AbstractAdvisorAutoProxyCreator.java 找出当前所有的Advisorprotected List<Advisor> findCandidateAdvisors() {
Assert.state(this.advisorRetrievalHelper != null, "No
BeanFactoryAdvisorRetrievalHelper available");
return this.advisorRetrievalHelper.findAdvisorBeans();}
// AnnotationAwareAspectJAutoProxyCreator,是AbstractAdvisorAutoProxyCreator的子类@Overrideprotected List<Advisor> findCandidateAdvisors() {
// 调用父类的findCandidateAdvisor函数,一般找出普通的直接
// 继承Advisor接口的实例,比如说`@Async`所需的`AsyncAnnotationAdvisor`
List<Advisor> advisors = super.findCandidateAdvisors();
// 为AspectJ的切面构造Advisor,也就是说处理@Aspect修饰的类,生成上文中说的`InstantiationModelAwarePointcutAdvisor`实例
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}return advisors;
}
相关的ProxyCreator也有一个类体系,不过太过繁杂,而且重要性不大,我们就先略过,直接将具体的类。由上边代码可知AbstractAdvisorAutoProxyCreator的findCandidateAdvisors函数是直接获取Spring容器中的Advisor实例,比如说AsyncAnnotationAdvisor实例,或者说我们自定义的AbstractPointcutAdvisor的子类实例。AdvisorRetrievalHelper的findAdvisorBeans函数通过BeanFactory的getBean获取了所有类型为Advisor的实例。
而AnnotationAwareAspectJAutoProxyCreator看其类名就可知,是与AspectJ相关的创建器,用来获取@Aspect定义的Advisor实例,也就是InstantiationModelAwarePointcutAdvisor实例。
接下去我们看一下BeanFactoryAspectJAdvisorsBuilder的buildAspectJAdvisors函数,它根据@Aspect修饰的切面实例生成对应的Advisor实例。
public List<Advisor> buildAspectJAdvisors() {
List<String> aspectNames = this.aspectBeanNames;
// 第一次初始化,synchronized加双次判断,和经典单例模式的写法一样。
if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
// Spring源码并没有buildAspectJAdvisorsFirstly函数,为了方便理解添加。
// 获取aspectNames,创建Advisor实例,并且存入aspectFactoryCache缓存
return buildAspectJAdvisorsFirstly();
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
// 遍历aspectNames,依次获取对应的Advisor实例,或者是MetadataAwareAspectInstanceFactory生成的Advisor实例
for (String aspectName : aspectNames) {
List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
// cache可以取到实例,该Advisor是单例的
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
// 取得Advisor对应的工厂类实例,再次生成Advisor实例,该Advisor是多实例的。
MetadataAwareAspectInstanceFactory factory =
this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}return advisors;
}
buildAspectJAdvisors函数执行时分为两种情况,第一个未初始化时,也就是aspectNames为null时,执行buildAspectJAdvisorsFirstly进行第一次初始化,在这一过程中生成切面名称列表aspectBeanNames和要返回的Advisor列表,并且将生成的Advisor实例放置到advisorsCache中。
第二种情况则是已经初始化后再次调用,遍历aspectNames,从advisorsCache取出对应的Advisor实例,或者从advisorsCache取出Advisor对应的工厂类对象,再次生成Advisor实例。
public List<Advisor> buildAspectJAdvisorsFirstly() {
List<Advisor> advisors = new ArrayList<>();
List<String> aspectNames = new ArrayList<>();
// 调用BeanFactoryUtils获取所有bean的名称
String[] beanNames =
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 获取对应名称的bean实例
Class<?> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
/**
* AbstractAspectJAdvisorFactory类的isAspect函数来判断是否为切面实例
* 判断条件为是否被@Aspect修饰或者是由AspectJ编程而来。
*/
if (this.advisorFactory.isAspect(beanType)) {
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
// 切面的属性为单例模式
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
// 获取一个切面中所有定义的Advisor实例。一个切面可以定义多个Advisor。
List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 单例模式,只需要将生成的Advisor添加到缓存
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
// 多实例模式,需要保存工厂类,便于下一次再次生成Advisor实例。
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
}
this.aspectBeanNames = aspectNames;return advisors;
}
buildAspectJAdvisorsFirstly函数的逻辑如下:
- 首先使用BeanFactoryUtils获取了BeanFactory中所有的BeanName,然后进而使用BeanFactory获取所有的Bean实例。
- 遍历Bean实例,通过ReflectiveAspectJAdvisorFactory的isAspect函数判断该实例是否为切面实例,也就是被@Aspect注解修饰的实例。
- 如果是,则使用ReflectiveAspectJAdvisorFactory,根据切面实例的定义来生成对应的多个Advisor实例,并且将其加入到advisorsCache中。
生成InstantiationModelAwarePointcutAdvisorImpl实例
ReflectiveAspectJAdvisorFactory的getAdvisors函数会获取@Aspect修饰的实例中所有没有被@Pointcut修饰的方法,然后调用getAdvisor函数,并且将这些方法作为参数。
public Advisor getAdvisor(Method candidateAdviceMethod,
MetadataAwareAspectInstanceFactory aspectInstanceFactory,
int declarationOrderInAspect, String aspectName) {
validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
// 获得该方法上的切入点条件表达式
AspectJExpressionPointcut expressionPointcut = getPointcut(
candidateAdviceMethod,
aspectInstanceFactory.getAspectMetadata().getAspectClass());
if (expressionPointcut == null) {
return null;
}
// 生成Advisor实例
return new
InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
this, aspectInstanceFactory, declarationOrderInAspect, aspectName);}
private AspectJExpressionPointcut getPointcut(Method
candidateAdviceMethod, Class<?> candidateAspectClass) {
// 获得该函数上@Pointcut, @Around, @Before, @After, @AfterReturning, @AfterThrowing注解的信息
AspectJAnnotation<?> aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
// 没有上述注解,则直接返回
if (aspectJAnnotation == null) {
return null;
}
AspectJExpressionPointcut ajexp =
new AspectJExpressionPointcut(candidateAspectClass, new String[0], new
Class<?>[0]);
// 获得注解信息中的切入点判断表达式
ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
if (this.beanFactory != null) {
ajexp.setBeanFactory(this.beanFactory);
}return ajexp;
}
getAdvisor函数就是根据作为参数传入的切面实例的方法上的注解来生成Advisor实例,也就是InstantiationModelAwarePointcutAdvisorImpl对象。依据方法上的切入点表达式生成AspectJExpressionPointcut。
我们都知道PointcutAdvisor实例中必然有一个Pointcut和Advice实例。修饰在方法上的注解包括:@Pointcut, @Around, @Before, @After, @AfterReturning和@AfterThrowing,所以InstantiationModelAwarePointcutAdvisorImpl会依据不同的不同的注解生成不同的Advice通知。
public
InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
// .... 省略成员变量的直接赋值
// 单例模式时
this.pointcut = this.declaredPointcut;
this.lazy = false;
// 按照注解解析 Advice
this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);}
InstantiationModelAwarePointcutAdvisorImpl的构造函数中会生成对应的Pointcut和Advice。instantiateAdvice函数调用了ReflectiveAspectJAdvisorFactory的getAdvice函数。
// ReflectiveAspectJAdvisorFactorypublic Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut,
MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
Class<?> candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
validate(candidateAspectClass);
// 获取 Advice 注解
AspectJAnnotation<?> aspectJAnnotation =
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
if (aspectJAnnotation == null) {
return null;
}
// 检查是否为AspectJ注解
if (!isAspect(candidateAspectClass)) {
throw new AopConfigException("Advice must be declared inside an aspect type: " +
"Offending method '" + candidateAdviceMethod + "' in class [" +
candidateAspectClass.getName() + "]");
}
AbstractAspectJAdvice springAdvice;
// 按照注解类型生成相应的 Advice 实现类
switch (aspectJAnnotation.getAnnotationType()) {
case AtPointcut:
if (logger.isDebugEnabled()) {
logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
}
return null;
case AtAround:
// @Before 生成 AspectJMethodBeforeAdvice
springAdvice = new AspectJAroundAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtBefore:
// @After 生成 AspectJAfterAdvice
springAdvice = new AspectJMethodBeforeAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfter: // @AfterReturning 生成 AspectJAfterAdvice
springAdvice = new AspectJAfterAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
break;
case AtAfterReturning:
// @AfterThrowing 生成 AspectJAfterThrowingAdvice
springAdvice = new AspectJAfterReturningAdvice(
candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
AfterReturning afterReturningAnnotation = (AfterReturning)
aspectJAnnotation.getAnnotation();
if (StringUtils.hasText(afterReturningAnnotation.returning())) {
springAdvice.setReturningName(afterReturningAnnotation.returning());
}
break;
case AtAfterThrowing:
// @Around 生成 AspectJAroundAdvice
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);
}
// 配置Advice
springAdvice.setAspectName(aspectName);
springAdvice.setDeclarationOrder(declarationOrder);
// 获取方法的参数列表方法
String[] argNames =
this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod);
if (argNames != null) {
// 设置参数名称
springAdvice.setArgumentNamesFromStringArray(argNames);
}
springAdvice.calculateArgumentBindings();
return springAdvice;
}
至此,Spring AOP就获取了容器中所有的Advisor实例,下一步在每个实例初始化完成后,根据这些Advisor的Pointcut切入点进行筛选,获取合适的Advisor实例,并生成代理实例。
我这儿整理了比较全面的JAVA相关的面试资料,
需要领取面试资料的同学,请加群:473984645
获取更多学习资料,可以加群:473984645或扫描下方二维码