Spring @Pointcut切点详解

pointcut就是切点,通知需要在哪些方法处进行增强,在AspectJ中用@Pointcut注解表达式标注。

@Pointcut("execution(* com.aop.test.aspect..*.*(..))")
public void pointcut() {}
在spring aop中定义了Pointcut接口规范,其中定义了类过滤器`ClassFilter`和方法匹配器`MethodMatcher`。
public interface Pointcut {
	ClassFilter getClassFilter();
	MethodMatcher getMethodMatcher();
}

// 类匹配
public interface ClassFilter {
	boolean matches(Class<?> clazz);
}
// 方法匹配
public interface MethodMatcher {
 	// 方法是否匹配切点(静态匹配)
	boolean matches(Method method, Class<?> targetClass);
 	// 代理对象已经创建,静态匹配成功(两个参数的matches)
    // 方法调用时检查三个参数的matches方法是否匹配
	boolean isRuntime();
 	// 动态匹配,方法调用时带参数判断
	boolean matches(Method method, Class<?> targetClass, Object... args);
}

针对与AspectJ的实现

相关类结构:
image.png
抽象类主要定义了切点表达式expression

public abstract class AbstractExpressionPointcut implements ExpressionPointcut, Serializable {
	@Nullable
	private String location;
	@Nullable
	private String expression;
}
public class AspectJExpressionPointcut extends AbstractExpressionPointcut
		implements ClassFilter, IntroductionAwareMethodMatcher, BeanFactoryAware {
	private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();
	static {
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.ARGS);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.REFERENCE);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.THIS);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.TARGET);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.WITHIN);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ANNOTATION);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_WITHIN);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_ARGS);
		SUPPORTED_PRIMITIVES.add(PointcutPrimitive.AT_TARGET);
	}
	@Nullable
	private Class<?> pointcutDeclarationScope;
	private String[] pointcutParameterNames = new String[0];
	private Class<?>[] pointcutParameterTypes = new Class<?>[0];
	@Nullable
	private BeanFactory beanFactory;
	@Nullable
	private transient ClassLoader pointcutClassLoader;
	@Nullable
	private transient PointcutExpression pointcutExpression;
	private transient Map<Method, ShadowMatch> shadowMatchCache = new ConcurrentHashMap<>(32);
}

AspectJExpressionPointcut的具体实现有兴趣在慢慢分析,其最主要的意图就是解析@Pointcut注解表达式,调用ClassFilter#matches(Class)MethodMatcher#matches(Method, Class)判断目标类及方法是否符合切点表达式的定义。

Spring事务如何实现的Pointcut

Spring事务也是通过AOP的方式来实现,那么事务必然也需要有其对应的切点匹配方式,这里我们讨论注解申明式事务@Transaction,不难猜测这里的切点匹配就是判断目标类(及其方法)上是否有标记@Transaction注解,类上或类中任意一个方法上标记了@Transaction那么这个类就需要被代理,在方法调用时在具体判断方法是否需要事务。
image.png

public abstract class StaticMethodMatcherPointcut extends StaticMethodMatcher implements Pointcut {
	// 定义类过滤字段
    private ClassFilter classFilter = ClassFilter.TRUE;
}

abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
	protected TransactionAttributeSourcePointcut() {
		setClassFilter(new TransactionAttributeSourceClassFilter());
	}
    // 方法是否匹配
	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}
	// 获取事务属性,交给子类实现
	@Nullable
	protected abstract TransactionAttributeSource getTransactionAttributeSource();
	// 内部类实现的类过滤器
	private class TransactionAttributeSourceClassFilter implements ClassFilter {
		@Override
		public boolean matches(Class<?> clazz) {
            // 基础设施类忽略
			if (TransactionalProxy.class.isAssignableFrom(clazz) ||
					TransactionManager.class.isAssignableFrom(clazz) ||
					PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
				return false;
			}
            // 调用子类实现的获取事务属性
			TransactionAttributeSource tas = getTransactionAttributeSource();
			return (tas == null || tas.isCandidateClass(clazz));
		}
	}
}

在事务实现的Advisor中实现了具体的实现类

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    @Nullable
    private TransactionAttributeSource transactionAttributeSource;
    // 匿名内部类实现
    private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
        @Nullable
        protected TransactionAttributeSource getTransactionAttributeSource() {
            return BeanFactoryTransactionAttributeSourceAdvisor.this.transactionAttributeSource;
        }
    };
}

这里可以看出在IOC容器中BeanFactoryTransactionAttributeSourceAdvisor的bean中设置的TransactionAttributeSource就是获取事务属性的具体工具类,详细的分析我们在事务中再细细道来,参见事务桥接AOPTransactionAttributeSource

@annotation是一个切点表达式,它用于指定作用于方法上的注解。具体地说,当Spring扫描到带有该注解的方法时,切面通知就会被执行。在给定的引用内容中,@Pointcut("@annotation(com.test.aop.demo.MyAnnotation)")用于定义一个切点cutController(),它作用于使用@MyAnnotation注解的方法上。同样,@Pointcut("@within(com.test.aop.demo.MyAnnotation)")用于定义一个切点cutService(),它作用于被@MyAnnotation注解的类上。最后,@Pointcut("cutController() || cutService()")定义了一个切点cutAll(),它是cutController()和cutService()的逻辑或运算结果,即作用于使用@MyAnnotation注解的方法或被@MyAnnotation注解的类上。这些切点表达式使得我们可以在切面中选择性地应用通知,从而更灵活地控制切面的行为。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Spring Boot AOP @Pointcut拦截注解的表达式与运算符](https://blog.youkuaiyun.com/u011974797/article/details/130085645)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【Spring AOP】@Aspect结合案例详解(一): @Pointcut使用@annotation + 五种通知Advice注解(已附源码)](https://blog.youkuaiyun.com/scm_2008/article/details/128593857)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值