Spring-AOP @AspectJ切点函数之@within()和@target

简介: Spring-AOP @AspectJ切点函数之@within()和@target

概述


除了@annotation和@args外,还有另外两个用于注解的切点函数,分别是@target和@within.


和@annotation @args函数一样,@target和@within也只接受注解类名作为入参。


其中@target(M)匹配任意标注了@M的目标类,而@within(M)匹配标注了@M的类及其子孙类(子类经测试匹配不到,欢迎指正)


@target(M)的匹配规则


aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwOTA1MjM0MTAyMTcw.png


@target使用@target(注解类型全限定名)匹配当前目标对象类型的执行方法, 必须是在目标对象上声明注解,在接口上声明不起作用


@within(M)的匹配规则


经验证,目前发现和 @target(M)的匹配规则是一样的。

@within(注解类型全限定名)匹配所有持有指定注解的类里面的方法, 即要把注解加在类上. 在接口上声明不起作用 。 子孙类经测试匹配不到,如有错误烦请指出。


实例

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster


@target


aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwOTA2MDEzNTA4MDcw.png


首先自定义一个注解用于测试用

package com.xgj.aop.spring.advisor.aspectJ.function.attarget;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 
 * 
 * @ClassName: Mark
 * 
 * @Description: 自定义注解
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午12:02:46
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Mark {
  public String value() default "";
}


4个注解标注的POJO ,继承关系 C3 -->C2–> C1–> C0

package com.xgj.aop.spring.advisor.aspectJ.function.attarget;
import org.springframework.stereotype.Component;
/**
 * 
 * 
 * @ClassName: C0
 * 
 * @Description: @Component 标注的Bean
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午1:36:37
 */
@Component
public class C0 {
  public void methodName() {
    System.out.println("C0 method executed");
  }
}


C1类声明处标注了自定义注解@Mark

package com.xgj.aop.spring.advisor.aspectJ.function.attarget;
import org.springframework.stereotype.Component;
@Mark
@Component
public class C1 extends C0 {
  public void methodName() {
    System.out.println("C1 method executed");
  }
}


C2类声明处标注了自定义注解@Mark

package com.xgj.aop.spring.advisor.aspectJ.function.attarget;
import org.springframework.stereotype.Component;
@Mark
@Component
public class C2 extends C1 {
  public void methodName() {
    System.out.println("C2 method executed");
  }
}
package com.xgj.aop.spring.advisor.aspectJ.function.attarget;
import org.springframework.stereotype.Component;
@Component
public class C3 extends C2 {
  public void methodName() {
    System.out.println("C3 method executed");
  }
}

使用@Aspect标注的环绕增强切面

package com.xgj.aop.spring.advisor.aspectJ.function.attarget;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
/**
 * 
 * 
 * @ClassName: AtTargetAspect
 * 
 * @Description: 标注了@Aspect的切面 环绕增强切面
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 上午11:59:26
 */
@Aspect
public class AtTargetAspect {
  @Around("@target(com.xgj.aop.spring.advisor.aspectJ.function.attarget.Mark)")
  public void crossCuttingCode(ProceedingJoinPoint joinPoint)
      throws Throwable {
    System.out.println("****AtTargetAspect.crossCuttingCode() : "
        + joinPoint.getSignature().getName()
        + ": Before Method Execution");
    try {
      joinPoint.proceed();
    } finally {
      // Do Something useful, If you have
    }
    System.out.println("****AtTargetAspect.crossCuttingCode() : "
        + joinPoint.getSignature().getName()
        + ": After Method Execution");
  }
}


配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
<!-- (1)声明Context命名空间以及Schema文件   (2)扫描类包以及应用注解定义的bean -->
<context:component-scan base-package="com.xgj.aop.spring.advisor.aspectJ.function.attarget"/>
<!-- 基于@AspectJ切面的驱动器 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 使用了@AspectJ注解的切面类 -->
<bean class="com.xgj.aop.spring.advisor.aspectJ.function.attarget.AtTargetAspect"/>
</beans>


测试代码

package com.xgj.aop.spring.advisor.aspectJ.function.attarget;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AtTargetAspectTest {
  private ApplicationContext ctx;
  @Test
  public void test() {
    ctx = new ClassPathXmlApplicationContext(
        "classpath:com/xgj/aop/spring/advisor/aspectJ/function/attarget/conf-attarget.xml");
    C0 c0 = ctx.getBean("c0", C0.class);
    C1 c1 = ctx.getBean("c1", C1.class);
    C2 c2 = ctx.getBean("c2", C2.class);
    C3 c3 = ctx.getBean("c3", C3.class);
    // C0没有标注了@Mark,不会被织入增强
    c0.methodName();
    // C1标注了@Mark,会被织入增强
    c1.methodName();
    // C2标注了@Mark,会被织入增强
    c2.methodName();
    // C3没有标注了@Mark,不会被织入增强
    c3.methodName();
  }
}


