多个AspectJ对同一个对象操作产生的实际效果以及顺序情况

1,417 阅读10分钟
原文链接: xuqiang.me

前提

  • Spring 5
  • 基于Java Configuration配置,而非XML配置
  • 对于AspectJ的分析,不对Spring本身的Advisor做分析

概要

如果需要了解多个AscpectJ对同一个对象操作产生的实际效果以及作用顺序,则需要首先了解AOP对象的构建过程,以及如何织入,还有就是织入过程中的顺序逻辑的了解。

所以,这篇文章主要内容如下:

AOP构造者注册

AOP构造者的注册是通过Spring的Import机制实现。在EnableAspectJAutoProxy注解上,存在@Import注解,其内部有实现了ImportBeanDefinitionRegistrar接口的AspectJAutoProxyRegistrar类。

在这里简单介绍下ImportBeanDefinitionRegistrar接口。

ImportBeanDefinitionRegistrar接口常被用于Spring动态bean注册。这个接口会被ConfigurationClassPostProcessor类内的ConfigurationClassParser代理类解析,并通过ConfigurationClassBeanDefinitionReader类的loadBeanDefinitions方法调用所有实现了ImportBeanDefinitionRegistrar接口类的registerBeanDefinitions方法。

以下是ImportBeanDefinitionRegistrar类执行registerBeanDefinitions的过程:

// 1. 容器上下文注册
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
  this();
  register(annotatedClasses);
  // 刷新
  refresh();
}

// 2. 执行invokeBeanFactoryPostProcessors
public void refresh() throws BeansException, IllegalStateException {
  // ...
  invokeBeanFactoryPostProcessors(beanFactory);
  // ...
}

// 3. 执行PostProcessor代理类的invokeBeanFactoryPostProcessors方法
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

// 4. 循环所有的beanProcessors
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
  postProcessor.postProcessBeanDefinitionRegistry(registry);
}

// 5. 执行ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry方法
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
  processConfigBeanDefinitions(registry);
}

// 6. 实例化ConfigurationClassParser类,并执行解析操作(比如@PropertySources、@ComponentScans、@Import、@ImportSelectors等等注解的解析处理)
ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
parser.parse(candidates);

// 7. 加载Bean解析信息
if (this.reader == null) {
  this.reader = new ConfigurationClassBeanDefinitionReader(
      registry, this.sourceExtractor, this.resourceLoader, this.environment,
      this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);

// 8. 从配置类加载Bean解析信息
private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

  if (trackedConditionEvaluator.shouldSkip(configClass)) {
    String beanName = configClass.getBeanName();
    if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
      this.registry.removeBeanDefinition(beanName);
    }
    this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
    return;
  }

  if (configClass.isImported()) {
    registerBeanDefinitionForImportedConfigurationClass(configClass);
  }
  for (BeanMethod beanMethod : configClass.getBeanMethods()) {
    loadBeanDefinitionsForBeanMethod(beanMethod);
  }

  loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
  // 加载Import registry的信息
  loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

9. ImportBeanDefinitionRegistrar执行bean解析
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
  registrars.forEach((registrar, metadata) ->
      registrar.registerBeanDefinitions(metadata, this.registry));
}

在注册过程中,ImportBeanDefinitionRegistrar类先将AnnotationAwareAspectJAutoProxyCreator注册到了Bean容器内,然后通过EnableAspectJAutoProxy注解,将proxyTargetClassexposeProxy属性注入到 AnnotationAwareAspectJAutoProxyCreator类的bean定义内。

// 将AnnotationAwareAspectJAutoProxyCreator注册到Bean容器
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

AnnotationAttributes enableAspectJAutoProxy =
    AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
  if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
    // 注册属性proxyTargetClass
    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
  }
  if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
    // 注册属性exposeProxy
    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
  }
}

AOP代理对象的初始化构建

AOP的代理对象是在BeanPostProcesser的处理回调内创建的,AOP的代理创建类实现了BeanPostProcesser的接口,该类名为AnnotationAwareAspectJAutoProxyCreator

本质上来说,是它的父类AbstractAutoProxyCreator实现了SmartInstantiationAwareBeanPostProcessor接口,而这个接口继承了InstantiationAwareBeanPostProcessor接口,同时InstantiationAwareBeanPostProcessor接口继承了BeanPostProcesser接口。

在类初始化完成后,会调用AbstractAutoProxyCreator类的postProcessAfterInitialization方法,在这个方法内,会获取目标对象的所有advice来判断是否需要构建代理类。

Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
  // 需要代理,创建具体的代理类
  // ...
}

