【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.rhkb.cn/news/459760.html

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

相关文章

江协科技STM32学习- P24 DMA数据转运DMA+AD多通道

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

【刷题11】CTFHub技能树sql注入系列

整数型注入 看到源码了&#xff0c;直接sql一套秒了 字符型注入 SQL 报错注入 构造payload 1 and (select extractvalue(1,concat(’~’,(select database())))) 后续步骤跟sql基本步骤一样 SQL 布尔注入 人工测试太麻烦&#xff0c;这里直接使用sqlmap,知道这有sql注入漏洞&am…

面试经典 150 题.P26. 删除有序数组中的重复项(003)

本题来自&#xff1a;力扣-面试经典 150 题 面试经典 150 题 - 学习计划 - 力扣&#xff08;LeetCode&#xff09;全球极客挚爱的技术成长平台https://leetcode.cn/studyplan/top-interview-150/ 题解&#xff1a; class Solution {public int removeDuplicates(int[] nums) …

docker中使用ros2humble的rviz2不显示问题

这里写目录标题 docker中使用ros2humble的rviz2不显示问题删除 Docker 镜像和容器删除 Docker 容器Linux服务器下查看系统CPU个数、核心数、(make编译最大的)线程数总结&#xff1a; RVIZ2 不能显示数据集 docker中使用ros2humble的rviz2不显示问题 问题描述&#xff1a; roo…

ELK + Filebeat + Spring Boot:日志分析入门与实践(二)

目录 一、环境 1.1 ELKF环境 1.2 版本 1.3 流程 二、Filebeat安装 2.1 安装 2.2 新增配置采集日志 三、logstash 配置 3.1 配置输出日志到es 3.2 Grok 日志格式解析 3.2 启动 logstash ​3.3 启动项目查看索引 一、环境 1.1 ELKF环境 springboot项目&#xff1a;w…

基于SSM土家风景文化管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;景点分类管理&#xff0c;热门景点管理&#xff0c;门票订单管理&#xff0c;旅游线路管理&#xff0c;系统管理 前提账号功能包括&#xff1a;系统首页&#xff0c;个人中心&…

Linux特种文件系统--tmpfs文件系统

tmpfs类似于RamDisk&#xff08;只能使用物理内存&#xff09;&#xff0c;使用虚拟内存&#xff08;简称VM&#xff09;子系统的页面存储文件。tmpfs完全依赖VM&#xff0c;遵循子系统的整体调度策略。说白了tmpfs跟普通进程差不多&#xff0c;使用的都是某种形式的虚拟内存&a…

不同概率分布的更新过程——Python实现(均匀分布、卡方分布、指数分布等作为概率分布的更新过程)

更新过程(renewal process)是描述元件或设备更新现象的一类随机过程。以下是对更新过程的详细介绍: 一、定义与特点 定义:设对某元件的工作进行观测,假定元件的使用寿命是一随机变量,当元件发生故障时就进行修理或换上新的同类元件,而且元件的更新是即时的(修理或更换…

GIT分布式版本控制系统基础操作

问题大纲 1、什么分布式版本控制系统 2、简述Git的使用分为哪几个步骤 3、克隆和拉取的区别是什么&#xff1f; 4、git相关的所有指令 一、分布式版本控制系统 分布式版本控制系统是一种版本控制系统&#xff0c;它允许每个用户都拥有完整的项目历史记录和版本控制信息。与…

ArcGIS必会的选择要素方法(AND、OR、R、IN等)位置选择等

今天来看看ArcGIS中的几个选择的重要使用方法 1、常规选择、 2、模糊查询、 3、组合复合条件查询&#xff08;AND、OR、IN&#xff09;&#xff0c; 4、空值NULL查询 5、位置选择 推荐学习&#xff1a; 以梦为马&#xff0c;超过万名学员学习ArcGIS入门到实战的应用课程…

Spring Bean创建流程

Spring Bean 创建流程图 大家总是会错误的理解Bean的“实例化”和“初始化”过程&#xff0c;总会以为初始化就是对象执行构造函数生成对象实例的过程&#xff0c;其实不然&#xff0c;在初始化阶段实际对象已经实例化出来了&#xff0c;初始化阶段进行的是依赖的注入和执行一…

rtp协议:rtcp包格式和传输间隔

RTP Control Protocol -- RTCP-rtp控制协议 实时传输控制协议&#xff08;RTCP&#xff09;基于对会话中的所有参与者定期传输控制包&#xff0c;使用与数据包相同的分发机制。底层协议必须提供数据包和控制包的多路复用&#xff0c;例如使用UDP时使用不同的端口号。RTCP执行四…

2024年医疗人工智能研究报告-生成式AI爆发,医疗人工智能走到新的十字路口(附下载)

前言 2024的医疗AI&#xff0c;既是坎坷&#xff0c;又是新生。 快速发展的大语言模型&#xff0c;携着生成式AI掠过医疗领域。过往的互联网医疗、医学影像、新药研发……一个一个场景经由新一代AI重塑&#xff0c;焕发出前所未有的价值。 不过&#xff0c;发现价值并不意味着…

网络请求自定义header导致跨域问题

我记得我的项目之前已经解决了跨域问题。 后来在功能开发着&#xff0c;需要添加一个自定义的header&#xff0c;发现又出现跨域报错。 于是又开始一通摸索折腾。 我的项目前面端是用axios网络请求&#xff0c;通过拦截器添加header&#xff0c;代码如下&#xff1a; //添加请…

macOS 15 Sequoia dmg格式转用于虚拟机的iso格式教程

想要把dmg格式转成iso格式&#xff0c;然后能在虚拟机上用&#xff0c;最起码新版的macOS镜像是不能用UltraISO&#xff0c;dmg2iso这种软件了&#xff0c;你直接转放到VMware里绝对读不出来&#xff0c;办法就是&#xff0c;在Mac系统中转换为cdr&#xff0c;然后再转成iso&am…

大语言模型数据流程源码解读(基于llama3模型)

文章目录 前言一、数据进入LlamaForCausalLM(LlamaPreTrainedModel)类二、数据进入LlamaModel(LlamaPreTrainedModel)类1、input_ids的embedding编码2、position_ids位置获取3、causal_mask因果mask构建1、causal_mask调用2、因果mask代码解读(_update_causal_mask)4、hidden_s…

MATLAB人脸考勤系统

MATLAB人脸考勤系统课题介绍 该课题为基于MATLAB平台的人脸识别系统。传统的人脸识别都是直接人头的比对&#xff0c;现实意义不大&#xff0c;没有一定的新意。该课题识别原理为&#xff1a;先采集待识别人员的人脸&#xff0c;进行训练&#xff0c;得到人脸特征值。测试的时…

Http 状态码 301 Permanent Rediret 302 Temporary Redirect、 重定向 重写

HTTP状态码301和302是什么&#xff1f; 1、HTTP状态码301 HTTP状态码301表示永久性转移&#xff08;Permanent Redirect&#xff09;&#xff0c;这意味着请求的资源已经被分配了一个新的URI&#xff0c;以后的引用应该使用资源现在所指的URI。 HTTP 301状态码表示请求的资源…

如何用猿大师办公助手实现OA系统中Word公文/合同在线编辑及流转?

在OA系统或者合同管理系统中&#xff0c;我们会经常遇到网页在线编辑Word文档形式的公文及合同的情况&#xff0c;并且需要上级对下级的公文进行批注等操作&#xff0c;或者不同部门的人需要签字审核&#xff0c;这就需要用到文档流转功能&#xff0c;如何用猿大师办公助手实现…