SpringAOP

Spring 框架的 DI 技术

DI,即依赖注入,它是实现 IoC 的一种具体方式。通过 DI,Spring 框架能够将对象所依赖的组件精准地注入到对象中。

  1. DI 的基本概念 :在软件开发中,一个对象往往需要依赖其他对象来完成特定的功能。而 DI 就是在对象创建的过程中,由 Spring 框架自动将这些依赖的对象注入到目标对象中。这样一来,对象之间的依赖关系就变得清晰明了,便于后期的维护和扩展。

  2. DI 的注入方式 :Spring 框架提供了多种 DI 注入方式,包括属性的 set 方法注入、构造方法注入,以及对数组、集合等复杂数据类型的注入。在实际开发中,我们可以根据具体的需求和场景,灵活地选择合适的注入方式。

Spring 框架整合 JUnit

单元测试是软件开发过程中不可或缺的一环,它能够帮助我们及时发现代码中的问题,确保软件的质量。Spring 框架与 JUnit 的整合,为单元测试提供了极大的便利。

  1. 整合的意义 :在未整合之前,进行单元测试需要我们手动创建对象、配置环境等,过程繁琐且容易出错。而 Spring 框架与 JUnit 整合后,我们可以在测试类中直接注入所需的 Bean,无需再手动创建对象。这不仅提高了测试的效率,还使得测试环境更加贴近真实的运行环境。

  2. 整合的实现 :要实现 Spring 框架与 JUnit 的整合,我们只需在测试类上添加 @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration 注解。其中,@RunWith 注解指定了使用 Spring 提供的测试运行器,而 @ContextConfiguration 注解则用于加载 Spring 的配置文件。这样,在测试方法中,我们就可以直接使用 Spring 框架管理的对象,进行各种测试操作。

Spring 框架的事务管理

事务管理是企业级应用开发中一个至关重要的课题,它直接关系到数据的一致性和完整性。Spring 框架提供了简单易用的事务管理功能,帮助我们轻松应对这一挑战。

  1. 事务管理的重要性 :在实际的业务场景中,一个完整的业务操作往往涉及多个数据库操作步骤。如果这些操作不能保证原子性,即要么全部成功,要么全部失败,那么就可能导致数据的不一致。例如,在银行转账的场景中,如果从账户 A 扣款成功,但往账户 B 加款失败,那么就会造成资金的缺失。而 Spring 框架的事务管理功能,就能够确保这种情况下所有操作回滚,从而保证数据的一致性。

  2. 事务管理的配置 :Spring 框架支持多种事务管理方式,包括声明式事务和编程式事务。声明式事务通过简单的注解或配置来定义事务规则,无需编写额外的事务代码,适合大多数场景。而编程式事务则提供了更灵活的事务控制,适用于一些复杂的业务场景。通过合理配置事务的传播行为、隔离级别等参数,我们可以满足不同业务场景下的事务需求。

Spring 框架与数据库的交互

在企业级应用开发中,与数据库进行交互是一个常见的需求。Spring 框架提供了简洁而强大的 JDBC 模板(JdbcTemplate),极大地简化了数据库操作的复杂性。

  1. JDBC 模板的优势 :传统的 JDBC 操作往往涉及到大量的重复代码,如数据库连接的获取与关闭、SQL 语句的执行等。而 Spring 框架的 JDBC 模板则对这些繁琐的操作进行了封装,使得我们只需专注于 SQL 语句的编写和结果的处理。它不仅减少了代码量,还降低了出错的可能性,提高了开发效率。

  2. JDBC 模板的使用 :在使用 JDBC 模板时,我们首先需要配置数据源,以建立与数据库的连接。然后,通过创建 JdbcTemplate 对象,并将其与数据源关联起来,就可以开始执行各种数据库操作了。无论是简单的增删改查,还是复杂的批量操作,JDBC 模板都能轻松应对。

Spring 框架的注解开发

注解是 Java 5 引入的新特性,它在 Spring 框架中得到了广泛的应用。通过注解,我们可以用更加简洁直观的方式完成许多配置工作,使代码更具可读性和可维护性。

  1. 注解的作用 :在 Spring 框架中,注解可用于定义 Bean、注入依赖、配置事务等多种场景。与传统的 XML 配置方式相比,注解方式更加简洁明了,减少了大量的配置文件编写工作。同时,注解直接写在代码中,使得开发者的意图更加清晰地表达出来,便于其他开发者阅读和理解。

  2. 常用注解介绍 :在 Spring 框架中,有许多常用的注解,如 @Component@Service@Repository@Controller 等,它们分别用于标识不同的组件类型。此外,还有 @Autowired@Resource 等注解,用于实现依赖注入;@Transactional 注解,用于配置事务等。这些注解各司其职,共同构成了 Spring 框架注解开发的强大体系。

Spring 框架的组件扫描

组件扫描是 Spring 框架的一项重要功能,它能够自动扫描指定包及其子包下的类,发现其中带有特定注解的类,并将其作为 Spring 管理的 Bean。

  1. 组件扫描的意义 :在大型项目中,手动配置每一个 Bean 是一项繁琐且容易出错的任务。而组件扫描的出现,使得我们可以自动地将带有注解的类纳入 Spring 框架的管理范围,大大提高了开发的效率,同时也减少了配置错误的可能性。

  2. 组件扫描的配置 :要启用组件扫描,我们只需在 Spring 的配置文件中添加 <context:component-scan> 标签,并指定要扫描的包路径。或者,也可以通过注解的方式,在配置类上使用 @ComponentScan 注解来实现组件扫描。Spring 框架会自动扫描指定包下的类,对于带有 @Component 等注解的类,自动创建对应的 Bean,并将其添加到 Spring 容器中。

