手写Spring框架-肆

前言

前面已经实现了ioc部分,本章开始来实现AOP内容
AOP 意为:面向切面编程,通过预编译的方式和运行期间动态代理实现程序功能功能的统一维护。
其实AOP也是 OOP 的延续,在 Spring 框架中是一个非常重要的内容,使用 AOP 可以对业务逻辑的各个部分进行隔离,从而使各模块间的业务逻辑耦合度降低,提高代码的可复用性,同时也能提高开发效率。
关于 AOP 的核心技术实现主要是动态代理的使用,就像你可以给一个接口的实现类,使用代理的方式替换掉这个实现类,使用代理类来处理你需要的逻辑。比如:

    @Test
    public void test_aop() throws NoSuchMethodException {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut("execution(* com.wtx.springframework.test.bean.UserService.*(..))");
        Class<UserService> clazz = UserService.class;
        Method method = clazz.getDeclaredMethod("queryUserInfo");

        System.out.println(pointcut.matches(clazz));
        System.out.println(pointcut.matches(method, clazz));

        // true、true
    }

代理类的实现基本都大家都见过,那么有了一个基本的思路后,接下来就需要考虑下怎么给方法做代理呢,而不是代理类。另外怎么去代理所有符合某些规则的所有类中方法呢。如果可以代理掉所有类的方法,就可以做一个方法拦截器,给所有被代理的方法添加上一些自定义处理,比如打印日志、记录耗时、监控异常等。

正文

定义切入点接口

用来定义哪些类或者哪些方法需要增强

public interface Pointcut {
    ClassFilter getClassFilter();

    MethodMatcher getMethodMatcher();
}

定义类匹配接口

用于类层面,过滤哪些类

public interface ClassFilter {
    boolean matches(Class<?> clazz);
}

定义方法匹配接口

public interface MethodMatcher {
    boolean matches(Method method, Class<?> targetClass);
}

定义切点表达式

实现了Pointcut, ClassFilter, MethodMatcher,意味着我自己既能当切点,也能当类过滤器和方法匹配器

public class AspectJExpressionPointcut implements Pointcut, ClassFilter, MethodMatcher {
    private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();

    private final PointcutExpression pointcutExpression;


    static {
        SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
    }

    public AspectJExpressionPointcut(String expression) {
        PointcutParser pointcutParser = PointcutParser.getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
        this.pointcutExpression = pointcutParser.parsePointcutExpression(expression);
    }

    @Override
    public boolean matches(Class<?> clazz) {
        return this.pointcutExpression.couldMatchJoinPointsInType(clazz);
    }

    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        //alwaysMatches() 就是直接返回布尔值结果:完全匹配返回 true。
        return this.pointcutExpression.matchesMethodExecution(method).alwaysMatches();
    }

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

    @Override
    public MethodMatcher getMethodMatcher() {
        return this;
    }
}

定义切面信息包装类

  • AdvisedSupport,主要是用于把代理、拦截、匹配的各项属性包装到一个类中,方便在 Proxy 实现类进行使用。这和你的业务开发中包装入参是一个道理
  • TargetSource,是一个目标对象,在目标对象类中提供 Object 入参属性,以及获取目标类 TargetClass 信息。
  • MethodInterceptor,是一个具体拦截方法实现类,由用户自己实现 MethodInterceptor#invoke 方法,做具体的处理。像我们本文的案例中是做方法监控处理
@Data
public class AdvisedSupport {
    private TargetSource targetSource;

    private MethodInterceptor methodInterceptor;

    private MethodMatcher methodMatcher;
}

定义AOP代理类

定义一个标准接口,用于获取代理类。因为具体实现代理的方式可以有 JDK 方式,也可以是 Cglib 方式,所以定义接口会更加方便管理实现类。

public interface AopProxy {
    Object getProxy();
}

基于 JDK 实现的代理类

public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
    private final AdvisedSupport advisedSupport;

    public JdkDynamicAopProxy(AdvisedSupport advisedSupport) {
        this.advisedSupport = advisedSupport;
    }

    @Override
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), this.advisedSupport.getTargetSource().getTargetClass(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(this.advisedSupport.getMethodMatcher().matches(method, this.advisedSupport.getTargetSource().getTarget().getClass())){
            MethodInterceptor methodInterceptor = this.advisedSupport.getMethodInterceptor();
            return methodInterceptor.invoke(new ReflectiveMethodInvocation(this.advisedSupport.getTargetSource().getTarget(), method, args));
        }
        return method.invoke(this.advisedSupport.getTargetSource().getTarget(), args);
    }
}

入参信息包装

public class ReflectiveMethodInvocation implements MethodInvocation {
    // 目标对象
    protected final Object target;
    // 方法
    protected final Method method;
    // 入参
    protected final Object[] arguments;

    public ReflectiveMethodInvocation(Object target, Method method, Object[] arguments) {
        this.target = target;
        this.method = method;
        this.arguments = arguments;
    }

    @Override
    public Method getMethod() {
        return this.method;
    }

    @Override
    public Object[] getArguments() {
        return this.arguments;
    }

    @Override
    public Object proceed() throws Throwable {
        return this.method.invoke(target, arguments);
    }

    @Override
    public Object getThis() {
        return this.target;
    }

    @Override
    public AccessibleObject getStaticPart() {
        return this.method;
    }
}

基于Cglib实现的代理类

public class Cglib2AopProxy implements AopProxy{
    private final AdvisedSupport advisedSupport;

    public Cglib2AopProxy(AdvisedSupport advisedSupport) {
        this.advisedSupport = advisedSupport;
    }

    @Override
    public Object getProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.advisedSupport.getTargetSource().getTarget().getClass());
        enhancer.setInterfaces(this.advisedSupport.getTargetSource().getTargetClass());
        enhancer.setCallback(new DynamicAdvisedInterceptor(this.advisedSupport));
        return enhancer.create();
    }

    private static class DynamicAdvisedInterceptor implements MethodInterceptor {

        private final AdvisedSupport advised;

        public DynamicAdvisedInterceptor(AdvisedSupport advised) {
            this.advised = advised;
        }

        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, objects, methodProxy);
            if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
                return advised.getMethodInterceptor().invoke(methodInvocation);
            }
            return methodInvocation.proceed();
        }
    }

    private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

        private final MethodProxy methodProxy;

        public CglibMethodInvocation(Object target, Method method, Object[] arguments, MethodProxy methodProxy) {
            super(target, method, arguments);
            this.methodProxy = methodProxy;
        }

        @Override
        public Object proceed() throws Throwable {
            return this.methodProxy.invoke(this.target, this.arguments);
        }

    }
}

基于 Cglib 使用 Enhancer 代理的类可以在运行期间为接口使用底层 ASM 字节码增强技术处理对象的代理对象生成,因此被代理类不需要实现任何接口。

posted @ 2025-09-04 16:18  忧伤丶情语  阅读(5)  评论(0)    收藏  举报