首页 > 基础资料 博客日记

Java-28 深入浅出 Spring - 实现简易Ioc-04 在上节的业务下手动实现AOP

2025-01-14 12:30:12基础资料围观31

Java资料网推荐Java-28 深入浅出 Spring - 实现简易Ioc-04 在上节的业务下手动实现AOP这篇文章给大家,欢迎收藏Java资料网享受知识的乐趣

点一下关注吧!!!非常感谢!!持续更新!!!

大数据篇正在更新!https://blog.csdn.net/w776341482/category_12713819.html

目前已经更新到了:

  • MyBatis(已更完)
  • Spring(正在更新…)

AOP 实现

注意,这里的 AOP 还不具备扩展能力,只是一个简易的实现,帮助我们更好的实现对事务的控制。

AOP(面向切面编程)

AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它通过分离关注点来提高代码的模块化,尤其是与横切关注点(cross-cutting concerns)相关的功能。这些横切关注点是指那些与业务逻辑并非直接相关,但却需要跨越多个模块的功能,如日志记录、安全验证、事务管理等。AOP 通过提供一种方式来将这些横切关注点与业务逻辑分离,进而增强代码的复用性和可维护性。

AOP的核心概念

AOP 的工作方式与 OOP(面向对象编程)有所不同,OOP 强调的是对象的定义和封装,而 AOP 强调的是如何把程序的不同功能切分成不同的模块。AOP 的关键概念主要包括以下几个:

切面(Aspect)

切面是 AOP 中最重要的概念,它是对某个横切关注点的模块化。一个切面定义了一个与核心业务逻辑无关的功能(例如,日志记录、性能监控等),并把这些功能应用到程序的各个部分。切面可以包含多个通知和切点。

连接点(Joinpoint)

连接点指的是程序中能够插入切面的地方,通常是方法调用、方法执行、异常抛出等。连接点表示了在程序的某个执行点插入切面逻辑的机会。在 Java 中,连接点通常是一个方法调用。

通知(Advice)

通知是切面在连接点上执行的具体行为或操作。通知有不同的类型,例如:
前置通知(Before):在目标方法执行前执行。
后置通知(After):在目标方法执行后执行,不管方法是成功还是失败。
环绕通知(Around):在目标方法执行前后都可以控制,甚至可以选择是否调用目标方法。
异常通知(Throws):在目标方法抛出异常后执行。
返回通知(AfterReturning):在目标方法正常返回后执行。

切点(Pointcut)

切点是一个定义了通知执行位置的表达式,它指定了哪些连接点需要被拦截。切点通常是基于方法签名、注解、执行路径等条件来匹配的。切点用于选择需要应用通知的连接点。

织入(Weaving)

织入是将切面应用到目标对象的过程。这个过程可以在编译时、类加载时或运行时进行。织入的方式决定了 AOP 实现的具体方式。常见的 AOP 织入方式有:

  • 编译时织入:在源代码编译时完成切面的织入(例如使用 AspectJ 编译器)。
  • 类加载时织入:在类加载过程中通过修改字节码来完成织入。
  • 运行时织入:在程序运行时通过代理等方式完成织入(Spring AOP)。

Resources

<?xml version="1.0" encoding="UTF-8" ?>
<!-- BeanFactory 类会进行处理这块内容 -->
<beans>
    <!-- WzkConnectionUtils 交给容器管理 -->
    <bean id="wzkConnectionUtils" class="wzk.utils.WzkConnectionUtils"></bean>
    <!-- 依赖了工具类 WzkConnectionUtils -->
    <!-- id 是放入到容器中的名称 -->
    <bean id="wzkAccountDao" class="wzk.dao.impl.JdbcWzkAccountDaoImpl">
        <!-- name是成员变量名字 ref是引用从容器中拿对象 -->
        <property name="WzkConnectionUtils" ref="wzkConnectionUtils"/>
    </bean>
    <!-- 依赖了 WzkAccountDao -->
    <bean id="wzkTransferService" class="wzk.service.impl.WzkTransferServiceImpl">
        <!-- name是成员变量名字 ref是引用从容器中拿对象 -->
        <property name="WzkAccountDao" ref="wzkAccountDao"></property>
    </bean>
    <!-- WzkTransactionManager 依赖了 WzkConnectionUtils -->
    <bean id="wzkTransactionManager" class="wzk.utils.WzkTransactionManager">
        <property name="WzkConnectionUtils" ref="wzkConnectionUtils"></property>
    </bean>
    <!-- ProxyFactory 依赖了 WzkTransactionManager -->
    <bean id="proxyFactory" class="wzk.factory.ProxyFactory">
        <property name="WzkTransactionManager" ref="wzkTransactionManager"></property>
    </bean>
</beans>

对应的截图如下所示:

WzkTransactionManager

编写:事务控制器

/**
 * 事务的控制器 这里只是对 JDBC 等操作的简单封装
 * @author wzk
 * @date 11:31 2024/11/19
**/
public class WzkTransactionManager {

    private WzkConnectionUtils wzkConnectionUtils;

    public void setWzkConnectionUtils(WzkConnectionUtils wzkConnectionUtils) {
        this.wzkConnectionUtils = wzkConnectionUtils;
    }

    public void beginTransaction() throws SQLException {
        wzkConnectionUtils.getCurrentConnection().setAutoCommit(false);
    }

    public void commit() throws SQLException {
        wzkConnectionUtils.getCurrentConnection().commit();
    }

    public void rollback() throws SQLException {
        wzkConnectionUtils.getCurrentConnection().rollback();
    }

}

对应的截图如下所示:

