Spring容器之IoC- 依赖注入

Spring容器之IoC(二)-- 依赖注入

DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想。指Spring创建对象的过程中,将对象依赖属性通过配置进行注入。 依赖指的是对象和对象之间的关联关系。注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。
依赖注入常见的实现方式包括两种:set注入和构造注入

1. 依赖注入之setter注入

①创建学生类Student 该类需要包括无参构造函数,以及每个属性的set方法

public class Student {
    private Integer id;
    private String name;
    private Integer age;
    private String sex;

    public Student() {
    } 
    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 Integer getAge() { return age;}
    public void setAge(Integer age) {this.age = age;}
    public String getSex() {return sex;}
    public void setSex(String sex) {this.sex = sex;}
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", age=" + age +
                ", sex='" + sex + ''' +
                '}';
    }
}
复制代码

②配置bean时为属性赋值


    
    
    
    
    
    
    

复制代码

再次强调一下:

  1. 使用set注入必须给该属性提供一个set方法。 Spring容器会调用这个set方法,来给该属性赋值。这个set方法,可以是不使用IDEA工具生成的,也可以不符合javabean规范,但是这个方法必须是以set单词开始的也就是说前三个字母不能随便写,必须是以"set"开头
  2. 若想让Spring调用对应的set方法,需要配置property标签,该标签的主要属性是name和ref,name的属性值是想要注入属性的set方法名去掉“set”,然后把剩下的单词首字母变小写。ref翻译为引用,ref要指定的是要注入bean的id。(后面会讲property标签的value和ref标签的具体用法)

2、依赖注入之构造器注入

①在Student类中添加有参构造

public Student(Integer id, String name, Integer age, String sex) {
    this.id = id;
    this.name = name;
    this.age = age;
    this.sex = sex;
}
复制代码

②配置bean

spring-di.xml


    
    
    
    

复制代码

注意:

constructor-arg标签还有两个属性可以进一步描述构造器参数:

index属性:指定参数所在位置的索引(从0开始) name属性:指定参数名 直接根据类型去匹配

3、Set注入详细使用

3.1、特殊值处理

了解一些特殊值的处理之前先了解一下spring里认为哪些被称为简单值类型,以下是BeanUtils类的方法,该方法的作用是检查给定类型是否表示“简单”值类型:基本数据类型或基本数据类型的包装器、枚举、字符串或其他字符序列、数字、日期、时态、URI、URL、区域设置或类,并且 void 不被视为简单值类型。:

package org.springframework.beans;

public abstract class BeanUtils {
······
/**
 * Check if the given type represents a "simple" value type: a primitive or
 * primitive wrapper, an enum, a String or other CharSequence, a Number, a
 * Date, a Temporal, a URI, a URL, a Locale, or a Class.
 * 

{@code Void} and {@code void} are not considered simple value types. * @param type the type to check * @return whether the given type represents a "simple" value type * @see #isSimpleProperty(Class) */ public static boolean isSimpleValueType(Class<?> type) { return (Void.class != type && void.class != type && (ClassUtils.isPrimitiveOrWrapper(type) || Enum.class.isAssignableFrom(type) || CharSequence.class.isAssignableFrom(type) || Number.class.isAssignableFrom(type) || Date.class.isAssignableFrom(type) || Temporal.class.isAssignableFrom(type) || URI.class == type || URL.class == type || Locale.class == type || Class.class == type)); } ······ } 复制代码

下面再来看一些特殊的值,就是这些特殊的该怎么注入到属性里面

①字面量赋值

什么是字面量?

int a = 10;

声明一个变量a,初始化为10,此时a就不代表字母a了,而是作为一个变量的名字。当我们引用a的时候,我们实际上拿到的值是10。

而如果a是带引号的:'a',那么它现在不是一个变量,它就是代表a这个字母本身,这就是字面量。所以字面量没有引申含义,就是我们看到的这个数据本身。



复制代码

②null值

注入空字符串使用:或者 value=""

注入null使用: 或者 不为该属性赋值


    

复制代码

注意:

复制代码

以上写法,name属性是有值的,所赋的值就是字符串‘null’

③xml特殊字符

XML中有5个特殊字符,分别是:<、>、'、"、&

以上5个特殊符号在XML中会被特殊对待,会被当做XML语法的一部分进行解析,如果这些特殊符号直接出现在注入的字符串当中,会报错。举个例子:




复制代码

特殊字符

转义字符

>

>

<

<

'

'

"

"

&

&

除了使用实体符号来代替,也可以使用CDATA节


    
    
    
    
    
    

复制代码

注意:使用CDATA时,不能使用value属性,只能使用value标签。

④Date

Date虽然被Spring认为是简单值类型,使用value赋值,但是value后的字符串不能随便写,格式必须符合Date的toString()方法格式,例如Thu Mar 02 18:06:45 HKT 2023。但是,Date也可以用ref进行赋值,用ref赋值的方式有很多,主要是看用什么样的方式构造出一个Date类型的对象。







    



复制代码

3.2、为对象类型属性赋值

①创建班级类Clazz

public class Clazz {
    private Integer clazzId;
    private String clazzName;
    public Integer getClazzId() {return clazzId;}
    public void setClazzId(Integer clazzId) {this.clazzId = clazzId;}
    public String getClazzName() {return clazzName;}
    public void setClazzName(String clazzName) {this.clazzName = clazzName;}
    @Override
    public String toString() {
        return "Clazz{" +
                "clazzId=" + clazzId +
                ", clazzName='" + clazzName + ''' +
                '}';
    }
    public Clazz() {}
    public Clazz(Integer clazzId, String clazzName) {
        this.clazzId = clazzId;
        this.clazzName = clazzName;
    }
}
复制代码

