无 IoC 无 AOP

在没有 Spring 的情况下,我们先手动实现业务上的逻辑,并且分层:

  • DAO
  • Service
  • Controller

IoC(Inversion of Control,控制反转)简介

控制反转(IoC)是一种设计原则,用于实现组件间的解耦,是面向对象编程中非常重要的概念之一。IoC的核心思想是将程序中对对象的控制权从调用方转移到框架或容器中,使得对象之间的依赖关系由容器来管理。


IoC 的特点

解耦

IoC通过将依赖的管理和创建责任交给容器,减少了模块之间的耦合性,增强了系统的可维护性和可扩展性。

动态依赖管理

容器根据配置或注解动态地将依赖注入到对象中,而不需要硬编码的依赖关系。

灵活性

对象的依赖可以在运行时动态修改,只需更改配置即可,不需要修改代码。


IoC 的应用场景

IoC被广泛应用于各种软件开发框架和项目中,以下是几个典型应用:

  • Spring Framework:Spring框架使用IoC容器管理Bean的生命周期和依赖关系
  • Guice 和 Dagger:轻量级DI框架
  • 前端框架(如Angular):通过依赖注入系统来管理组件和服务之间的依赖关系

IoC 的优势

  • 增强模块化:通过减少模块之间的直接依赖,促进模块化设计
  • 提高测试性:依赖注入可以方便地替换依赖对象,从而支持单元测试
  • 增强灵活性:通过配置或注解动态注入依赖
  • 便于维护:解耦使得系统在增加或修改功能时影响最小

IoC 的限制

  • 学习曲线:初学者需要一定时间理解IoC和DI的概念
  • 运行时性能开销:IoC容器在运行时解析依赖关系可能会引入一些性能开销
  • 复杂性:在大型项目中,过度使用IoC可能导致配置和依赖关系变得复杂

Utils

WzkDruidUtils

/**
 * Druid 工具类
 * 这里用到了单例设计模式、静态代码块初始化
 * @author wzk
 * @date 16:38 2024/11/18
 **/
public class WzkDruidUtils {

    private static DruidDataSource druidDataSource = new DruidDataSource();

    static {
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://172.16.1.130:3306/wzk-mybatis");
        druidDataSource.setUsername("hive");
        druidDataSource.setPassword("hive@wzk.icu");
    }

    private WzkDruidUtils() {

    }

    public static DruidDataSource getInstance() {
        return druidDataSource;
    }
}

WzkConnectionUtils

/**
 * 当前线程SQL 链接器
 * 通过 ThreadLocal 的方式 对 connection 进行传递
 * @author wzk
 * @date 16:43 2024/11/18
 **/
public class WzkConnectionUtils {

    private final ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    public Connection getCurrentConnection() throws SQLException {
        Connection connection = threadLocal.get();
        if (null == connection) {
            connection = WzkDruidUtils.getInstance().getConnection();
            threadLocal.set(connection);
        }
        return connection;
    }
}

DAO层

WzkAccountDao

package wzk.dao;

import wzk.model.WzkAccount;

public interface WzkAccountDao {

    WzkAccount selectWzkAccount(String card) throws Exception;

    int updateWzkAccount(WzkAccount wzkAccount) throws Exception;

}

JdbcWzkAccountDaoImpl

public class JdbcWzkAccountDaoImpl implements WzkAccountDao {

    private WzkConnectionUtils wzkConnectionUtils;

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


    @Override
    public WzkAccount selectWzkAccount(String card) throws Exception {
        Connection connection = wzkConnectionUtils.getCurrentConnection();
        String sql = "select * from wzk_account where card = ? limit 1";
        PreparedStatement prepareStatement = connection.prepareStatement(sql);
        prepareStatement.setString(1, card);
        ResultSet resultSet = prepareStatement.executeQuery();
        WzkAccount wzkAccount = new WzkAccount();
        while (resultSet.next()) {
            wzkAccount.setCard(resultSet.getString("card"));
            wzkAccount.setName(resultSet.getString("name"));
            wzkAccount.setMoney(resultSet.getInt("money"));
        }
        resultSet.close();
        prepareStatement.close();
        return wzkAccount;
    }

    @Override
    public int updateWzkAccount(WzkAccount wzkAccount) throws Exception {
        Connection connection = wzkConnectionUtils.getCurrentConnection();
        String sql = "update wzk_account set money =? where card =?";
        PreparedStatement prepareStatement = connection.prepareStatement(sql);
        prepareStatement.setInt(1, wzkAccount.getMoney());
        prepareStatement.setString(2, wzkAccount.getCard());
        int result = prepareStatement.executeUpdate();
        prepareStatement.close();
        return result;
    }
}

Service层

WzkTransferService

package wzk.service;

public interface WzkTransferService {

    void transfer(String fromCard, String toCard, int money) throws Exception;

}

WzkTransferServiceImpl

public class WzkTransferServiceImpl implements WzkTransferService {

    private WzkAccountDao wzkAccountDao;

    public void setWzkAccountDao(WzkAccountDao wzkAccountDao) {
        this.wzkAccountDao = wzkAccountDao;
    }


    @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 toResult = wzkAccountDao.updateWzkAccount(to);
        System.out.println("transfer fromResult: " + fromResult + " toResult: " + toResult);
    }
}

Controller 层

WzkServlet

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

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("=== WzkServlet doGet ===");

        // 由于没有 Spring 的帮助 我们就需要手动去创建和维护依赖之间的关系
        // 组装 DAO DAO层依赖于 ConnectionUtils 和 DruidUtils
        JdbcWzkAccountDaoImpl jdbcWzkAccountDaoImpl = new JdbcWzkAccountDaoImpl();
        jdbcWzkAccountDaoImpl.setConnectionUtils(new WzkConnectionUtils());

        // 组装 Service
        WzkTransferServiceImpl wzkTransferService = new WzkTransferServiceImpl();
        wzkTransferService.setWzkAccountDao(jdbcWzkAccountDaoImpl);

        // 执行业务逻辑
        try {
            wzkTransferService.transfer("1", "2", 100);
        } catch (Exception e) {
            System.out.println("=== transfer error ====");
        }

        resp.setContentType("application/json;charset=utf-8");
        resp.getWriter().print("=== WzkServlet doGet ===");
    }

}

测试运行

启动服务,在浏览器或者Postman中访问URL:

http://localhost:8999/wzkServlet

在无IoC与AOP的场景下,我们需要手动创建和维护依赖关系,这体现了IoC的核心价值——将对象创建和依赖管理的控制权从应用代码转移到容器中。