手写Spring框架之AOP

本文将详细讲解如何从头开始手写Spring框架的AOP功能和事务管理。首先回顾Spring AOP和动态代理的基础知识,然后逐步构建切面注解、代理框架,包括Proxy接口、ProxyChain类、AspectProxy类、ProxyFactory类和AopHelper助手类。接着展示AOP的实际应用,创建一个监控接口性能的切面。最后,实现事务管理,通过DatabaseHelper和TransactionProxy类完成事务的开启、提交和回滚。文章最后给出了全部功能实现后的总结。

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

简介

手写Spring框架第一篇博客(必读): 手写Spring框架

前面两篇博客已经实现了Bean容器, IOC功能和MVC功能, 本篇博客来实现AOP功能和事务管理. 在看下面的内容之前, 一定要先回顾下Spring AOP和动态代理.

Spring AOP

动态代理

handwritten-mvc-framwork 实现

定义注解

(1) 切面注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {
    /**
     * 包名
     */
    String pkg() default "";

    /**
     * 类名
     */
    String cls() default "";
}

(2) 事务注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
}

搭建代理框架

毫无疑问这个代理框架是基于动态代理实现的, 但加了一个链式代理的功能, 目的是为了解决多重代理的问题, 也就是目标对象的方法被多次增强.

(1) Proxy接口

我们自定义了一个最上层的代理接口, 其中doProxy()执行的是链式代理, 具体详情可以看后面的介绍.

public interface Proxy {

    /**
     * 执行链式代理
     * 所谓链式代理, 就是说, 可将多个代理通过一条链子串起来, 一个个地去执行, 执行顺序取决于添加到链上的先后顺序
     */
    Object doProxy(ProxyChain proxyChain) throws Throwable;
}

(2) ProxyChain类

这是一个代理链类, proxyList 存储的是代理列表(也就是增强列表), 当执行doProxyChain() 方法时会按照顺序执行增强, 最后再执行目标方法.

public class ProxyChain {

    private final Class<?> targetClass; //目标类
    private final Object targetObject; //目标对象
    private final Method targetMethod; //目标方法
    private final MethodProxy methodProxy; //方法代理
    private final Object[] methodParams; //方法参数

    private List<Proxy> proxyList = new ArrayList<>(); //代理列表
    private int proxyIndex = 0; //代理索引

    public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) {
        this.targetClass = targetClass;
        this.targetObject = targetObject;
        this.targetMethod = targetMethod;
        this.methodProxy = methodProxy;
        this.methodParams = methodParams;
        this.proxyList = proxyList;
    }

    public Object[] getMethodParams() {
        return methodParams;
    }

    public Class<?> getTargetClass() {
        return targetClass;
    }

    public Method getTargetMethod() {
        return targetMethod;
    }

    /**
     * 递归执行
     */
    public Object doProxyChain() throws Throwable {
        Object methodResult;
        if (proxyIndex < proxyList.size()) {
            //执行增强方法
            methodResult = proxyList.get(proxyIndex++).doProxy(this);
        } else {
            //目标方法最后执行且只执行一次
            methodResult = methodProxy.invokeSuper(targetObject, methodParams);
        }
        return methodResult;
    }
}

(3) AspectProxy类

AspectProxy是一个切面抽象类, 实现了Proxy接口, 类中定义了切入点判断和各种增强. 当执行 doProxy() 方法时, 会先进行切入点判断, 再执行前置增强, 代理链的下一个doProxyChain()方法, 后置增强等.

public abstract class AspectProxy implements Proxy {

    private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class);

    @Override
    public final Object doProxy(ProxyChain proxyChain) throws Throwable {
        Object result = null;

        Class<?> cls = proxyChain.getTargetClass();
        Method method = proxyChain.getTargetMethod();
        Object[] params = proxyChain.getMethodParams();

        begin();
        try {
            if (intercept(method, params)) {
                before(method, params);
                result = proxyChain.doProxyChain();
                after(method, params);
            } else {
                result = proxyChain.doProxyChain();
            }
        } catch (Exception e) {
            logger.error("proxy failure", e);
            error(method, params, e);
            throw e;
        } finally {
            end();
        }

        return result;
    }

    /**
     * 开始增强
     */
    public void begin() {
    }

    /**
     * 切入点判断
     */
    public boolean intercept(Method method, Object[] params) throws Throwable {
        return true;
    }

    /**
     * 前置增强
     */
    public void before(Method method, Object[] params) throws Throwable {
    }

    /**
     * 后置增强
     */
    public void after(Method method, Object[] params) throws Throwable {
    }

    /**
     * 异常增强
     */
    public void error(Method method, Object[] params, Throwable e) {
    }

    /**
     * 最终增强
     */
    public void end() {
    }
}

(4) ProxyFactory类

这是一个代理工厂类, 我们通过这个类来梳理上面的代理逻辑. 当调用 ProxyFactory.createProxy(final Class<?> targetClass, final List proxyList) 方法来创建一个代理对象后, 每次执行代理方法时都会调用 intercept() 方法, 从而创建一个 ProxyChain 对象, 并调用该对象的 doProxyChain() 方法. 调用doProxyChain()方法时会首先递归的执行增强, 最后再执行目标方法.

public class ProxyFactory {

    /**
     * 输入一个目标类和一组Proxy接口实现, 输出一个代理对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T createProxy(final Class<?> targetClass, final List<Proxy> proxyList) {
        return (T) Enhancer.create(targetClass, new MethodInterceptor() {
            /**
             * 代理方法, 每次调用目标方法时都会先创建一个 ProxyChain 对象, 然后调用该对象的 doProxyChain() 方法.
             */
            @Override
            public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
                return new ProxyChain(targetClass, targetObject, targetMethod, methodProxy, methodParams, proxyList).doProxyChain();
            }
        });
    }
}

(5) AopHelper 助手类

AopHelper 助手类用来初始化整个AOP框架, 逻辑如下:

框架中所有Bean的实例都是从Bean容器中获取, 然后再执行该实例的方法, 基于此, 初始化AOP框架实际上就是用代理对象覆盖

评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值