(造轮子)手写Spring框架-切点表达式

82 阅读1分钟

切点表达式

代码地址:WangChao-ly/chao-spring at pointcut-expression (github.com)

建议订阅博主专栏,从下到上系统手写spring源码,体会其中过程!

Joinpoint,织入点,指需要执行代理操作的某个类的某个方法(仅支持方法级别的JoinPoint);Pointcut是JoinPoint的表述方式,能捕获JoinPoint。

最常用的切点表达式是AspectJ的切点表达式。需要匹配类,定义ClassFilter接口;匹配方法,定义MethodMatcher接口。PointCut需要同时匹配类和方法,包含ClassFilter和MethodMatcher,AspectJExpressionPointcut是支持AspectJ切点表达式的PointCut实现,简单实现仅支持execution函数。


  1. ClassFilter:匹配类的接口
public interface ClassFilter {
    /**
     * 匹配类
     * @param clazz
     * @return
     */
    boolean matches(Class<?> clazz);
}
  1. MethodMatcher:匹配方法的接口
public interface MethodMatcher {
    /**
     * 方法匹配
     * @param method
     * @param targetClass
     * @return
     */
    boolean matches(Method method, Class<?> targetClass);
}
  1. PintCut:该接口是继承上面两个接口,既能匹配类,又能匹配方法
  2. AspectJExpressionPointcut:该接口是PointCut的实现类,通过aspectj包的方法,解析用户指定范围的类和方法进行匹配
public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {
    /**
     * 切面编程中支持的不同切点类型的枚举值或常量
     */
    private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<PointcutPrimitive>();
    static{
        SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
    }
    private final PointcutExpression pointcutExpression;

    public AspectJExpressionPointcut(String expression){
        //拿到pointcutParser
        PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES,this.getClass().getClassLoader());
        pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }
    @Override
    public boolean matches(Class<?> clazz) {
        return pointcutExpression.couldMatchJoinPointsInType(clazz);
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
    }

    @Override
    public ClassFilter getClassFilter() {
        return this;
    }

    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }
}
  1. 测试
public class PointcutExpressionTest {
    @Test
    public void testPointcutExpression() throws Exception {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut("execution(* org.springframework.test.service.HelloService.*(..))");
        Class<HelloService> clazz = HelloService.class;
        Method method = clazz.getDeclaredMethod("sayHello");

        //匹配类和方法
        Assert.isTrue(pointcut.matches(clazz));
        Assert.isTrue(pointcut.matches(method, clazz));
    }
}