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

本文详细介绍了 Spring AOP 中 target() 和 this() 函数的使用方式及区别,通过具体示例展示了如何利用这两种切点函数进行面向切面编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

target()切点函数通过判断目标类是否按类型匹配指定类来决定连接点是否匹配. 用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;

this()切点函数则通过判断代理类是否按类型匹配指定类来决定是否和切点匹配。 用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配。 this中使用的表达式必须是类型全限定名,不支持通配符。

两者都仅接受类名的入参,虽然类名可以带“+”,但是对于这两个函数来讲,使用或者不是用,效果完全相同。


实例

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


target()

target(M)表示如果目标类按类型匹配于M,这目标类的所有方法都匹配切点。

  • target(com.xgj.IBussiness) :IBussiness为接口,匹配接口实现类中所有方法,包括未在接口中声明的方法
  • target(com.xgj.IBussiness)等同于target(com.xgj.IBussiness+)

这里写图片描述

接口

package com.xgj.aop.spring.advisor.aspectJ.function.target;

public interface IBussinessService {

	String doSomething();

}

目标Bean

package com.xgj.aop.spring.advisor.aspectJ.function.target;

import org.springframework.stereotype.Component;

/**
 * 
 * 
 * @ClassName: BussinessService
 * 
 * @Description: @Component标注的bean
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午8:18:03
 */

@Component
public class BussinessService {

	public String doSomething() {
		System.out.println("doSomething executed");
		return "success";
	}
}

切面

package com.xgj.aop.spring.advisor.aspectJ.function.target;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

/**
 * 
 * 
 * @ClassName: TargetAspect
 * 
 * @Description: @Aspect标注的切面
 *               target(com.xgj.aop.spring.advisor.aspectJ.function.
 *               target.Class1)等同于
 *               target(com.xgj.aop.spring.advisor.aspectJ.function
 *               .target.Class1+)
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午7:53:52
 */

@Aspect
public class TargetAspect {

				@AfterReturning("target(com.xgj.aop.spring.advisor.aspectJ.function.target.IBussinessService)")
	public void crossCuttingCode() {
		System.out.println("some logic is here");
	}
}

配置文件

<?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.target"/>

<!-- 基于@AspectJ切面的驱动器 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
 
<!-- 使用了@AspectJ注解的切面类 -->
<bean class="com.xgj.aop.spring.advisor.aspectJ.function.target.TargetAspect"/>

</beans>

测试类

package com.xgj.aop.spring.advisor.aspectJ.function.target;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TargetAspectTest {

	private ApplicationContext applicationContext;

	@Test
	public void test() {
		applicationContext = new ClassPathXmlApplicationContext(
				"classpath:com/xgj/aop/spring/advisor/aspectJ/function/target/conf-target.xml");

		BussinessService bussinessService = applicationContext.getBean(
				"bussinessService", BussinessService.class);
		// 织入增强
		bussinessService.doSomething();
		// 织入增强
		bussinessService.doAnother();
	}
}


运行结果:

2017-09-05 20:37:52,147  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@285211ef: startup date [Tue Sep 05 20:37:52 BOT 2017]; root of context hierarchy
2017-09-05 20:37:52,264  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/function/target/conf-target.xml]
doSomething executed
some logic is here
doAnother executed
some logic is here


this()

一般情况下,使用this()和target()来匹配定义切点,二者是等效的

  • target(com.xgj.IBussiness)等价于 this(com.xgj.IBussiness)
  • target(com.xgj.BussinessService)等价于this(com.xgj.BussinessService)

二者的区别体现在通过引介切面产生代理对象时的具体表现。

看个例子:

这里写图片描述

接口

package com.xgj.aop.spring.advisor.aspectJ.function.thisFun;

public interface IBussinessService {
	String doBussiness();
}

实现类

package com.xgj.aop.spring.advisor.aspectJ.function.thisFun;

import org.springframework.stereotype.Component;

/**
 * 
 * 
 * @ClassName: BussinessService
 * 
 * @Description: @Component标注的bean
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午8:18:03
 */

@Component
public class BussinessService implements IBussinessService {

	@Override
	public String doBussiness() {
		System.out.println("doBussiness executed");
		return "success";
	}

	public String doAnother() {
		System.out.println("doAnother executed");
		return "success";
	}
}

另外一个通过引介切面要实现的接口

package com.xgj.aop.spring.advisor.aspectJ.function.thisFun;

public interface ITransportService {
	public void doTransport();
}

实现类

package com.xgj.aop.spring.advisor.aspectJ.function.thisFun;

public class TransportService implements ITransportService {

	@Override
	public void doTransport() {
		System.out.println("doTransport executed");
	}

}

为Bussiness添加 ITransportService接口的切面

package com.xgj.aop.spring.advisor.aspectJ.function.thisFun;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.core.Ordered;

/**
 * 
 * 
 * @ClassName: AddTransportForBussinessAspect
 * 
 * @Description: 为Bussiness添加 ITransportService接口的切面
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午9:18:50
 */

@Aspect
public class AddTransportForBussinessAspect implements Ordered {
	// (1)value 为BussinessService添加接口实现, (2)defaultImpl要添加的接口的默认的接口实现类
	@DeclareParents(value = "com.xgj.aop.spring.advisor.aspectJ.function.thisFun.BussinessService", defaultImpl = TransportService.class)
	public ITransportService iTransportService; // (3) 要实现的目标接口