②修改Student类

在Student类中添加以下代码:

private Clazz clazz;
public Clazz getClazz() {
    return clazz;
}
public void setClazz(Clazz clazz) {
    this.clazz = clazz;
}
复制代码

3.2.1、引用外部bean

配置Clazz类型的bean:


    
    

复制代码

为Student中的clazz属性赋值:


    
    
    
    
    
    

复制代码

错误演示:


    
    
    
    
    

复制代码

如果错把ref属性写成了value属性,会抛出异常: Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.qiuye.spring6.bean.Clazz' for property 'clazz': no matching editors or conversion strategy found

意思是不能把String类型转换成我们要的Clazz类型,说明我们使用value属性时,Spring只把这个属性看做一个普通的字符串,不会认为这是一个bean的id,更不会根据它去找到bean来赋值

3.2.2、内部bean


    
    
    
    
    
        
        
        
            
            
        
    

复制代码

3.2.3、级联属性赋值

使用级联属性赋值,被注入的类的该属性必须提供get方法,例如把Clazz对象注入到Student对象,Student类必须提供clazz属性的get方法,而且再Bean标签里面必须先给clazz赋值,再给clazz下的属性赋值,顺序不能颠倒。


    
    
    
    
    
    
    

复制代码

3.2.4、为数组类型属性赋值

①修改Student类

在Student类中添加hobbies属性,类型是数组:

private String[] hobbies;
public String[] getHobbies() {
    return hobbies;
}
public void setHobbies(String[] hobbies) {
    this.hobbies = hobbies;
}
复制代码

②配置bean


    
    
    
    
    
    
    
    
        
            抽烟
            喝酒
            烫头
        
    
    
        
        
            
            
            
            
        
    
a




复制代码

3.2.5、为集合类型属性赋值

①为List集合类型属性赋值

在Clazz类中添加以下代码:

private List students;
public List getStudents() {
    return students;
}
public void setStudents(List students) {
    this.students = students;
}
复制代码

配置bean:


    
    
    
        
            
            
            
        
    

复制代码

若为Set集合类型属性赋值,只需要将其中的list标签改为set标签即可,同数组一样注入简单类型用value标签,注入其他类型用ref标签。

②为Map集合类型属性赋值

创建教师类Teacher:

public class Teacher {
    private Integer teacherId;
    private String teacherName;
    public Integer getTeacherId() {
        return teacherId;
    }
    public void setTeacherId(Integer teacherId) {
        this.teacherId = teacherId;
    }
    public String getTeacherName() {
        return teacherName;
    }
    public void setTeacherName(String teacherName) {
        this.teacherName = teacherName;
    }
    public Teacher(Integer teacherId, String teacherName) {
        this.teacherId = teacherId;
        this.teacherName = teacherName;
    }
    public Teacher() {
    }
    
