精品专题:
01.《C语言从不挂科到高绩点》课程详细笔记
https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482
02. 《SpringBoot详细教程》课程详细笔记
https://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.5482https://blog.csdn.net/yueyehuguang/category_12789841.html?spm=1001.2014.3001.548203.《SpringBoot电脑商城项目》课程详细笔记
https://blog.csdn.net/yueyehuguang/category_12752883.html?spm=1001.2014.3001.5482https://blog.csdn.net/yueyehuguang/category_12752883.html?spm=1001.2014.3001.548204.《VUE3.0 核心教程》课程详细笔记
https://blog.csdn.net/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482https://blog.csdn.net/yueyehuguang/category_12769996.html?spm=1001.2014.3001.5482
================================
|| 持续分享系列教程,关注一下不迷路 ||
|| 视频教程:小破站:墨轩大楼 ||
================================
一、IOC 的概念
IOC全称是Inversion Of Control ,被译为控制反转。
指的是程序中对象的获取方式发生了反转,由最初的new方式创建,转变为由第三方框架创建、注入。第三方框架一般是通过配置方式注入一个具体实现,从而降低了对象之间的耦合度。
IOC按实现方法不同,可以分为依赖注入DI和依赖查找两种。Spring容器是采用DI实现了IOC控制,IOC是Spring框架的基础和核心。
举个例子,租房子时的两种选择。没有IOC之前,是租户自己和每一个房东交涉。有了IOC之后,IOC可以看作中介,找房子时,你只需要和这个中介打交道就可以,中介再分别和各个房东交涉,具体看下图:
二、DI 的概念
DI全称是Dependency Injection ,被译为依赖注入。
DI的基本原理就是将一起工作具有关系的对象,通过构造方法参数或者方法参数传入建立关联,因此容器的工作就是创建Bean时注入那些依赖关系。
IOC是一种思想,而DI是实现IOC的主要技术途径。
DI主要有两种注入方式,即Setter注入和构造器注入。
没有DI时我们创建和使用对象的方式:
java">Student muzi = new Student();
st.study()
使用DI之后创建和使用对象的方式:
三、setter注入
通过调用无参构造器或者无参static工厂方法实例化bean之后,调用该Bean的setter方法,即可实现setter方式注入。
- 首先自定义一个Computer类
java">package com.moxuan.spring01.entity;import java.io.Serializable;public class Computer implements Serializable {private String mainBoard;// 主板private String hdd;// 硬盘private String ram; //内存public String getMainBoard() {return mainBoard;}public void setMainBoard(String mainBoard) {this.mainBoard = mainBoard;}public String getHdd() {return hdd;}public void setHdd(String hdd) {this.hdd = hdd;}public String getRam() {return ram;}public void setRam(String ram) {this.ram = ram;}
}
- 在applicationContext.xml中配置setter注入
<!-- property : 表示实体类的属性name: 实体类属性名称value: 实体类属性值表示,将value值通过属性的set方法,设置到name属性中
-->
<bean id="computer" class="com.moxuan.spring01.entity.Computer"><property name="mainBoard" value="技嘉"></property><property name="hdd" value="希捷"></property><property name="ram" value="金士顿"></property>
</bean>
- 编写测试代码:
java">/**
* 测试setter注入
*/
@Testpublic void test05(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");Computer computer = context.getBean("computer",Computer.class);System.out.println(computer.getMainBoard());System.out.println(computer.getHdd());System.out.println(computer.getRam());
}
运行效果:
四、构造器注入
基于构造器的注入是通过调用带参数的构造器来实现的。容器在bean被实例化的时候,根据参数类型执行响应的构造器。
- 首先新建一个MobliePhone手机类
java">package com.moxuan.spring01.entity;public class MobilePhone {private String brand;private double price;public MobilePhone(String brand,double price){this.brand = brand;this.price = price;}public MobilePhone(){this.brand = "华为";this.price = 3999;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}
}
- 在applicationContext.xml中配置bean
<!--构造器注入: 有参数构造器-->
<bean id="phone" class="com.moxuan.spring01.entity.MobilePhone"><constructor-arg index="0" value="苹果"></constructor-arg><constructor-arg index="1" value="5999"></constructor-arg>
</bean><!--构造器注入: 无参数构造器--><bean id="noArgPhone" class="com.moxuan.spring01.entity.MobilePhone"></bean>
- 添加测试方法
java">/*** 测试构造器注入*/
@Test
public void test06(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");// 有参数构造器MobilePhone phone = context.getBean("phone",MobilePhone.class);System.out.println(phone.getBrand());System.out.println(phone.getPrice());// 无参数构造器MobilePhone phone1 = context.getBean("noArgPhone",MobilePhone.class);System.out.println(phone1.getBrand());System.out.println(phone1.getPrice());
}
- 运行结果:
五、自动装配
Spring IOC 容器可以自动装配(autowire)相互协作bean之间的关联关系。autowire可以针对单个bean进行设置,autowire的方法之处在于减少xml的注入配置。
在xml配置文件中,可以在<bean/>元素中使用autowire属性指定自动装配规则,一共有五种类型值。
属性值 | 描述 |
no | 禁用自动装配,默认值 |
byName | 根据属性名自动装配,此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配。 |
byType | 如果容器中存在一个与指定属性类型相同的bean,那么将于该属性自动装配。 |
constructor | 与byType的方式类似,不同之处在于它应用于构造器函数 |
autodetect | 通过bean类决定是使用constructor还是byType方式进行自动装配,如果发现默认的构造器,那么将使用byType方式。 |
5.1 测试byName
- 新增Student类
java">package com.moxuan.spring01.entity;public class Student {private Computer computer;private MobilePhone phone;public Computer getComputer() {return computer;}public void setComputer(Computer computer) {this.computer = computer;}public MobilePhone getPhone() {return phone;}public void setPhone(MobilePhone phone) {this.phone = phone;}
}
- 在applicationContext.xml中配置bean
<!-- setter 注入-->
<bean id="computer" class="com.moxuan.spring01.entity.Computer"><property name="mainBoard" value="技嘉"></property><property name="hdd" value="希捷"></property><property name="ram" value="金士顿"></property>
</bean><!--构造器注入: 有参数构造器-->
<bean id="phone" class="com.moxuan.spring01.entity.MobilePhone"><constructor-arg index="0" value="苹果"></constructor-arg><constructor-arg index="1" value="5999"></constructor-arg>
</bean><!--构造器注入: 无参数构造器-->
<bean id="noArgPhone" class="com.moxuan.spring01.entity.MobilePhone">
</bean><!--自动装配-->
<bean id="student" class="com.moxuan.spring01.entity.Student" autowire="byName"></bean>
- 添加测试方法
java">/**
* 测试自动装配
*/
@Test
public void test07(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");Student student = context.getBean("student",Student.class);System.out.println(student.getComputer().getHdd());System.out.println(student.getComputer().getMainBoard());System.out.println(student.getPhone().getBrand());System.out.println(student.getPhone().getPrice());}
- 运行效果
从运行效果可以看出,虽然配置文件中配置了两个MobliePhone类型的,但是由于我们自动装配的时候选择的是byName,会根据属性名去匹配,也就是会找到xml文件中id或者name和属性名相同的bean去装配。
5.2 测试byType
首先我们先将上一个案例中的autowire="byName" 修改为 autowire="byType"
这个时候就会出现问题,从报错信息来看,是说配置了多个MobilePhone类型的bean,如果这个时候按照类型装配的话,不知道该装配哪个,会有冲突。所以当使用byType的时候,xml配置文件中,不能出现多个同种类型的bean。
我们把id="phone"的bean注释掉
<!--构造器注入: 无参数构造器-->
<bean id="noArgPhone" class="com.moxuan.spring01.entity.MobilePhone"></bean><!--自动装配-->
<bean id="student" class="com.moxuan.spring01.entity.Student" autowire="byType"></bean>
测试代码不变
java">/**
* 测试自动装配
*/
@Test
public void test07(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");Student student = context.getBean("student",Student.class);System.out.println(student.getComputer().getHdd());System.out.println(student.getComputer().getMainBoard());System.out.println(student.getPhone().getBrand());System.out.println(student.getPhone().getPrice());}
测试结果
六、作业练习
6.1 利用Spring实现Bean属性Setter方式注入
JDBCDataSource类封装了管理数据库连接的方法getConnection(),这个方法在执行之前需要数据库连接参数:数据库驱动,连接URL,用户名和密码,代码如下:
java">package com.moxuan.spring01.entity;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class JDBCDataSource {private String driver;private String url;private String user;private String password;public String getDriver() {return driver;}public void setDriver(String driver) {try{// 注册数据库驱动Class.forName(driver);this.driver = driver;}catch (Exception e){e.printStackTrace();}}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getUser() {return user;}public void setUser(String user) {this.user = user;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Connection getConnection(){Connection conn = null;try {conn = DriverManager.getConnection(url,user,password);} catch (SQLException throwables) {throwables.printStackTrace();}return conn;}public void close(Connection conn){if(conn!=null){try {conn.close();} catch (SQLException throwables) {throwables.printStackTrace();}}}
}
请利用Spring实现JDBCDataSource对象的创建,再使用setter注入的方式将数据库连接参数注入给JDBCDataSource。实现正常调用getConnection()方法获得数据库连接。
步骤一:在pom文件中导入mysql数据库所需要的依赖
<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.0.31</version>
</dependency>
步骤二:在applicationContext.xml中,增加setter代码注入JDBC参数
<bean id="dataSource" class="com.moxuan.spring01.entity.JDBCDataSource"><property name="driver" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://@localhost:3306/student"></property><property name="user" value="root"></property><property name="password" value="123456"></property></bean>
步骤三:在测试类中添加测试方法
java">/**
* 测试setter注入jdbc连接参数
*/
@Test
public void test08(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");JDBCDataSource dataSource = context.getBean("dataSource",JDBCDataSource.class);Connection conn = dataSource.getConnection();System.out.println(conn);
}
运行效果:
6.2 利用构造器参数实现依赖属性的注入
MysqlHeroDao是经典的数据库访问接口的实现类,这个类工作必须依赖mysql数据库连接来工作。JDBCDataSource实例可以提供mysql数据库的连接。MysqlHeroDao类采用构造器参数的方式依赖JDBCDataSource类,这样的好处是创建MysqlHeroDao对象必须有参数JDBCDataSource对象实例。
请完成以下几个练习:
- 请新建Hero类,添加id,name(名称),job(职业),sex(性别)等属性。
- 请在mysql数据库中添加hero表,添加id,name,job,sex等字段,并添加几条数据。
- 创建HeroDao接口,定义根据id查询英雄数据的接口。
- 创建MysqlHeroDao类,使用构造器注入的方式,注入JDBCDataSource,获取数据库连接,并实现HeroDao接口中定义的功能。
- 编写测试类,给定一个id能查询出对应id的英雄数据。
步骤一:新建Hero.java实体类
java">@Data
public class Hero implements Serializable {private Integer id;private String name;private String job;private String sex;
}
此处使用了lombok自动添加了get和set方法。
步骤二:在数据库中新增hero表,脚本如下:
DROP TABLE IF EXISTS `hero`;
CREATE TABLE `hero` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(30) DEFAULT NULL,`job` varchar(30) DEFAULT NULL,`sex` varchar(30) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of hero
-- ----------------------------
INSERT INTO `hero` VALUES ('1', '后羿', '射手', '男');
INSERT INTO `hero` VALUES ('2', '甄姬', '法师', '女');
INSERT INTO `hero` VALUES ('3', '典韦', '战士', '男');
INSERT INTO `hero` VALUES ('4', '蔡文姬', '辅助', '女');
步骤三:创建HeroDao接口,并定义根据ID查找数据的功能
java">public interface HeroDao {/** 根据id查找英雄数据**/Hero findHeroById(int id);
}
步骤四:创建MysqlHeroDao,实现HeroDao接口,并实现里面的功能
java">package com.moxuan.spring01.entity;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;public class MysqlHeroDao implements HeroDao{private JDBCDataSource dataSource;public MysqlHeroDao(JDBCDataSource dataSource){this.dataSource = dataSource;}@Overridepublic Hero findHeroById(int id) {Connection con = dataSource.getConnection();String sql = "select * from hero where id=?";try {PreparedStatement pst = con.prepareStatement(sql);pst.setInt(1,id);ResultSet rs = pst.executeQuery();Hero hero = null;if(rs.next()){hero = new Hero();hero.setId(rs.getInt("id"));hero.setName(rs.getString("name"));hero.setJob(rs.getString("job"));hero.setSex(rs.getString("sex"));}con.close();return hero;} catch (SQLException throwables) {throwables.printStackTrace();}return null;}
}
步骤五:在applicationContext.xml中配置MysqlHeroDao,并利用构造器注入datasource。
<bean id="dataSource" class="com.moxuan.spring01.entity.JDBCDataSource"><property name="driver" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://@localhost:3306/student"></property><property name="user" value="root"></property><property name="password" value="123456"></property></bean><bean id="heroDao" class="com.moxuan.spring01.entity.MysqlHeroDao"><!-- 引用上面的datasource--><constructor-arg index="0" ref="dataSource"></constructor-arg></bean>
上面代码中dataSource为按构造参数注入,这个参数是引用了id为dataSource的Bean对象。
步骤六:编写测试方法
java">@Test
public void test09(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");HeroDao dao = context.getBean("heroDao",MysqlHeroDao.class);Hero hero = dao.findHeroById(1);System.out.println(hero);
}
运行效果:
6.3 利用Spring自动装配功能实现自动属性注入
HeroService类需要依赖HeroDao接口的实例实现查询hero数据的功能,也就是说要能够正确执行HeroService类型对象的查询hero数据的方法必须为HeroService对象注入HeroDao类型的实例。
请使用Spring自动装配的方式为HeroService提供HeroDao对象的实例。
步骤一:添加HeroService类,并添加根据id查询hero的方法
java">package com.moxuan.spring01.entity;public class HeroService {private HeroDao heroDao;public HeroDao getHeroDao() {return heroDao;}public void setHeroDao(HeroDao heroDao) {this.heroDao = heroDao;}public Hero getHeroById(int id){return heroDao.findHeroById(id);}
}
步骤二:在applicationContext.xml中将heroDao自动装配到HeroService中。
<bean id="dataSource" class="com.moxuan.spring01.entity.JDBCDataSource"><property name="driver" value="com.mysql.cj.jdbc.Driver"></property><property name="url" value="jdbc:mysql://@localhost:3306/student"></property><property name="user" value="root"></property><property name="password" value="123456"></property>
</bean><bean id="heroDao" class="com.moxuan.spring01.entity.MysqlHeroDao"><!-- 引用上面的datasource--><constructor-arg index="0" ref="dataSource"></constructor-arg>
</bean><bean id="heroService" class="com.moxuan.spring01.entity.HeroService" autowire="byType"></bean>
步骤三: 编写测试方法
java">@Test
public void test10(){AbstractApplicationContext context =new ClassPathXmlApplicationContext("applicationContext.xml");HeroService service = context.getBean("heroService",HeroService.class);Hero hero = service.getHeroById(2);System.out.println(hero);}