Spring 框架的配置类

配置类是 Spring 框架纯注解开发的核心,它替代了传统的 XML 配置文件,使得整个开发过程更加简洁、灵活。

  1. 配置类的作用 :在纯注解开发模式下,配置类用于定义各种 Bean、配置事务管理器、数据源等。通过在配置类上使用 @Configuration 注解,我们告诉 Spring 框架这是一个配置类。然后,在类内部通过使用 @Bean 注解的方法,来创建和配置各种 Bean。这种方式不仅避免了繁琐的 XML 配置文件,还使得代码的结构更加清晰,便于管理和维护。

  2. 配置类的编写 :在编写配置类时,我们通常会结合 @ComponentScan 注解来启用组件扫描,自动发现项目中的其他组件。此外,还可以通过 @Import 注解来导入其他配置类,实现配置的模块化和复用。对于一些复杂的配置,如数据源的配置、事务管理器的配置等,我们可以在配置类中以方法的形式进行定义,并通过 @Bean 注解将其添加到 Spring 容器中。

Spring 框架的实际案例

为了更加深入地理解 Spring 框架的应用,让我们来看一个实际的案例 ------ 转账业务的实现。

  1. 案例背景 :假设有一个银行转账系统,用户 A 需要向用户 B 转账一定金额。这个过程中,需要完成从 A 账户扣款、向 B 账户加款两个关键步骤。并且,为了保证数据的一致性,这两个步骤必须在一个事务中完成。

  2. 案例实现 :在实现该案例时,我们首先定义了一个 AccountDao 接口,用于封装与数据库交互的方法,如扣款(outMoney)和加款(inMoney)。然后,我们创建了 AccountDaoImpl 实现类,通过继承 JdbcDaoSupport 类,利用 Spring 框架的 JDBC 模板来实现具体的数据库操作。接着,我们定义了 AccountService 接口,并在 AccountServiceImpl 实现类中,调用 AccountDao 的方法来完成转账的业务逻辑。为了确保事务的一致性,我们在 AccountServiceImpl 类上使用了 @Transactional 注解来配置事务。最后,通过编写测试类,使用 Spring 框架与 JUnit 整合的方式,对转账功能进行测试。

以下是关键的代码部分:

数据库表结构创建代码(SQL)

复制代码
create database spring_db;
use spring_db;
create table account(
    id int primary key auto_increment,
    name varchar(40),
    money double
)character set utf8 collate utf8_general_ci;
insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);

实体类 Account.java

复制代码
package com.qcby.model;

public class Account {
    private Integer id;
    private String name;
    private Double money;

    public Account() {
    }

    public Account(Integer id, String name, Double money) {
        this.id = id;
        this.name = name;
        this.money = money;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

AccountDao 接口(AccountDao.java)

复制代码
package com.qcby.test.Demo3;

public interface AccountDao {
    public void outMoney(String out, double money);

    public void inMoney(String in, double money);
}

AccountDaoImpl 实现类(AccountDaoImpl.java)

复制代码
package com.qcby.test.Demo3;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {

    @Override
    public void outMoney(String out, double money) {
        this.getJdbcTemplate().update("UPDATE account SET money = money - ? WHERE name = ?", money, out);
    }

    @Override
    public void inMoney(String in, double money) {
        this.getJdbcTemplate().update("UPDATE account SET money = money + ? WHERE name = ?", money, in);
    }
}

AccountService 接口(AccountService.java)

复制代码
package com.qcby.test.Demo2;

public interface AccountService {
    public void pay(String out, String in, double money);
}

AccountServiceImpl 实现类(AccountServiceImpl.java)

复制代码
package com.qcby.test.Demo4;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(isolation = Isolation.DEFAULT)
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountDao accountDao;

    @Override
    public void pay(String out, String in, double money) {
        accountDao.outMoney(out, money);
        int a = 1 / 0;  // 故意制造错误,用于测试事务回滚
        accountDao.inMoney(in, money);
    }

    public void setAccountDao(AccountDaoImpl accountDao) {
        this.accountDao = accountDao;
    }
}

测试类 Demo4.java

复制代码
package com.qcby.test.Demo4;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:applicationContext.xml")
public class Demo4 {

    @Autowired
    private AccountService accountService;

    @Test
    public void testPay() {
        accountService.pay("aaa", "bbb", 100);
    }
}
相关推荐
忆~遂愿3 分钟前
GE 引擎进阶:依赖图的原子性管理与异构算子协作调度
java·开发语言·人工智能
MZ_ZXD0017 分钟前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·vue.js·spring boot·python·django·php
PP东10 分钟前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
ManThink Technology15 分钟前
如何使用EBHelper 简化EdgeBus的代码编写?
java·前端·网络
invicinble19 分钟前
springboot的核心实现机制原理
java·spring boot·后端
Goat恶霸詹姆斯24 分钟前
mysql常用语句
数据库·mysql·oracle
人道领域27 分钟前
SSM框架从入门到入土(AOP面向切面编程)
java·开发语言
大模型玩家七七1 小时前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习
曾经的三心草1 小时前
redis-9-哨兵
数据库·redis·bootstrap
明哥说编程1 小时前
Dataverse自定义表查询优化:D365集成大数据量提速实战【索引配置】
数据库·查询优化·dataverse·dataverse自定义表·索引配置·d365集成·大数据量提速