Proxy

ProxyFactory

代理的工厂具体实现如下:

/**
 * 代理工厂 + 单例模式
 * 参考代理设计模式 实现事务的控制
 * 这里主要实现的是动态代理的方式
 * @author wzk
 * @date 11:33 2024/11/19
**/
public class ProxyFactory {

    private WzkTransactionManager wzkTransactionManager;

    public void setWzkTransactionManager(WzkTransactionManager wzkTransactionManager) {
        this.wzkTransactionManager = wzkTransactionManager;
    }

    /**
     * 动态代理-JDK的实现
     * @author wzk
     * @date 11:35 2024/11/19
    **/
    public Object getJdkProxy(Object object) {
        return Proxy.newProxyInstance(
                object.getClass().getClassLoader(),
                object.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object result;
                        // 开启事务
                        wzkTransactionManager.beginTransaction();
                        // 执行原来的方法
                        try {
                            result = method.invoke(object, args);
                        } catch (Exception e) {
                            // 回滚
                            wzkTransactionManager.rollback();
                            throw e;
                        }
                        // 提交事务
                        wzkTransactionManager.commit();
                        return result;
                    }
                }
        );
    }

    /**
     * 动态代理-CGLIB的实现
     * @author wzk
     * @date 13:57 2024/11/19
    **/
    public Object getCglibProxy(String object) {
        return Enhancer.create(
                object.getClass(),
                new MethodInterceptor() {
                    @Override
                    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                        Object result;
                        wzkTransactionManager.beginTransaction();
                        try {
                            result = method.invoke(object, args);
                        } catch (Exception e) {
                            wzkTransactionManager.rollback();
                            throw e;
                        }
                        wzkTransactionManager.commit();
                        return result;
                    }
                }
        );
    }
}

对应的截图如下如下:

Controller

WzkServlet

代码可能有点长,本来考虑复制片段,但是考虑到全局,不然大家看的比较晕,所以都复制过来了。

@WebServlet(name="wzkServlet", urlPatterns = "/wzkServlet")
public class WzkServlet extends HttpServlet {

    // ========================== 2 ==========================
    // 由 BeanFactory 处理
    // private WzkTransferService wzkTransferService = (WzkTransferService) BeanFactory.getBean("wzkTransferService");
    // =======================================================

    // ========================== 3 ==========================
    // 另一种方式 相同的
    // private WzkTransferService wzkTransferService;
    // @Override
    // public void init() throws ServletException {
    //    super.init();
    //    this.wzkTransferService = (WzkTransferService) BeanFactory.getBean("wzkTransferService");
    // }
    // ======================================================

    // ================== 4 ======================
    // 获取代理的对象 有事务 AOP 加持的
    private WzkTransferService wzkTransferService;

    @Override
    public void init() throws ServletException {
        super.init();
        // 从BeanFactory中国拿到代理工厂ProxyFactory 可以对某个类进行代理扩展
        // 这里扩展的功能点:事务提交与回滚
        ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
        this.wzkTransferService = (WzkTransferService) proxyFactory.getJdkProxy(
                BeanFactory.getBean("wzkTransferService"));
    }
    // ===========================================

    @Override
    protected void doGet(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse resp) throws javax.servlet.ServletException, IOException {
        System.out.println("=== WzkServlet doGet ===");
        // ======================= 1 =============================
        // 由于没有 Spring 的帮助 我们就需要手动去创建和维护依赖之间的关系
        // 组装 DAO DAO层依赖于 ConnectionUtils 和 DruidUtils
        // JdbcWzkAccountDaoImpl jdbcWzkAccountDaoImpl = new JdbcWzkAccountDaoImpl();
        // jdbcWzkAccountDaoImpl.setConnectionUtils(new WzkConnectionUtils());
        // 组装 Service
        // WzkTransferServiceImpl wzkTransferService = new WzkTransferServiceImpl();
        // wzkTransferService.setWzkAccountDao(jdbcWzkAccountDaoImpl);
        // ======================================================
        // 执行业务逻辑
        System.out.println("wzkTransferService: " + wzkTransferService);
        try {
            wzkTransferService.transfer("1", "2", 100);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("=== transfer error ====");
        }
        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().print("=== WzkServlet doGet ===");
    }

}

对应的截图如下所示:

测试运行1

启动项目进行测试,这里测试顺利执行的情况。
对应的截图如下所示,可以看到顺利的执行了:

对应的数据库的处理也是可以的:

测试运行2

这里测试,当运行过程中出现问题,需要进行回滚的情况。
我们需要在 impl 里 WzkTransferServiceImpl 的 transfer 代码中,随便加入一个异常,比如 用 1 除以 0 这种。

@Override
    public void transfer(String fromCard, String toCard, int money) throws Exception {
        WzkAccount from = wzkAccountDao.selectWzkAccount(fromCard);
        WzkAccount to = wzkAccountDao.selectWzkAccount(toCard);
        from.setMoney(from.getMoney() - money);
        to.setMoney(to.getMoney() + money);
        int fromResult = wzkAccountDao.updateWzkAccount(from);

        // 故意制造异常
        int i = 1 / 0;
        
        int toResult = wzkAccountDao.updateWzkAccount(to);
        System.out.println("transfer fromResult: " + fromResult + " toResult: " + toResult);
    }

对应的代码截图如下所示,此时执行之后,数据库的数据应该是不会变化才对(因为事务管理器回滚了):

对应的结果如下所示,可以看到确实是报错了:

数据库的数据如下所示:


文章来源:https://blog.csdn.net/w776341482/article/details/144530222
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云