自学内容网 自学内容网

【SSM详细教程】-02-Spring容器IOC详解

精品专题:

01.《C语言从不挂科到高绩点》课程详细笔记

https://blog.csdn.net/yueyehuguang/category_12753294.html?spm=1001.2014.3001.5482icon-default.png?t=O83Ahttps://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.5482icon-default.png?t=O83Ahttps://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.5482icon-default.png?t=O83Ahttps://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.5482icon-default.png?t=O83Ahttps://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时我们创建和使用对象的方式:

Student muzi = new Student();
st.study()

使用DI之后创建和使用对象的方式:

三、setter注入

通过调用无参构造器或者无参static工厂方法实例化bean之后,调用该Bean的setter方法,即可实现setter方式注入。

  1. 首先自定义一个Computer类
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;
    }
}

  1. 在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>
  1. 编写测试代码:
/**
* 测试setter注入
*/
@Test
    public 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被实例化的时候,根据参数类型执行响应的构造器。

  1. 首先新建一个MobliePhone手机类
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;
    }
}

  1. 在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>

  1. 添加测试方法
/**
     * 测试构造器注入
     */
@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());
}

  1. 运行结果:

五、自动装配

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

  1. 新增Student类
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;
    }
}

  1. 在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>

  1. 添加测试方法
/**
* 测试自动装配
*/
@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());

}

  1. 运行效果

从运行效果可以看出,虽然配置文件中配置了两个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>

测试代码不变

/**
* 测试自动装配
*/
@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,用户名和密码,代码如下:

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>

步骤三:在测试类中添加测试方法

/**
* 测试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对象实例。

请完成以下几个练习:

  1. 请新建Hero类,添加id,name(名称),job(职业),sex(性别)等属性。
  2. 请在mysql数据库中添加hero表,添加id,name,job,sex等字段,并添加几条数据。
  3. 创建HeroDao接口,定义根据id查询英雄数据的接口。
  4. 创建MysqlHeroDao类,使用构造器注入的方式,注入JDBCDataSource,获取数据库连接,并实现HeroDao接口中定义的功能。
  5. 编写测试类,给定一个id能查询出对应id的英雄数据。

步骤一:新建Hero.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查找数据的功能

public interface HeroDao {
    /** 根据id查找英雄数据**/
    Hero findHeroById(int id);
}

步骤四:创建MysqlHeroDao,实现HeroDao接口,并实现里面的功能

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

    @Override
    public 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对象。

步骤六:编写测试方法

@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的方法

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>

步骤三: 编写测试方法

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

}

原文地址:https://blog.csdn.net/yueyehuguang/article/details/142935543

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!