【Spring框架】Spring框架的开发方式

目录

  • Spring框架开发方式
    • 前言
    • 具体案例
      • 导入依赖
      • 创建数据库表结构
      • 创建实体类
      • 编写持久层接口和实现类
      • 编写业务层接口和实现类
      • 配置文件的编写
    • IoC注解开发
      • 注解开发入门(半注解)
      • IoC常用注解
      • Spring纯注解方式开发
    • Spring整合JUnit测试

Spring框架开发方式

前言

Spring开发主要依赖的就是IoC控制反转思想,将对象的创建权利移交给Spring框架,对各个模块之间进行解耦,实现方式就是DI——依赖注入,这里不清楚的可以看【Spring框架】Spring核心思想IoC以及依赖注入DI详解-CSDN博客这篇文章。

具体案例

我们创建我们项目的大致结构:实体类+业务层+持久层+测试类,这里我们为了清楚的理解Spring框架的开发方式,在持久层方面我们不引入MyBatis进行数据注入,而是选择原始的JDBC程序。好了我们先创建一个最普通的Maven项目,并引入我们的必要依赖(不会创建Maven项目可以看:【Maven】一篇带你了解Maven项目管理工具-CSDN博客):

导入依赖

<dependencies><!-- Spring核心 --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.0.2.RELEASE</version></dependency><!-- slf4j接口https://mvnrepository.com/artifact/org.slf4j/slf4j-api --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.16</version></dependency><!-- log4j核心https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.24.0</version></dependency><!-- log4j2绑定到slf4j接口进行实现https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl --><dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-slf4j2-impl</artifactId><version>2.24.0</version><scope>test</scope></dependency><!-- JUnit测试 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!--Druid连接池--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.10</version></dependency><!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.4.0</version></dependency>
</dependencies>

创建数据库表结构

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);

创建实体类

public class Account {private Integer id;private String name;private Double money;public Account() {}public Account(String name, Double money, Integer id) {this.name = name;this.money = money;this.id = id;}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;}@Overridepublic String toString() {return "Account{" +"id=" + id +", name='" + name + '\'' +", money=" + money +'}';}
}

这里我们创建一个简单的账户类,和我们的数据库表结构向对应,有id、姓名、余额三个属性。

编写持久层接口和实现类

接口

public interface AccountDao {// 查询所有账户List<Account> findAll();
}

实现类

这里和之前没有引入Spring框架的时候是有区别的,我们可以将数据库连接池对象的创建权利移交给Spring框架,我们只需要在持久层注入连接池对象就可以进行使用,不需要再去new一个对象,我们来看一下对比:

在没有引入Spring之前:

