一、第一个Spring程序
1.1 spring简介
- spring:春天,给软件行业带来春天!
- spring理念:使现有的技术更加易用,是一个粘合剂,整合了现有的技术框架
- spring是一个轻量级的开源免费框架
- 核心:控制反转(IOC),面向切面编程(AOP)
- 支持对事务的支持,支持整合其他框架
Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
spring官方文档: https://spring.io/projects/spring-framework#learn
maven官网:https://mvnrepository.com/
1.2 环境配置
软件版本
- jdk 11.0.6
- maven 3.6.2 阿里云
- idea 2019.3
idea新建项目配置
需要注意以下几点:
- 选择创建maven新项目,删除src目录,创建子module
- 在 File | Settings | Build, Execution, Deployment | Build Tools | Maven 中,配置maven
- 在 File | Settings | Build, Execution, Deployment | Compiler | Java Compiler 中,设置发行版本为 11
- File | Settings | Editor | File Encodings,编码改为UTF-8
- 在File | Project Setting | Modules 中,将版本设置为11
所需依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.8.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.0</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>2.0.2</version> </dependency> </dependencies>
jdk发型版本配置
如果不配置,运行测试方法时,可能会报“不支持发行版本5”错误
<properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties>
所需过滤器
过滤器的作用,是在程序编译时,将xml、properties等静态配置文件也加入 target 包中,否则程序无法读取到xml文件
<build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
1.3 编写实体类
User类有两个变量,分别是姓名name和年龄age
类上方的三个注解均在lombok包中
@Data 是用来自动生成set和get方法
@AllArgsConstructor是用来自动生成全部参数的构造方法
@NoArgsConstructor是用来自动生成无参构造方法
@Data @AllArgsConstructor @NoArgsConstructor public class User { private String name; private int age; }
1.4 编写配置文件
<?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" xmlns:c="http://www.springframework.org/schema/c" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="user" class="zwz.pojo.User"> <!-- property相当于给某个变量设置一个值--> <property name="name" value="ZWZ"/> <property name="age" value="18"/> </bean> </beans>
1.5 测试
先是用传统的方法new一个对象
@Test public void testtTradition(){ User user = new User("ZWZ",18); System.out.println(user); }
接着用spring的方式从容器获取一个对象
@Test public void testSpring(){ // ApplicationContext Spring上下文对象 | ClassPathXmlApplicationContext 从配置文件中去取 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 从容器中取出user对象 User user = (User) context.getBean("user"); System.out.println(user); }
都可以得到相同的运行结果
User(name=ZWZ, age=18) Process finished with exit code 0
二、IOC 控制反转
2.1传统开发
我们就以**张三想找一个女朋友谈恋爱**为例,结合Java代码,说明spring控制反转和传统开发的区别
web开发后端的层次,从上到下可以分为:Controller(控制器层)、Service(业务逻辑层)、Dao(数据持久层)
谈恋爱接口(Dao层)
这是一个Dao层的接口,描述谈恋爱这一个抽象性行为
public interface LoveDao { // 谈恋爱的mapper层接口 void talkLove(); }
女朋友一号(Dao层实现1)
这是接口的第一个实现,是活灵活现的女朋友
public class LoveDaoImpl1 implements LoveDao { @Override public void talkLove() { System.out.println("女朋友1号和你谈恋爱了!"); } }
女朋友二号(Dao层实现2)
这是接口的第二个实现,是活灵活现的女朋友
public class LoveDaoImpl2 implements LoveDao{ @Override public void talkLove() { System.out.println("女朋友2号和你谈恋爱了!"); } }
女朋友三号(Dao层实现3)
这是接口的第三个实现,是活灵活现的女朋友
public class LoveDaoImpl3 implements LoveDao{ @Override public void talkLove() { System.out.println("女朋友3号和你谈恋爱了!"); } }
谈恋爱接口(Service层)
这是业务逻辑层的接口,和Dao层一样,是一个抽象性接口
public interface LoveService { // 谈恋爱的Service层接口 void talkLove(); }
谈恋爱实现(Service层)
业务逻辑层调用Dao层的方法,完善业务逻辑层接口的具体实现
如果你选择和女朋友一号谈恋爱,那么…
public class LoveServiceImpl implements LoveService { private LoveDao loveDao = new LoveDaoImpl1(); @Override public void talkLove() { loveDao.talkLove(); } }
测试
@Test public void testTradition(){ LoveService loveService = new LoveServiceImpl(); loveService.talkLove(); }
女朋友1号和你谈恋爱了! Process finished with exit code 0
如果张三的**需求改变了**,他只想和女朋友二号谈恋爱
那么,我们就**必须修改service层的实现类**
private LoveDao loveDao = new LoveDaoImpl2();
女朋友2号和你谈恋爱了! Process finished with exit code 0
- 该程序适应不了需求的变更,需求变了要更改源代码,这是万万不行的!
- 如何解决?如何让程序不动,让客户端去改变?这就需要控制反转
2.2 IOC控制反转实现
首先,Dao层的接口、Dao层的实现类、Service层的接口不改动,我们只改service实现类和测试方法
谈恋爱实现(Service层)
原有代码直接new出一个Dao层实现,现在我们使用构造器,将Dao层实现类的选择权交给用户,从而实现了控制反转
public class LoveServiceImpl implements LoveService { // 传统开发代码 // private LoveDao loveDao = new LoveDaoImpl1(); // IOC控制反转 LoveDao的选择,放权给用户 private LoveDao loveDao; public LoveServiceImpl(LoveDao loveDao) { this.loveDao = loveDao; } @Override public void talkLove() { loveDao.talkLove(); } }
测试
- 张三如果想和一号女朋友谈恋爱
@Test public void testIoc(){ // 用户需求发生改变,没有改动内部代码 LoveServiceImpl loveService = new LoveServiceImpl(new LoveDaoImpl1()); loveService.talkLove(); }
输出
女朋友1号和你谈恋爱了! Process finished with exit code 0
- 如果他跟女朋友二号谈恋爱,只需要更改测试方法
@Test public void testIoc(){ // 用户需求发生改变,没有改动内部代码 LoveServiceImpl loveService = new LoveServiceImpl(new LoveDaoImpl2()); loveService.talkLove(); }
输出
女朋友2号和你谈恋爱了! Process finished with exit code 0
通过 UserServiceImpl 的构造器,对UserDao进行动态注入,用户可以自己选择需要使用的UserDao的实现类,从而灵活变动
- 在传统开发中,需求变更需要修改源代码,如果系统代码量大,修改会非常麻烦,牵一发而动全身!
- 在传统开发中,对象创建在程序中实现;控制反转之后,程序变成了被动接受对象!
- 控制反转是一种设计思想,让第三方去管理对象的创建和获取。在spring中实现控制反转是IOC容器,实现方法是依赖注入DI
本文原创首发CSDN,本文链接https://blog.csdn.net/qq_41464123/article/details/108118680,作者博客https://blog.csdn.net/qq_41464123,转载请带上本链接,谢谢配合。
三、DI 依赖注入
3.1 概念
在第一个Spring程序中已经体验了,传统赋值和依赖注入的区别
传统赋值
User user = new User("ZWZ",18);
依赖注入
在容器中配置bean,并注入值
<bean id="user" class="zwz.pojo.User"> <!-- property相当于给某个变量设置一个值--> <property name="name" value="ZWZ"/> <property name="age" value="18"/> </bean>
在容器中取出对象
// ApplicationContext Spring上下文对象 | ClassPathXmlApplicationContext 从配置文件中去取 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); // 从容器中取出user对象 User user = (User) context.getBean("user");
两种方式,都可以得到相同的运行结果
User(name=ZWZ, age=18) Process finished with exit code 0