运行结果:

2017-09-05 13:40:56,244  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@c24cb3: startup date [Tue Sep 05 13:40:56 BOT 2017]; root of context hierarchy
2017-09-05 13:40:56,338  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/function/attarget/conf-attarget.xml]
C0 method executed
****AtTargetAspect.crossCuttingCode() : methodName: Before Method Execution
C1 method executed
****AtTargetAspect.crossCuttingCode() : methodName: After Method Execution
****AtTargetAspect.crossCuttingCode() : methodName: Before Method Execution
C2 method executed
****AtTargetAspect.crossCuttingCode() : methodName: After Method Execution
C3 method executed


C1 和 C2标注了@Mark注解,可以看到成功的织入了@Around环绕增强


@within


aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwOTA2MDU1OTU4NDMy.png

自定义一个注解

package com.xgj.aop.spring.advisor.aspectJ.function.atwithin;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 
 * 
 * @ClassName: Mark
 * 
 * @Description: 自定义注解
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午12:02:46
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Mark2 {
  public String value() default "";
}


4个注解声明的POJO Bean

package com.xgj.aop.spring.advisor.aspectJ.function.atwithin;
import org.springframework.stereotype.Component;
/**
 * 
 * 
 * @ClassName: C0
 * 
 * @Description: @Component 标注的Bean
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午1:36:37
 */
@Component
public class A0 {
  public void methodName() {
    System.out.println("A0 method executed \n");
  }
}
package com.xgj.aop.spring.advisor.aspectJ.function.atwithin;
import org.springframework.stereotype.Component;
/**
 * 
 * 
 * @ClassName: A1
 * 
 * @Description: 标注了@Mark2,可以被增强
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午6:02:21
 */
@Mark2
@Component
public class A1 extends A0 {
  public void methodName() {
    System.out.println("A1 method executed");
  }
}
package com.xgj.aop.spring.advisor.aspectJ.function.atwithin;
import org.springframework.stereotype.Component;
@Component
public class A2 extends A1 {
  public void methodName() {
    System.out.println("A2 method executed");
  }
}
package com.xgj.aop.spring.advisor.aspectJ.function.atwithin;
import org.springframework.stereotype.Component;
@Component
public class A3 extends A2 {
  public void methodName() {
    System.out.println("A3 method executed");
  }
}

切面 实现了Ordered接口

package com.xgj.aop.spring.advisor.aspectJ.function.atwithin;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;
/**
 * 
 * 
 * @ClassName: AtWithinAspect
 * 
 * @Description: 标注了@Aspect 环绕增强切面
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午1:53:40
 */
@Aspect
public class AtWithinAspect implements Ordered {
  @Around("@within(com.xgj.aop.spring.advisor.aspectJ.function.atwithin.Mark2)")
  public void crossCuttingCode(ProceedingJoinPoint joinPoint)
      throws Throwable {
    System.out.println("****AtWithinAspect.crossCuttingCode() : "
        + joinPoint.getSignature().getName()
        + ": Before Method Execution");
    try {
      joinPoint.proceed();
    } finally {
      // Do Something useful, If you have
    }
    System.out.println("****AtWithinAspect.crossCuttingCode() : "
        + joinPoint.getSignature().getName()
        + ": After Method Execution \n");
  }
  @Override
  public int getOrder() {
    return 1;
  }
}


配置文件


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
<!-- (1)声明Context命名空间以及Schema文件   (2)扫描类包以及应用注解定义的bean -->
<context:component-scan base-package="com.xgj.aop.spring.advisor.aspectJ.function.atwithin"/>
<!-- 基于@AspectJ切面的驱动器 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 使用了@AspectJ注解的切面类 -->
<bean class="com.xgj.aop.spring.advisor.aspectJ.function.atwithin.AtWithinAspect"/>
</beans>

测试类

package com.xgj.aop.spring.advisor.aspectJ.function.atwithin;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AtWithinAspectTest {
  private ApplicationContext ctx;
  @Test
  public void test() {
    ctx = new ClassPathXmlApplicationContext(
        "classpath:com/xgj/aop/spring/advisor/aspectJ/function/atwithin/conf-atwithin.xml");
    A0 a0 = ctx.getBean("a0", A0.class);
    A1 a1 = ctx.getBean("a1", A1.class);
    A2 a2 = ctx.getBean("a2", A2.class);
    A3 a3 = ctx.getBean("a3", A3.class);
    // A0没有标注@Mark,不会被织入增强
    a0.methodName();
    // A1标注了@Mark,会被织入增强
    a1.methodName();
    // A2没有标注@Mark,不会被织入增强
    a2.methodName();
    // A3没有标注@Mark,不会被织入增强
    a3.methodName();
  }
}