public class AccountDaoImpl implements AccountDao {/*** 查询所有的数据* @return*/@Overridepublic List<Account> findAll() {// 手动创建连接池对象DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///spring_db");dataSource.setUsername("root");dataSource.setPassword("root");// 业务逻辑System.out.println("业务逻辑...");return list;}
}

我们通过手动创建链接池对象的方式进行数据库连接,也就是new一个新的连接池对象。

引入Spring之后:

public class AccountDaoImpl implements AccountDao {// 注入连接池对象private DataSource dataSource;public void setDataSource(DataSource dataSource) {this.dataSource = dataSource;}/*** 查询所有的数据* @return*/@Overridepublic List<Account> findAll() {/*不再使用手动的方式进行创建连接池对象DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.jc.jdbc.Driver");dataSource.setUrl("jdbc:mysql:///spring_db");dataSource.setUsername("root");dataSource.setPassword("root");*/System.out.println("业务逻辑...");return list;}
}

在引入Spring之后,我们只需要通过Spring注入bean对象就可以了,不需要每次创建新的持久层实现类的时候都去重复连接数据库。

编写业务层接口和实现类

public interface AccountService {// 查询所有用户List<Account> findAll();
}

同样的,在这里我们不需要再手动去创建持久层对象,我们只需要通过Spring框架创建对象,并进行依赖注入,就可以完成此功能:

public class AccountServiceImpl implements AccountService {// 依赖注入private AccountDao accountDao;public void setAccountDao(AccountDao accountDao) {this.accountDao = accountDao;}/*** 查询所有的数据*/@Overridepublic List<Account> findAll() {return accountDao.findAll();}
}

现在我们的业务层和持久层逻辑都已经编写好了,并注入了相关依赖,但是我们这些依赖去哪里拿呢?我们需要一个配置文件:applicationConfig.xml,Spring框架通过这个配置文件来创建我们的对象,并能让我们获取到对象。

配置文件的编写

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- Spring配置数据源 --><!-- 这里是将数据源的实例化交给Spring容器管理 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC"/><property name="username" value="root"/><property name="password" value="root"/></bean><!--管理bean--><bean id="accountService" class="com.qcby.service.Impl.AccountServiceImpl"><property name="accountDao" ref="accountDao" /></bean><bean id="accountDao" class="com.qcby.dao.Impl.AccountDaoImpl"><property name="dataSource" ref="dataSource" /></bean>
</beans>

最后我们编写我们的测试类,执行测试:

public class AccountServiceTest {@Testpublic void run1(){// 通过读取我们的配置文件ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");// 获取到对象AccountService accountService = (AccountService) ac.getBean("accountService");// 调用方法List<Account> list = accountService.findAll();for (Account account : list) {System.out.println(account);}}
}

测试结果:

在这里插入图片描述

以上我们就完成了使用Spring框架来对项目的管理。

IoC注解开发

注解开发入门(半注解)

Spring框架通过配置文件来管理我们移交的对象,我们同样也可以丢弃配置文件,使用springframework提供的注解来进行开发,比配置文件的方式更便捷,不需要在配置文件中再去配置SpringBean

再简单编写一个案例,不再添加实体类和持久层,这里我只写一个业务层的接口和实现类:

接口:

public interface RoomService {void hello();
}

实现类:

在我们需要Spring管理的类上添加@Component注解,这个注解的作用就相当于将这个类创建对象的权利移交给Spring框架去管理,也就是想当于我们配置文件中的:<bean id="rs" class="com.xxx.RoomService" />

@Component(value = "rs")
public class RoomServiceImpl implements RoomService {@Overridepublic void hello() {System.out.println("Hello IOC注解...");}
}

开启注解扫描

我们加入了注解,但是此时我们的Spring框架并没有读取到,我们需要在配置文件中加入开启注解扫描,扫描我们加入注解的类所在的包:

<!--开启注解扫描 com.qcby 所有的包中的所有的类 -->
<context:component-scan base-package="com.qcby" />

如果不开启,就会提示我们找不到名为rs的这个SpringBean对象:

在这里插入图片描述

编写测试方法进行测试:

public class AnnotationTest {/*** 测试注解创建Bean对象*/@Testpublic void run1() {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");RoomService roomService = (RoomService) applicationContext.getBean("rs");roomService.hello();}
}

在这里插入图片描述

IoC常用注解

注解说明
@Component用于实例化Bean对象 作用于实体类
@Controller用于实例化Bean对象 作用于web层
@Service用于实例化Bean对象 作用于service层
@Repository用于实例化Bean对象 作用于dao层
@Autowired使用在字段上用于根据类型依赖注入
@Qualifier必须和@Autowired一起使用用于根据名称进行依赖注入
@Resource相当于@Autowired+@Qualifier,使用name属性,按照名称进行注入
@Value注入普通属性
@Scope标注Bean的作用范围 声明Spring创建对象的模式 单例singleton|多例prototype
@PostConstruct使用在方法上标注该方法是Bean的初始化方法 相当于init-method
@PreDestroy使用在方法上标注该方法是Bean的销毁方法 destroy-method

Spring纯注解方式开发

纯注解的方式是微服务架构开发的主要方式,所以非常重要。纯注解的目的就是要舍弃臃肿的配置文件,用相同作用的配置类进行代替。

首先编写我们的实体类:

@Component
public class Order {@Value("小明")private String name;@Value("1000")private Integer money;public String getName() {return name;}public Integer getMoney() {return money;}@Overridepublic String toString() {return "Order{" +"name='" + name + '\'' +", money=" + money +'}';}
}

编写持久层接口和实现类:

public interface OrderDao1 {void saveOrder(String name,Integer money);
}
@Component(value = "odi")
public class OrderDao1Impl implements OrderDao1 {// 注入dataSource@Autowired@Qualifier(value = "dataSource1")private DataSource dataSource;@Overridepublic void saveOrder(String name,Integer money) {Connection connection = null;PreparedStatement stmt = null;ResultSet rs = null;int num;try {connection = dataSource.getConnection();String sql = "insert into account(name,money) values(?,?)";stmt = connection.prepareStatement(sql);stmt.setString(1, name);stmt.setInt(2, money);num = stmt.executeUpdate();if (num > 0) {System.out.println("插入数据成功");} else {System.out.println("插入数据失败");}} catch (SQLException e) {throw new RuntimeException(e);} finally {try {connection.close();} catch (SQLException e) {e.printStackTrace();}try {stmt.close();} catch (SQLException e) {e.printStackTrace();}}}
}

编写业务层接口和实现类:

public interface OrderService1 {void saveOrder();
}
@Component(value = "aa")
public class OrderService1Impl implements OrderService1 {@Autowired@Qualifier(value = "odi")private OrderDao1 orderDao1;@Autowired@Qualifier(value = "order")private Order order;private String name;private Integer money;// 这里要延迟加载一下,不然会报空指针异常// 因为在注入order的时候,其中的name和money都还没注入进来@PostConstructpublic void init() {this.name = order.getName();this.money = order.getMoney();}@Overridepublic void saveOrder(){orderDao1.saveOrder(name, money);}
}

编写配置类:

@Configuration
@ComponentScan(value = "com.qcby")
public class SpringConfig {@Bean("dataSource1")public DataSource createDataSource() {DruidDataSource dataSource = new DruidDataSource();dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");dataSource.setUrl("jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC");dataSource.setUsername("root");dataSource.setPassword("20020322");return dataSource;}
}

这里使用@Configuration进行声明,声明这是一个配置类,并且用@ComponentScan注解对包进行扫描,最后编写测试类

// 加载我们的配置类,代替application.xml文件
@ContextConfiguration(classes = SpringConfig.class)
public class demo1Test {@Testpublic void run(){ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);OrderService1 orderService = (OrderService1)applicationContext.getBean("aa");orderService.saveOrder();}
}

Spring整合JUnit测试

可以看到在测试类中,每次测试一个方法,我们都需要进行配置文件或者是配置类的读取,然后再通过依赖注入的方式获取到对象,最后通过对象对方法进行调用。Spring提供了整合Junit单元测试的技术,可以简化测试开发。

我们通过引入以下依赖,使用我们的Spring框架整合JUnit测试

<!-- Spring整合JUnit测试 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>5.0.2.RELEASE</version><scope>test</scope>
</dependency>

我们通过在测试类上添加注解:@RunWith(SpringJUnit4ClassRunner.class)来整合我们的JUnit测试,这个写法是固定的,当然你也可以通过配置文件的方式,在配置文件中添加对应的测试对象即可:

// 整合JUnit测试
@RunWith(SpringJUnit4ClassRunner.class)
// 加载我们的配置类,代替application.xml文件
@ContextConfiguration(classes = SpringConfig.class)
public class demo1Test {// 测试对象注入@Autowiredprivate OrderService1 orderService;@Testpublic void run(){
//        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
//        OrderService1 orderService = (OrderService1)applicationContext.getBean("aa");orderService.saveOrder();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/58502.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis数据安全_持久化机制

由于Redis的数据都存放在内存中&#xff0c;如果没有配置持久化&#xff0c;Redis重启后数据就全丢失了&#xff0c;于是需要开启Redis的持久化功能&#xff0c;将数据保存到磁盘上&#xff0c;当Redis重启后&#xff0c;可以从磁盘中恢复数据。 持久化机制概述 对于Redis而言…

Golang | Leetcode Golang题解之第519题随机翻转矩阵

题目&#xff1a; 题解&#xff1a; type Solution struct {m, n, total intmp map[int]int }func Constructor(m, n int) Solution {return Solution{m, n, m * n, map[int]int{}} }func (s *Solution) Flip() (ans []int) {x : rand.Intn(s.total)s.total--if y, o…

【电子通识】四线制电阻屏怎么判断是哪一路出现异常?

在文章【电子通识】四线电阻屏原理中我们聊了一下四线电阻屏触摸的原理,如电阻屏结构、如何计算坐标等方面。 那么在实际的问题分析中,如果是屏硬件问题,那我们如何去判断到底是X还是Y出现异常或是说X+还是X-,是Y+还是Y-出现问题呢? 首先要知道,XY轴为什么会出问题,其实…

高效文本编辑与导航:Vim中的三种基本模式及粘滞位的深度解析

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

推荐一款开源的免费PDF编辑工具:CubePDF Utility

CubePDF Utility是一款功能强大的开源免费PDF编辑器&#xff0c;它采用了基于缩略图的界面设计&#xff0c;为用户提供了直观且高效的PDF编辑体验。该软件特别针对那些希望以简单直观方式编辑 PDF 文件的用户而设计&#xff0c;支持多种操作&#xff0c;如合并、提取、拆分、更…

一款基于.NET8开源且免费的中小型酒店管理系统

项目介绍 TopskyHotelManagerSystem是一款基于.NET8开源、免费&#xff08;MIT License&#xff09;的中小型酒店管理系统&#xff0c;为中小型酒店提供全面的酒店管理系统解决方案&#xff0c;帮助酒店提高运营效率&#xff0c;优化客户体验。 开发目的 在现如今发展迅速的酒…

化学语言模型在创新型药物设计中的挑战与机遇

化学语言模型在创新型药物设计中的挑战与机遇 研究背景 化学生物学领域借用了语言学的类比&#xff0c;将基因密码转录和翻译为蛋白质&#xff0c;细胞通过化学信号进行相互沟通。分子可以被看作构成"化学语言"的基本单元&#xff08;见图1a&#xff09;。类似于人…

第4章 kafka broker

4.1 Kafka Broker 工作流程 4.1.1 Zookeeper 存储的 Kafka 信息 4.1.2 Kafka Broker 总体工作流程 4.1.3 Broker 重要参数 4.2 生产经验——节点服役和退役 4.2.1 服役新节点 4.2.2 退役旧节点 4.3 Kafka 副本 4.3.1 副本基本信息 4.3.2 Leader 选举流程 4.3.3 Leader …

【力扣打卡系列】滑动窗口与双指针(三数之和)

坚持按题型打卡&刷&梳理力扣算法题系列&#xff0c;语言为go&#xff0c;Day11 搜索旋转排序数组 题目描述 解题思路 单独开一个函数来判断是否被染成蓝色 以与最后一个元素的大小比较来确定在哪个段上分类讨论target、nums[key]、end的大小情况&#xff0c;来确定此处…

LabVIEW汽车状态监测系统

LabVIEW汽车状态监测系统通过模拟车辆运行状态&#xff0c;有效地辅助工程师进行故障预测和维护计划优化&#xff0c;从而提高汽车的可靠性和安全性。 项目背景&#xff1a; 现代汽车工业面临着日益增长的安全要求和客户对于车辆性能的高期望。汽车状态监测系统旨在实时监控汽…

函数基础,定义与调用。作用域,闭包函数

一、函数的定义与调用 函数是一段可重复使用的代码块&#xff0c;用于执行特定任务或计算等功能。它可以接受输入参数&#xff08;形参&#xff09;&#xff0c;并根据参数执行操作后返回结果。 函数的定义 例如在 JavaScript 中可以这样定义函数&#xff1a; function fun…

python代码中通过pymobiledevice3访问iOS沙盒目录获取app日志

【背景】 在进行业务操作过程中&#xff0c;即在app上的一些操作&#xff0c;在日志中会有对应的节点&#xff0c;例如&#xff0c;下面是查看设备实时视频过程对应的一些关键节点&#xff1a; 1、TxDeviceAwakeLogicHelper&#xff1a;wakeStart deviceId CxD2BA11000xxxx …

C# OpenCvSharp DNN UNet 推理

目录 效果 模型 项目 代码 下载 效果 模型 Inputs ------------------------- name&#xff1a;data tensor&#xff1a;Float[1, 3, 256, 256] --------------------------------------------------------------- Outputs ------------------------- name&#xff1a;p…

Flutter仿京东商城APP实战 用户中心基础布局

用户中心界面 pages/tabs/user/user.dart import package:flutter/material.dart; import package:jdshop/utils/zdp_screen.dart; import package:provider/provider.dart;import ../../../store/counter_store.dart;class UserPage extends StatefulWidget {const UserPage…

D52【python 接口自动化学习】- python基础之模块与标准库

day52 标准库 学习日期&#xff1a;20241029 学习目标&#xff1a;模块与标准库 -- 67 标准库&#xff1a;Python默认提供的便携功能有哪些&#xff1f; 学习笔记 标准库中的常见组件 如何通过官方文档学习标准 from urllib.request import urlopen with urlopen(http://ww…

芒果YOLO11改进:免费|注意力机制SKNet:选择性内核网络结构,不同关注会产生融合层神经元有效感受野

&#x1f4a1;&#x1f680;&#x1f680;&#x1f680;本博客 改进源代码改进 适用于 YOLO11 按步骤操作运行改进后的代码即可 YOLO11改进&#xff1a;注意力机制&#xff5c;YOLO11SKAttention改进内容&#x1f680;&#x1f680;&#x1f680; 文章目录 1. SKAttention 论文…

顺序表排序相关算法题|负数移到正数前面|奇数移到偶数前面|小于x的数移到大于x的数前面|快排思想(C)

负数移到正数前面 已知顺序表 ( a 1 , … , a n ) (a_{1},\dots,a_{n}) (a1​,…,an​)&#xff0c;每个元素都是整数&#xff0c;把所有值为负数的元素移到全部正数值元素前边 算法思想 快排的前后指针版本 排序|冒泡排序|快速排序|霍尔版本|挖坑版本|前后指针版本|非递归版…

如何在Linux系统中使用LVM进行磁盘管理

如何在Linux系统中使用LVM进行磁盘管理 LVM简介 安装LVM 在Debian/Ubuntu系统中安装 在CentOS/RHEL系统中安装 创建物理卷 准备磁盘 创建卷组 创建逻辑卷 格式化逻辑卷 挂载逻辑卷 扩展逻辑卷 扩展现有物理卷 添加新的物理卷 调整卷组 调整卷组大小 使用LVM快照 LVM监控 查…

kaggle 数据集下载

文章目录 kaggle 数据集下载&#xff08;1&#xff09; 数据集下载&#xff08;2&#xff09; 手机号验证 kaggle 数据集下载 这两天想学习 kaggle 赛事 把深度学习相关的内容自己给过一遍&#xff0c;快忘得差不多了&#xff0c;惭愧。 参考了好多帖子&#xff0c;使用命令行…

力扣题86~90

题86&#xff08;中等&#xff09;&#xff1a; python代码 # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def partition(self, head: Optional[Li…