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);
    }
}
相关推荐
昔我往昔8 分钟前
除了GC哪些地方有用到安全点
java·jvm·安全
wxin_VXbishe9 分钟前
springboot旅游小程序-计算机毕业设计源码76696
java·spring boot·python·spring·django·sqlite·flask
我是Superman丶22 分钟前
【Lua】java 调用redis执行 lua脚本
java·开发语言·junit
素雪风华27 分钟前
构建RAG混合开发---PythonAI+JavaEE+Vue.js前端的实践
java·vue.js·python·ai·语言模型·llms·qwen千问大模型
zm36 分钟前
服务器连接多客户端
java·javascript·算法
残花月伴1 小时前
springCloud/Alibaba常用中间件之Setinel实现熔断降级
spring·spring cloud·中间件
jllllyuz1 小时前
matlab实现蚁群算法解决公交车路径规划问题
服务器·前端·数据库
Warren981 小时前
Java面试八股Spring篇(4500字)
java·开发语言·spring boot·后端·spring·面试
晚秋大魔王1 小时前
OpenHarmony 开源鸿蒙南向开发——linux下使用make交叉编译第三方库——gnutls
java·开发语言
胡子发芽1 小时前
面试题:请解释Java中的垃圾回收机制(Garbage Collection, GC),并讨论不同的垃圾回收算法及其优缺点
java·jvm