运行结果:

2017-09-05 18:04:01,685  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@c24cb3: startup date [Tue Sep 05 18:04:01 BOT 2017]; root of context hierarchy
2017-09-05 18:04:01,793  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/function/atwithin/conf-atwithin.xml]
A0 method executed 
****AtWithinAspect.crossCuttingCode() : methodName: Before Method Execution
A1 method executed
****AtWithinAspect.crossCuttingCode() : methodName: After Method Execution 
A2 method executed
A3 method executed


注意事项


如果标注了@M注解的是一个接口,则所有实现该接口的类并不匹配@within(M) . 假设接口Waiter标注了@Mark注解,但是它的实现类NaiveWaiter、NaughtyWaiter这些接口实现类灭有标注@Mark, 则@within(com.xgj.Mark) 和 @target(com,xgj.Mark)都不匹配NaiveWaiter、NaughtyWaiter。 因为@within() @target() @annotation函数都是针对目标类而言的,而非针对运行时的引用类型而言。 需要特别注意。


验证过程见github中的 com.xgj.aop.spring.advisor.aspectJ.function.atwithin2


输出结果:

2017-09-05 18:11:18,171  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@24b9371e: startup date [Tue Sep 05 18:11:18 BOT 2017]; root of context hierarchy
2017-09-05 18:11:18,285  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/function/atwithin2/beans.xml]
NaughtyWaiter:greet to XiaoGong...
NaiveWaiter:greet to Jiang...

标注在接口上的@@Monitorable,使用within ,实现类中的方法并没有匹配

相关文章
|
5月前
|
XML Java API
Spring AOP切点和通知机制的深度解析
Spring AOP切点和通知机制的深度解析
83 4
|
5月前
|
Java Serverless 应用服务中间件
Serverless 应用引擎产品使用合集之Web函数启动的Spring Boot项目可以通过什么方式配置Nginx
阿里云Serverless 应用引擎(SAE)提供了完整的微服务应用生命周期管理能力,包括应用部署、服务治理、开发运维、资源管理等功能,并通过扩展功能支持多环境管理、API Gateway、事件驱动等高级应用场景,帮助企业快速构建、部署、运维和扩展微服务架构,实现Serverless化的应用部署与运维模式。以下是对SAE产品使用合集的概述,包括应用管理、服务治理、开发运维、资源管理等方面。
|
5月前
|
XML 缓存 Java
浅浅了解下Spring中生命周期函数(Spring6全攻略)
Spring框架设计生命周期回调函数的主要目的是为了提供一种机制,使开发人员能够在对象创建、初始化和销毁等生命周期阶段执行特定的操作。这种机制可以帮助开发人员编写更加灵活和可维护的代码。
33 0
|
6月前
|
Java 开发者 Spring
Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
【5月更文挑战第1天】Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
71 5
|
6月前
|
监控 Java 测试技术
Spring Boot与事务钩子函数:概念与实战
【4月更文挑战第29天】在复杂的业务逻辑中,事务管理是确保数据一致性和完整性的关键。Spring Boot提供了强大的事务管理机制,其中事务钩子函数(Transaction Hooks)允许开发者在事务的不同阶段插入自定义逻辑。本篇博客将详细探讨事务钩子函数的概念及其在Spring Boot中的应用。
172 1
|
6月前
Spring5源码(31)-基于@AspectJ的AOP
Spring5源码(31)-基于@AspectJ的AOP
49 0
|
6月前
|
XML Java 数据格式
Spring-AOP @AspectJ语法基础
Spring-AOP @AspectJ语法基础
79 0
|
消息中间件 Java Kafka
Spring 事务的独门绝技:钩子函数的使用技巧
经过前面对Spring AOP、事务的总结,我们已经对它们有了一个比较感性的认知了。今天,我继续安利一个独门绝技:Spring 事务的钩子函数。单纯的讲技术可能比较枯燥乏味。接下来,我将以一个实际的案例来描述Spring事务钩子函数的正确使用姿势。
Spring 事务的独门绝技:钩子函数的使用技巧
|
Java Spring
AOP之切点
AOP之切点
|
2月前
Micronaut AOP与代理机制:实现应用功能增强,无需侵入式编程的秘诀
AOP(面向切面编程)能够帮助我们在不修改现有代码的前提下,为应用程序添加新的功能或行为。Micronaut框架中的AOP模块通过动态代理机制实现了这一目标。AOP将横切关注点(如日志记录、事务管理等)从业务逻辑中分离出来,提高模块化程度。在Micronaut中,带有特定注解的类会在启动时生成代理对象,在运行时拦截方法调用并执行额外逻辑。例如,可以通过创建切面类并在目标类上添加注解来记录方法调用信息,从而在不侵入原有代码的情况下增强应用功能,提高代码的可维护性和可扩展性。
62 1