    @Override
    public String toString() {
        return "Teacher{" +
                "teacherId=" + teacherId +
                ", teacherName='" + teacherName + ''' +
                '}';
    }
}
复制代码

在Student类中添加以下代码:

private Map teacherMap;
public Map getTeacherMap() {
    return teacherMap;
}
public void setTeacherMap(Map teacherMap) {
    this.teacherMap = teacherMap;
}
复制代码

配置bean:


    
    



    
    

 

    
    
    
    
    
    
        
            抽烟
            喝酒
            烫头
        
    
    
        
            
                
                    10010
                
                
            
            
                
                    10086
                
                
            
        
    

复制代码

要点:

③注入Properties

java.util.Properties继承java.util.Hashtable,所以Properties也是一个Map集合。它的key和value都是String类型,使用标签嵌套标签完成。

    
        
            
                com.mysql.cj.jdbc.Driver
                jdbc:mysql://localhost:3306/spring
                root
                123456
            
        
    
复制代码

3.2.6、p命名空间

引入p命名空间 xmlns:p="www.springframework.org/schema/p"

<?xml version="1.0" encoding="UTF-8"?>

复制代码

引入p命名空间后,可以通过以下方式为bean的各个属性赋值,非简单类型需要加ref


复制代码

p命名空间是简化set注入的,所以它基于set方法注入的

3.2.7、C命名空间

C命名空间是为了简化构造注入的配置,使用c命名空间需要引入xmlns:c="www.springframework.org/schema/c",并且需要提供构造方法

    
    
复制代码

3.2.8、util命名空间

Util命名空间的作用是允许配置复用,就是一些相同属性可以提取出来,在需用的地方进行引入。 在使用util命名空间之前,需要先引入xmlns:util="http://www.springframework.org/schema/util"和http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd 需要注意引入的内容和地方。
util命名空间主要是针对集合来使用的,具体就需要看场景需求。

<?xml version="1.0" encoding="UTF-8"?>

    
        com.mysql.cj.jdbc.Driver
        jdbc:mysql://localhost:3306/spring
        root
        123456
    
    
        
    
    
        
    

复制代码

3.2.9、自动装配

Spring还可以完成自动化的注入,自动化注入又被称为自动装配。它可以根据名字进行自动装配,也可以根据类型进行自动装配。

public class UserService {
    private UserDAO userDAO;
    private UserMysqlDAO userMysqlDAO;

    public void setDao(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    public void setUserMysqlDAO(UserMysqlDAO userMysqlDAO) {
        this.userMysqlDAO = userMysqlDAO;
    }

    public void add(){
        userDAO.add();
        userMysqlDAO.add();
    }
}
复制代码




复制代码

这个配置起到关键作用:

再来看看根据类型进行自动装配,此时需要使用autowire="byType":




复制代码

同理,byType在装配的时候都是基于set方法的。所以set方法是必须要提供的。提供构造方法是不行的,大家可以测试一下。有一点需要注意,根据类型装配时,如果配置文件中有两个类型一样的bean,会抛出异常,所以使用byType时,必须保证注入的bean类型是唯一的。

3.2.10、引入外部属性配置文件

我们都知道编写数据源的时候是需要连接数据库的信息的,例如:driver url username password等信息。如果把这些信息单独写到一个属性配置文件中,这样用户修改起来不就会更加的方便嘛。
①在类路径下新建jdbc.properties文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/spring
username=root
password=root123
复制代码

②在spring中配置文件里面引入context命名空间
xmlns:context="http://www.springframework.org/schema/context"和http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
③使用context命名空间的标签,使用location来指定文件的位置,用${}来获取对应key的值

<?xml version="1.0" encoding="UTF-8"?>


    
    
    
        
        
        
        
    


链接:https://juejin.cn/post/7212812263097368635

展开阅读全文

页面更新:2024-05-28

标签:赋值   字符串   容器   属性   对象   类型   代码   标签   简单   方法   空间

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top