	@Override
	public int getOrder() {
		return 2;
	}

}

横切逻辑切面

package com.xgj.aop.spring.advisor.aspectJ.function.thisFun;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.core.Ordered;

/**
 * 
 * 
 * @ClassName: ThisAspect
 * 
 * @Description: @Aspectn标注的切面
 * 
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年9月5日 下午8:50:26
 */

@Aspect
public class ThisAspect implements Ordered {
	// 织入任何运行期对象为ITransportService的Bean中
	@AfterReturning("this(com.xgj.aop.spring.advisor.aspectJ.function.thisFun.ITransportService)")
	public void corssCuttingCode() {
		System.out.println("some logic is here \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.thisFun"/>

<!-- 基于@AspectJ切面的驱动器 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
 
<!-- 使用了@AspectJ注解的切面类 -->
<bean class="com.xgj.aop.spring.advisor.aspectJ.function.thisFun.ThisAspect"/>
<bean class="com.xgj.aop.spring.advisor.aspectJ.function.thisFun.AddTransportForBussinessAspect"/>

</beans>

测试类

package com.xgj.aop.spring.advisor.aspectJ.function.thisFun;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ThisAspectTest {
	private ApplicationContext applicationContext;

	@Test
	public void test() {
		applicationContext = new ClassPathXmlApplicationContext(
				"classpath:com/xgj/aop/spring/advisor/aspectJ/function/thisFun/conf-this.xml");

		BussinessService bussinessService = (BussinessService) applicationContext
				.getBean("bussinessService");
		// 匹配 this
		bussinessService.doBussiness();
		// 匹配 this
		bussinessService.doAnother();

		// 匹配 this
		((ITransportService) bussinessService).doTransport();

	}
}

运行结果

2017-09-05 22:24:03,301  INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@24177697: startup date [Tue Sep 05 22:24:03 BOT 2017]; root of context hierarchy
2017-09-05 22:24:03,397  INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/function/thisFun/conf-this.xml]
doBussiness executed
some logic is here 
 
doAnother executed
some logic is here 
 
doTransport executed
some logic is here 
 

如果有多个切面,注意多切面织入的顺序,如果不加织入的顺序, doTransport 方法的切面无法织入。

可见代理对象的方法都织入了this()函数定义的切面。

### Spring AOP 中 `aspectj-autoproxy` 配置启动报错解决方案 当在 Spring AOP 使用 `<aop:aspectj-autoproxy>` 进行配置时,如果遇到启动时报错提示找不到切点方法(Pointcut),通常是因为以下几个原因引起的: #### 1. 切点表达式错误 切点表达式的语法可能存在问题,或者未正确定位目标类中的方法。确保切点表达式能够匹配到实际存在的方法。 例如,假设有一个服务类 `MyService` 其方法 `doSomething()`,可以通过如下方式定义切点: ```java @Aspect public class LoggingAspect { @Before("execution(* com.example.service.MyService.doSomething(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Method called: " + joinPoint.getSignature().getName()); } } ``` 如果切点路径不正确或拼写有误,则会引发无法找到切点的异常[^1]。 --- #### 2. 组件扫描范围不足 如果没有正确启用组件扫描或将目标类排除在外,可能导致 Aspect 或目标 Bean 未能加载至容器中。因此,在 XML 文件中需确认已启用组件扫描并覆盖相关包路径。 以下是正确的组件扫描配置示例: ```xml <context:component-scan base-package="com.example"/> <aop:aspectj-autoproxy/> ``` 这里需要确保 `base-package` 属性指定了包含所有目标类 Aspect 类所在的包路径[^3]。 --- #### 3. 缺少必要的依赖库 Spring AOP 基于 AspectJ 实现动态代理功能,因此项目中必须引入相关的依赖项。缺少这些依赖可能会导致运行失败。 Maven 构建工具下的必要依赖应包括以下内容: ```xml <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <!-- 如果使用 CGLIB 动态代理 --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency> ``` 此外,还需注意版本兼容性问题,尤其是不同版本间的 API 变更[^2]。 --- #### 4. 方法访问权限限制 只有公共 (`public`) 方法才能作为切入点被拦截。如果尝试将私有 (`private`)、受保护 (`protected`) 或默认访问级别的方法设为切入点,则会导致此问题发生。 修改方法声明使其公开即可解决问题: ```java // 正确做法 public void doSomething() {} // 错误示范 (非公有方法不可用作切入点) private void internalLogic() {} ``` --- #### 5. 启用了 ProxyTargetClass 而无对应支持 通过设置属性 `proxy-target-class="true"` 来强制使用 CGLIB 替代 JDK 动态代理模式下,某些场景仍可能出现冲突情况。此时建议验证所使用的对象确实适合此类代理机制,并调整相应参数值测试效果差异。 XML 示例代码片段如下所示: ```xml <aop:aspectj-autoproxy proxy-target-class="false"/> <!-- 默认采用接口形式 --> ``` --- ### 总结 综上所述,针对 Spring AOP 配置过程中因找不到切点而导致的应用程序初始化阶段抛出异常的情况,可以从以上几个方面逐一排查定位根本原因所在。最终目的是让框架成功识别所需监控的目标函数从而正常运作起来[^1]^[]^. ```python print("Debugging completed.") ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小工匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值