具体来看一下getAdvicesAndAdvisorsForBean方法,主要是搜索Advisor类的实现和标注有@Aspect注解的类,并且获取@Aspect注解类内的切面点(以下逻辑内容实现在AnnotationAwareAspectJAutoProxyCreator类内,覆盖了父类AbstractAutoProxyCreatorfindCandidateAdvisors方法)。

// Add all the Spring advisors found according to superclass rules.
List<Advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
  advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;

如果没有实现Advisor接口类,则super.findCandidateAdvisors()返回的会是一个空列表。本文也主要探究的是AspectJ相关的具体实现逻辑,所以忽略父类的Advisor搜索逻辑,来具体看一下buildAspectJAdvisors方法。

// this.aspectBeanNames缓存的是本次容器启动后的切面类名称列表,如果刚启动,则为空
List<String> aspectNames = this.aspectBeanNames;

// 判断是否为null,如果是的话,锁类并且初始化切面类名称
if (aspectNames == null) {
  synchronized (this) {
    // 再次判断是否为空,确保其他线程在获取锁后不会重复做初始化操作
    aspectNames = this.aspectBeanNames;
    if (aspectNames == null) {
      List<Advisor> advisors = new ArrayList<>();
      aspectNames = new ArrayList<>();
      // 查找所有父类为Object的bean对象
      String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
          this.beanFactory, Object.class, true, false);
      for (String beanName : beanNames) {
        // 判断是否需要通过[includePatterns]属性过滤,不过Java配置的AOP貌似不支持这个属性,也可能是没找到在哪里
        if (!isEligibleBean(beanName)) {
          continue;
        }
        // 在这里不需要立即实例化类;因为,通过getType方法它会被Spring容器缓存,但是却不会被织入
        Class<?> beanType = this.beanFactory.getType(beanName);
        if (beanType == null) {
          continue;
        }
        // 判断获取的类是否为Aspect类
        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);
            // 通过bean工厂类获取对应切面类的所有Advisor
            List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
            if (this.beanFactory.isSingleton(beanName)) {
              // 如果bean工厂类为单例,则将Advisors缓存到key为切面类名的advisorsCache内
              this.advisorsCache.put(beanName, classAdvisors);
            }
            else {
              // 如果bean工厂类不为实例,则缓存缓存到key为切面类名的aspectFactoryCache内
              this.aspectFactoryCache.put(beanName, factory);
            }
            // 将所有的Advisors缓存到advisors列表内
            advisors.addAll(classAdvisors);
          }
          else {
            // 每个切面类需要对应有工厂类
            if (this.beanFactory.isSingleton(beanName)) {
              // 如果工厂类是单例,则抛出异常
              throw new IllegalArgumentException("Bean with name '" + beanName +
                  "' is a singleton, but aspect instantiation model is not singleton");
            }
            // 缓存缓存到key为切面类名的aspectFactoryCache内
            MetadataAwareAspectInstanceFactory factory =
                new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
            this.aspectFactoryCache.put(beanName, factory);
            advisors.addAll(this.advisorFactory.getAdvisors(factory));
          }
        }
      }
      this.aspectBeanNames = aspectNames;
      return advisors;
    }
  }
}

// 切面类名称列表不为null
// 判断获取到的切面类名称列表是否为空
if (aspectNames.isEmpty()) {
  return Collections.emptyList();
}
List<Advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
  // 从advisorsCache内获取切面类的所有Advisors
  List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
  if (cachedAdvisors != null) {
    advisors.addAll(cachedAdvisors);
  }
  else {
    // 如果cachedAdvisors为空,则从aspectFactoryCache缓存内获取bean工厂,并且通过bean工厂获取所有的Advisors
    MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
    advisors.addAll(this.advisorFactory.getAdvisors(factory));
  }
}
return advisors;

以上代码基本描述的就是遍历容器内的所有对象,并且判断对象是否是Aspect类型,如果是的话加入到Advisors列表内,并返回。具体判断逻辑如下:

// 判断是否有@Aspect的注解或者这个类的字段名称存在`ajc$`前缀(如果被AspectJ Compiler编译的类会带有这个前缀)
return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));

获取了所有的Advisors之后,需要判断列表是否不为空,即specificInterceptors != DO_NOT_PROXY

如果不为空,则创建具体的代理类。

// 将此advisor存入advisedBeans缓存
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理对象
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
// 缓存代理类的类型,存入proxyTypes缓存
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;

先看下代理类的具体创建逻辑:

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
			@Nullable Object[] specificInterceptors, TargetSource targetSource) {
  
  // 如果bean工厂是ConfigurableListableBeanFactory的实例,则标记exposeTargetClass属性
  if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
    AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
  }

  ProxyFactory proxyFactory = new ProxyFactory();
  proxyFactory.copyFrom(this);

  // 判断AspectJ有没有设置proxyTargetClass属性(代理类直接继承目标类)
  if (!proxyFactory.isProxyTargetClass()) {
    if (shouldProxyTargetClass(beanClass, beanName)) {
      proxyFactory.setProxyTargetClass(true);
    }
    else {
      evaluateProxyInterfaces(beanClass, proxyFactory);
    }
  }

  // 构建切面
  // 对所有的切面(common、advisor、advice)做一次封装,将之全部分装为Advisor类型
  Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
  proxyFactory.addAdvisors(advisors);
  // 设置代理目标类
  proxyFactory.setTargetSource(targetSource);
  // 子类回调,目前AnnotationAwareAspectJAutoProxyCreator未覆盖该方法,忽略
  customizeProxyFactory(proxyFactory);

  proxyFactory.setFrozen(this.freezeProxy);
  if (advisorsPreFiltered()) {
    proxyFactory.setPreFiltered(true);
  }

  // 获取代理类
  return proxyFactory.getProxy(getProxyClassLoader());
}

接下来就是通过代理工厂来具体创建代理类,Spring中,可以通过两种方式来创建代理类:

  • Jdk动态代理
  • Cglib动态代理

具体使用哪种方式的通过如下条件判断:

// 未配置优化且未设置proxyTargetClass为true且有用户自定义的代理接口,则直接使用JDK动态代理
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
  Class<?> targetClass = config.getTargetClass();
  if (targetClass == null) {
    throw new AopConfigException("TargetSource cannot determine target class: " +
        "Either an interface or a target is required for proxy creation.");
  }
  // 目标代理类为接口或者是代理类,则使用JDK动态代理
  if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
    return new JdkDynamicAopProxy(config);
  }
  // 其他情况使用Cglib动态代理
  return new ObjenesisCglibAopProxy(config);
}
else {
  return new JdkDynamicAopProxy(config);
}

在这里,对JDK动态代理不做具体分析,具体来看ObjenesisCglibAopProxy类内getProxy的获取:

if (logger.isDebugEnabled()) {
  logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
}

try {
  Class<?> rootClass = this.advised.getTargetClass();
  Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

  Class<?> proxySuperClass = rootClass;
  if (ClassUtils.isCglibProxyClass(rootClass)) {
    proxySuperClass = rootClass.getSuperclass();
    Class<?>[] additionalInterfaces = rootClass.getInterfaces();
    for (Class<?> additionalInterface : additionalInterfaces) {
      this.advised.addInterface(additionalInterface);
    }
  }

  // Validate the class, writing log messages as necessary.
  validateClassIfNecessary(proxySuperClass, classLoader);

  // Configure CGLIB Enhancer...
  Enhancer enhancer = createEnhancer();
  if (classLoader != null) {
    enhancer.setClassLoader(classLoader);
    if (classLoader instanceof SmartClassLoader &&
        ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
      enhancer.setUseCache(false);
    }
  }
  enhancer.setSuperclass(proxySuperClass);
  enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
  enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
  enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

  // 获取回调方法(其中包括最重要的aopInterceptor,用于advices调用链的处理)
  Callback[] callbacks = getCallbacks(rootClass);
  Class<?>[] types = new Class<?>[callbacks.length];
  for (int x = 0; x < types.length; x++) {
    types[x] = callbacks[x].getClass();
  }
  // fixedInterceptorMap only populated at this point, after getCallbacks call above
  enhancer.setCallbackFilter(new ProxyCallbackFilter(
      this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
  enhancer.setCallbackTypes(types);

  // 生成代理class和代理实例
  return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
  throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
      ": Common causes of this problem include using a final class or a non-visible class",
      ex);
}
catch (Throwable ex) {
  // TargetSource.getTarget() failed
  throw new AopConfigException("Unexpected AOP exception", ex);
}

AOP advice的顺序问题

其实在通过AbstractAutoProxyCreator类的findCandidateAdvisors方法获取所有的advice后,会对这些advice做一个排序处理:

if (!eligibleAdvisors.isEmpty()) {
  eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}

Advisors的排序实现是通过AnnotationAwareOrderComparator类来达成的。这个类继承了OrderComparator类,覆盖了findOrdergetPriority方法。

其内部实现的顺序为:Ordered接口 -> 类级别的Order -> 类级别的Prority -> 其他被注解元素的Order -> 其他被注解元素的Prority。

AOP advice的具体调用

Spring AOP的实现并不是将所有的advice硬编码进目标代理类,而是通过织入DynamicAdvisedInterceptor类,在intercept方法内部调用advice调用链来达到拦截的目的。

@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;
    }
    // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
    target = targetSource.getTarget();
    Class<?> targetClass = (target != null ? target.getClass() : null);
    // 通过拦截的方法和目标对象,获取该方法的拦截调用链
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    Object retVal;
    // Check whether we only have one InvokerInterceptor: that is,
    // no real advice, but just reflective invocation of the target.
    if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
      // We can skip creating a MethodInvocation: just invoke the target directly.
      // Note that the final invoker must be an InvokerInterceptor, so we know
      // it does nothing but a reflective operation on the target, and no hot
      // swapping or fancy proxying.
      Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
      retVal = methodProxy.invoke(target, argsToUse);
    }
    else {
      // We need to create a method invocation...
      // 如果存在调用链,则实例化一个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);
    }
  }
}

接下来看下CglibMethodInvocationproceed方法:

//	We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
  // 如果调用链全部执行完毕,则执行被代理对象的原方法
  return invokeJoinpoint();
}

// 获得本次的advice
Object interceptorOrInterceptionAdvice =
    this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
  // Evaluate dynamic method matcher here: static part will already have
  // been evaluated and found to match.
  InterceptorAndDynamicMethodMatcher dm =
      (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
  if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
    return dm.interceptor.invoke(this);
  }
  else {
    // Dynamic matching failed.
    // Skip this interceptor and invoke the next in the chain.
    return proceed();
  }
}
else {
  // It's an interceptor, so we just invoke it: The pointcut will have
  // been evaluated statically before this object was constructed.
  // 继续执行下一个拦截器
  return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

拦截器的执行顺序,是根据调用链的顺序来执行的,而调用链的顺序早在之前的sort阶段就已经排列好了;如下的代码主要是获取目标对象和方法对应的拦截器链:

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, @Nullable Class<?> targetClass) {

  // This is somewhat tricky... We have to process introductions first,
  // but we need to preserve order in the ultimate list.
  List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
  Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
  boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
  AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

  for (Advisor advisor : config.getAdvisors()) {
    if (advisor instanceof PointcutAdvisor) {
      // Add it conditionally.
      PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
      if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
        MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
        if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
          MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
          if (mm.isRuntime()) {
            // Creating a new object instance in the getInterceptors() method
            // isn't a problem as we normally cache created chains.
            for (MethodInterceptor interceptor : interceptors) {
              interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
            }
          }
          else {
            interceptorList.addAll(Arrays.asList(interceptors));
          }
        }
      }
    }
    else if (advisor instanceof IntroductionAdvisor) {
      IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
      if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
        Interceptor[] interceptors = registry.getInterceptors(advisor);
        interceptorList.addAll(Arrays.asList(interceptors));
      }
    }
    else {
      Interceptor[] interceptors = registry.getInterceptors(advisor);
      interceptorList.addAll(Arrays.asList(interceptors));
    }
  }

  return interceptorList;
}

举个例子,声明拦截目标类:

@Component
public class Hello {

    public void world() {
        System.out.println("hello world");
    }

}

定义两个拦截器HelloAop以及HelloAop2:

@Aspect
@Component
public class HelloAop {

    @Pointcut("execution(* com.whatakitty.learn.Hello.*(..))")
    public void world() {
    }

    @Before("world()")
    public void before() {
        System.out.println("start hello world");
    }

    @After("world()")
    public void after() {
        System.out.println("end hello world");
    }

    @Around("world()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("around 1");
        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("around 1");
    }

}

@Aspect
@Component
public class HelloAop2 {

    @Pointcut("execution(* com.whatakitty.learn.Hello.*(..))")
    public void world() {
    }

    @Before("world()")
    public void before() {
        System.out.println("start hello world 2");
    }

    @After("world()")
    public void after() {
        System.out.println("end hello world 2");
    }

    @Around("world()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println("around 2");
        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println("around 2");
    }


}

执行结果如下:

around 1
start hello world
around 2
start hello world 2
hello world
around 2
end hello world 2
around 1
end hello world