spring-IOC

IOC容器

简介

IoC(Inversion of Control)控制反转,是一种基于面向对象编程法则的设计思想,它设计出的程序具有松耦合、更优良的特点。
IoC容器是Spring框架中重要的核心组件之一,贯穿了Spring从出生到成长的整个过程,Spring通过IoC容器管理所有Java对象的实例化和初始化,控制对象与对象之间的实例化、初始化以及依赖关系。由IoC容器管理的Java对象称为Spring Bean,它与使用new 关键字创建的Java对象没有任何区别。

Bean管理:Bean对象的创建和Bean对象中属性的的赋值(或者叫Bean对象之间关系的维护)

控制反转,反转的是什么?

  • 将对象的创建权交出去,交给第三方容器负责。
  • 将对象和对象之间关系的维护权交出去,交给第三方容器负责。

如何实现控制反转?

DI(Dependency Injection) 依赖注入

依赖注入:指Spring创建对象的过程中,将对象依赖属性通过配置进行注入,它实现了控制反转的思想。当一个对象作为另一个对象的属性的时候,我们可以使用依赖注入的方式将对象的内容注入。

依赖注入的实现方式:①set注入、②构造注入


IoC在Spring中的实现

Spring的IoC容器中管理的组件叫做Bean, 在创建Bean之前,首先需要创建IoC容器,Spring提供的IoC容器有两种实现方式。

1、BeanFactory
这是IoC容器的基本实现,是Spring内部使用的接口
2、ApplicationContext
BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有的场合都使用ApplicationContext而不是底层的BeanFactory

ApplicationContext的主要实现类

在这里插入图片描述

类名简介
ClassPathXmlApplicationContext通过类读取路径下的XML格式的配置文件创建IoC对象
FileSystemXmlApplicationContext通过文件系统路径读取XML格式的配置文件创建IoC对象
ConfigurableApplicationContextApplicationContext的子接口,包含一些扩展方法refresh()和close(),让ApplicationContext具有启动、关闭和刷新上下文功能
WebApplicationContex专门为Web应用准备,基于Web环境创建的IoC容器对象,并将对象引入存入ServletContext域中

基于xml管理Bean

步骤

①导入相关依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.0.9</version>
</dependency>
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.20.0</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-slf4j2-impl</artifactId>
    <version>2.20.0</version>
</dependency>

②创建spring和log4j2的配置文件

spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.louis.ioc_xml.User"></bean>
</beans>

log4j2的配置文件可从取:https://blog.csdn.net/xry12354/article/details/131647570

③创建User对象

package com.louis.ioc_xml;

/**
 * @author XRY
 * @date 2023年06月22日13:58
 */
public class User {

    private String name;
    private Integer age;

    public void run(){
        System.out.println("run....");
    }
}

④获取Bean

方式一:根据id获取

由于id属性指定了bean的唯一标识,所以根据bean标签的id属性可以精确获取到一个组件对象。
写法:

<bean id="user" class="com.louis.ioc_xml.User"></bean>

id属性:唯一标识
class属性:要创建对象所在类的全路径(包名称+类名称)

@Test
public void testBeanById(){
    ApplicationContext applicationContext =
            new ClassPathXmlApplicationContext("bean.xml");
    User user = (User)applicationContext.getBean("user");
    logger.info("user = " + user);
}
/*[2023-06-22 14:17:20:953] [INFO] - TestBeanById.testBeanById(TestBeanById.java:20) - user = com.louis.ioc_xml.User@77d2e85*/

方式二:根据类型获取

@Test
public void testBeanByClass(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
    User bean = applicationContext.getBean(User.class);
    logger.info("user"+bean);
}
/*[2023-06-22 14:22:24:009] [INFO] - TestBeanById.testBeanByClass(TestBeanById.java:29) - usercom.louis.ioc_xml.User@1a9c38eb*/

方式三:根据id和类型获取

@Test
public void testBeanByClassAndId(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
    User user = applicationContext.getBean("user", User.class);
    logger.info("user" + user);
}
/*[2023-06-22 14:25:27:189] [INFO] - TestBeanById.testBeanByClassAndId(TestBeanById.java:37) - usercom.louis.ioc_xml.User@77d2e85*/

获取bean的细节

根据类型获取Bean时,要求IoC容器中指定类型的bean有且只能有一个。
组件类实现了接口,如果实现类只有一个则可以通过类型获取bean,如果实现类有多个,即使这些实现类都配置了bean也不能够使用类型获取。

只有一个实现类

//UserDaoImpl
package com.louis.bean;

/**
 * @author XRY
 * @date 2023年06月22日14:37
 */
public class UserDaoImpl implements UserDao{
    @Override
    public void run() {
        System.out.println("check the target");
    }
}

测试

@Test
public void testInterface(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
    UserDao userDao = applicationContext.getBean("userDao", UserDao.class);
    logger.info("userDao" + userDao);
    userDao.run();
}
/*[2023-06-22 14:43:27:092] [INFO] - TestBeanById.testInterface(TestBeanById.java:47) - userDaocom.louis.bean.UserDaoImpl@58ffcbd7
    check the target*/

User有多个实现类

//PersonDaoImpl
package com.louis.bean;

/**
 * @author XRY
 * @date 2023年06月22日14:47
 */
public class PersonDaoImpl implements UserDao{
    @Override
    public void run() {
        System.out.println("person");
    }
}

测试

@Test
public void testTwoInterface(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
    UserDao personDao = (UserDao)applicationContext.getBean("personDao");
    logger.info("personDao" + personDao);
    UserDao bean = applicationContext.getBean(UserDao.class);
    logger.info("bean" + bean);
}
 /*[2023-06-22 14:55:05:632] [INFO] - TestBeanById.testTwoInterface(TestBeanById.java:57) - personDaocom.louis.bean.PersonDaoImpl@555cf22
    org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.louis.bean.UserDao' available: expected single matching bean but found 2: userDao,personDao*/
结论

根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看instanceof指定的类型的返回结果,只要返回的结果是true就可以认定为和类型匹配,能够获取到。
java中instanceof运算符用来判断前面的对象是否是后面的类,或其子类、实现类的实例。如果是返回true,否则返回false。


依赖注入

创建对象过程中,给属性设置值。

原生方法实现

package com.louis.di;

/**
 * @author XRY
 * @date 2023年06月23日9:46
 */
public class Book {
    private String name;
    private String author;

    public Book() {
    }

    public Book(String name, String author) {
        this.name = name;
        this.author = author;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }


    public static void main(String[] args){
        //使用原生方法实现值的设置
        //set
        Book book = new Book();
        book.setName("西游记");
        book.setAuthor("吴承恩");

        //构造器
        Book book1 = new Book("水浒传","施耐庵");
    }
}

基于setter注入

步骤

1、创建类,定义属性生成属性的set方法

package com.louis.di;

/**
 * @author XRY
 * @date 2023年06月23日9:46
 */
public class Book {
    private String name;
    private String author;
    

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}

2、在spring的配置文件中进行配置

<!--基于set方法进行注入-->
<bean id="book" class="com.louis.di.Book">
<!--在使用property这个标签时,就会调用类中的set方法-->
    <property name="name" value="红楼梦"></property>
    <property name="author" value="曹雪芹"></property>
</bean>

3、测试

@Test
public void testBook(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-di.xml");
    Book book = applicationContext.getBean("book", Book.class);
    logger.info("set注入" + book);
}

/*[2023-06-23 10:02:10:517] [INFO] - TestBeanById.testBook(TestBeanById.java:72) - set注入Book{name='红楼梦', author='曹雪芹'}*/

基于构造器注入

步骤

1、创建类,定义属性,生成有参构造方法(可以没有无参)

package com.louis.di;

/**
 * @author XRY
 * @date 2023年06月23日9:46
 */
public class Book {
    private String name;
    private String author;

    public Book() {
    }

    public Book(String name, String author) {
        this.name = name;
        this.author = author;
    }
    
    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}

2、在spring中进行配置

<!--构造器注入-->
<bean id="bookConstructor" class="com.louis.di.Book">
    <constructor-arg name="name" value="三国演义"></constructor-arg>
    <constructor-arg name="author" value="罗贯中"></constructor-arg>
<!--也可以使用index这种类型<constructor-arg index="0" value="三国"></constructor-arg>-->
</bean>

3、测试

@Test
public void testConstructor(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-di.xml");
    Book bookConstructor = applicationContext.getBean("bookConstructor", Book.class);
    logger.info("bookCon" + bookConstructor);
}
/*有参构造方法执行了
[2023-06-23 10:13:15:457] [INFO] - TestBeanById.testConstructor(TestBeanById.java:81) - bookConBook{name='三国演义', author='罗贯中'}*/

注入过程中特殊值的处理

字面量赋值

字面量
如:int a = 1;直接赋值,表示我们看到的这个数据本身。

<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>

null值

<bean id="book" class="com.louis.di.Book">
<!--在使用property这个标签时,就会调用类中的set方法-->
    <property name="name" value="红楼梦"></property>
    <property name="author">
        <null></null>
    </property>
</bean>

xml实体

当设置的值中有类似<>的时候,需要进行转义处理。解决方案:用xml实体来代替

 <property name="name" value="&lt;&gt;"></property>

CDATA节

它是xml中一种特殊的写法,当设置的值中有类似<>的时候,就是要写<>时可以使用。

<property name="name">
    <!--CDATA节中写什么符号都随意-->
    <value><![CDATA[ < >]]></value>
</property>

不同类型进行依赖注入

对象类型属性注入

如:部门和员工

Department
public class Department {
    private String dName;
    
    public void info(){
        System.out.println("Department name");
    }
}
Employee
public class Employee {
    private String eName;
    private Integer age;
    private Department dept;


    public void work(){
        System.out.println("Employee working");
    }
}
方式一:引用外部bean
1、生成它们的set方法

Department

//部门类
public class Department {
    private String dname;

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public void info(){
        System.out.println("Department name");
    }
}

Employee

public class Employee {
    private String eName;
    private Integer age;
    private Department dept;

    public String geteName() {
        return eName;
    }

    public void seteName(String eName) {
        this.eName = eName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Department getDept() {
        return dept;
    }

    public void setDept(Department dept) {
        this.dept = dept;
    }

    public void work(){
        System.out.println("Employee working");
        //为了验证引入是否成功
        dept.info();
    }
}
2、编写配置文件
<!--引入外部bean
    1、创建两个类对象:department和employee
    2、在Employee标签里面,使用property引入两个类-->
<bean id="dept" class="com.louis.di_test.Department">
    <property name="dname" value="IT"></property>
</bean>
<bean id="emp" class="com.louis.di_test.Employee">
    <property name="eName" value="Alex"></property>
    <property name="age" value="18"></property>
<!--注入对象类型的熟属性-->
    <property name="dept" ref="dept"></property>
</bean>
3、测试
@Test
public void testObj(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-diTest.xml");
    Employee emp = applicationContext.getBean("emp", Employee.class);
    emp.work();
    logger.info("emp" + emp);
}
/*Employee working
Department name
[2023-06-23 11:45:56:941] [INFO] - TestBeanById.testObj(TestBeanById.java:92) - empEmployee{eName='Alex', age=18, dept=Department{dname='IT'}}
*/
方式二:内部bean
1、生成set方法
2、编写配置文件
<!--内部bean注入-->
<bean id="emp2" class="com.louis.di_test.Employee">
    <property name="eName" value="Louie"></property>
    <property name="age" value="20"></property>
    <!--内部bean-->
    <property name="dept">
        <bean id="dept2" class="com.louis.di_test.Department">
            <property name="dname" value="设计"></property>
         </bean>
    </property>
</bean>
3、测试
@Test
public void testObj2(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-diTest.xml");
    Employee emp2 = applicationContext.getBean("emp2", Employee.class);
    emp2.work();
    logger.info("emp2" + emp2);
}
/*
Employee working
Department name
[2023-06-23 11:54:58:543] [INFO] - TestBeanById.testObj2(TestBeanById.java:104) - emp2Employee{eName='Louie', age=20, dept=Department{dname='设计'}}
*/
方式三:级联属性赋值
1、创建实体对象,生成set方法
2、编写配置文件
<!--级联赋值-->
<bean id="dept3" class="com.louis.di_test.Department">
    <property name="dname" value="超人组"></property>
</bean>
<bean id="emp3" class="com.louis.di_test.Employee">
    <property name="eName" value="khan"></property>
    <property name="age" value="23"></property>
    <property name="dept" ref="dept3"></property>
    <property name="dept.dname" value="研发科"></property>
</bean>
3、测试
@Test
public void testObj3(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-diTest.xml");
    Employee emp3 = applicationContext.getBean("emp3", Employee.class);
    emp3.work();
    logger.info("emp3" + emp3);
}

/*Employee working
Department name
[2023-06-23 12:02:44:654] [INFO] - TestBeanById.testObj3(TestBeanById.java:118) - emp3Employee{eName='khan', age=23, dept=Department{dname='研发科'}}*/

为数组类型属性赋值

1、编写实体类
public class Person {
    private String[] hobby;

    public String[] getHobby() {
        return hobby;
    }

    public void setHobby(String[] hobby) {
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "Person{" +
                "hobby=" + Arrays.toString(hobby) +
                '}';
    }
}
2、编写配置文件
 <!--注入数组类型的属性-->
<bean id="person" class="com.louis.di_array.Person">
    <!--注入数组类型属性值-->
    <property name="hobby">
        <array>
            <value>eat</value>
            <value>sleep</value>
            <value>code</value>
        </array>
    </property>
</bean>
3、测试
@Test
public void testArray(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-diarray.xml");
    Person person = applicationContext.getBean("person", Person.class);
    logger.info("person" + person);
}

/*[2023-06-23 12:14:00:835] [INFO] - TestBeanById.testArray(TestBeanById.java:129) - personPerson{hobby=[eat, sleep, code]}*/

为集合类型属性赋值

(一)为list集合类型属性赋值
1、编写实体类并生成set方法

Department

public class Department {
    private String dname;
    private List<Employee> empList;

    public List<Employee> getEmpList() {
        return empList;
    }

    public void setEmpList(List<Employee> empList) {
        this.empList = empList;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public void info(){
        System.out.println("Department name");
    }

    @Override
    public String toString() {
        return "Department{" +
                "dname='" + dname + '\'' +
                ", empList=" + empList +
                '}';
    }
}

Employee

public class Employee {
    private String eName;
    private Integer age;
    private Department dept;

    public String geteName() {
        return eName;
    }

    public void seteName(String eName) {
        this.eName = eName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Department getDept() {
        return dept;
    }

    public void setDept(Department dept) {
        this.dept = dept;
    }

    public void work(){
        System.out.println("Employee working");
        dept.info();
    }

    @Override
    public String toString() {
        return "Employee{" +
                "eName='" + eName + '\'' +
                ", age=" + age +
                ", dept=" + dept +
                '}';
    }
}
2、编写配置文件
<!--实现list集合注入-->
<bean id="emp" class="com.louis.di_test.Employee">
    <property name="eName" value="Louis"></property>
    <property name="age" value="23"></property>
</bean>
<bean id="empTwo" class="com.louis.di_test.Employee">
    <property name="eName" value="Alex"></property>
    <property name="age" value="22"></property>
</bean>
<bean id="dept" class="com.louis.di_test.Department">
    <property name="dname" value="研发科"></property>
    <property name="empList">
        <list>
<!--如果是字符串和基本数据类型,可以直接使用<value>标签-->
            <ref bean="emp"></ref>
            <ref bean="empTwo"></ref>
        </list>
    </property>
</bean>
3、测试
@Test
public void testList(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-dilist.xml");
    Department dept = applicationContext.getBean("dept", Department.class);
    dept.info();
    logger.info("dept" + dept);
}

/*Department name
employee.geteName() = Louis
employee.geteName() = Alex
[2023-06-23 12:31:05:121] [INFO] - TestBeanById.testList(TestBeanById.java:139) - deptDepartment{dname='研发科', empList=[Employee{eName='Louis', age=23, dept=null}, Employee{eName='Alex', age=22, dept=null}]}
*/
(二)为Map集合属性注入值
1、编写实体类并生成set方法

Student

public class Student {
    private String sname;
    private String sid;
    //一个学生可能对应多个老师
    private Map<String, Teacher> teacherMap;

    public Map<String, Teacher> getTeacherMap() {
        return teacherMap;
    }

    public void setTeacherMap(Map<String, Teacher> teacherMap) {
        this.teacherMap = teacherMap;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }
    
    public void learn(){
        System.out.println("学生姓名" + sname + "----" + "学号" + sid);
        System.out.println(teacherMap);
    }

    @Override
    public String toString() {
        return "Student{" +
                "sname='" + sname + '\'' +
                ", sid='" + sid + '\'' +
                ", teacherMap=" + teacherMap +
                '}';
    }
}

Teacher

public class Teacher {
    private String tname;
    private String tid;

    public String getTname() {
        return tname;
    }

    public void setTname(String tname) {
        this.tname = tname;
    }

    public String getTid() {
        return tid;
    }

    public void setTid(String tid) {
        this.tid = tid;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "tname='" + tname + '\'' +
                ", tid='" + tid + '\'' +
                '}';
    }
}
2、编写配置文件
    <!--
    1、创建两个对象
    2、注入普通类型属性
    3、在学生bean注入map集合类型属性
    -->
<bean id="teacher" class="com.louis.di_map.Teacher">
    <property name="tid" value="110"></property>
    <property name="tname" value="Alex"></property>
</bean>
<bean id="teacher2" class="com.louis.di_map.Teacher">
    <property name="tid" value="120"></property>
    <property name="tname" value="Khan"></property>
</bean>
<bean id="student" class="com.louis.di_map.Student">
    <property name="sid" value="18162004"></property>
    <property name="sname" value="Louie"></property>
    <property name="teacherMap">
        <map>
            <entry>
                <key>
                    <value>key1</value>
                </key>
                <ref bean="teacher"></ref>
            </entry>
            <entry>
                <key>
                    <value>key2</value>
                </key>
                <ref bean="teacher2"></ref>
            </entry>
        </map>
    </property>
</bean>
3、测试
@Test
public void testMap(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-diMap.xml");
    Student student = applicationContext.getBean("student", Student.class);
    logger.info("student" + student);
    student.learn();
}

/*[2023-06-23 12:57:29:327] [INFO] - TestBeanById.testMap(TestBeanById.java:152) - studentStudent{sname='Louie', sid='18162004', teacherMap={key1=Teacher{tname='Alex', tid='110'}, key2=Teacher{tname='Khan', tid='120'}}}
学生姓名Louie----学号18162004
{key1=Teacher{tname='Alex', tid='110'}, key2=Teacher{tname='Khan', tid='120'}}*/
引用集合类型的bean

将list和map的实现方式换一种写法。

1、在原有的Student和Teacher的基础上,再添加一个Lesson类
public class Lesson {
    private String lessonName;

    public String getLessonName() {
        return lessonName;
    }

    public void setLessonName(String lessonName) {
        this.lessonName = lessonName;
    }

    @Override
    public String toString() {
        return "Lesson{" +
                "lessonName='" + lessonName + '\'' +
                '}';
    }
}
2、再Student类中添加课程列表
List<Lesson> list;

public List<Lesson> getList() {
    return list;
}

public void setList(List<Lesson> list) {
    this.list = list;
}
3、编写配置文件

加上util的命名空间引入

<?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:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
       http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--
    1、创建三个对象
    2、注入普通类型属性
    3、使用util:类型 定义。需要更改命名空间引入
    4、在学生bean引入util:类型定义bean,完成list、map类型注入
    -->
    <bean id="lessonOne" class="com.louis.di_map.Lesson">
        <property name="lessonName" value="JAVA开发"></property>
    </bean>
    <bean id="lessonTwo" class="com.louis.di_map.Lesson">
        <property name="lessonName" value="Python 开发"></property>
    </bean>
    <bean id="teacherOne" class="com.louis.di_map.Teacher">
        <property name="tname" value="Louie"></property>
        <property name="tid" value="11011"></property>
    </bean>
    <bean id="teacherTwo" class="com.louis.di_map.Teacher">
        <property name="tname" value="Alex"></property>
        <property name="tid" value="12012"></property>
    </bean>
    <bean id="student" class="com.louis.di_map.Student">
        <property name="sname" value="khan"></property>
        <property name="sid" value="201811011"></property>
        <!--注入list、map类型的属性-->
        <property name="list" ref="lessonList"></property>
        <property name="teacherMap" ref="teacherMap"></property>
    </bean>
    <util:list id="lessonList">
        <ref bean="lessonOne"></ref>
        <ref bean="lessonTwo"></ref>
    </util:list>
    <util:map id="teacherMap">
        <entry>
            <key>
                <value>111</value>
            </key>
            <ref bean="teacherOne"></ref>
        </entry>
        <entry>
            <key>
                <value>222</value>
            </key>
            <ref bean="teacherTwo"></ref>
        </entry>
    </util:map>
</beans>
4、测试
@Test
public void testUtil(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-diRef.xml");
    Student student = applicationContext.getBean("student", Student.class);
    student.learn();
    logger.info("student" + student);
}

/*学生姓名khan----学号201811011
{111=Teacher{tname='Louie', tid='11011'}, 222=Teacher{tname='Alex', tid='12012'}}
[2023-06-23 14:28:04:062] [INFO] - TestBeanById.testUtil(TestBeanById.java:164) - studentStudent{sname='khan', sid='201811011', teacherMap={111=Teacher{tname='Louie', tid='11011'}, 222=Teacher{tname='Alex', tid='12012'}}, list=[Lesson{lessonName='JAVA开发'}, Lesson{lessonName='Python 开发'}]}
*/
p命名空间

命名空间:为避免命名时冲突,再命名后面加上:重命名的方式

xmlns:p = "http://www.springframework.org/schema/p"
编写配置文件
<!--p命名空间注入-->
<bean id="studentP" class="com.louis.di_map.Student" p:sid="201811" p:sname="Louis" p:list-ref="lessonList" p:teacherMap-ref="teacherMap">
</bean>
<util:list id="lessonList">
    <ref bean="lessonOne"></ref>
    <ref bean="lessonTwo"></ref>
</util:list>
<util:map id="teacherMap">
    <entry>
        <key>
            <value>111</value>
        </key>
        <ref bean="teacherOne"></ref>
    </entry>
    <entry>
        <key>
            <value>222</value>
        </key>
        <ref bean="teacherTwo"></ref>
    </entry>
</util:map>
测试
@Test
public void testP(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-diRef.xml");
    Student studentP = applicationContext.getBean("studentP", Student.class);
    studentP.learn();
    logger.info("studentP" + studentP);
}

/*学生姓名Louis----学号201811
{111=Teacher{tname='Louie', tid='11011'}, 222=Teacher{tname='Alex', tid='12012'}}
[2023-06-23 14:43:14:562] [INFO] - TestBeanById.testP(TestBeanById.java:176) - studentPStudent{sname='Louis', sid='201811', teacherMap={111=Teacher{tname='Louie', tid='11011'}, 222=Teacher{tname='Alex', tid='12012'}}, list=[Lesson{lessonName='JAVA开发'}, Lesson{lessonName='Python 开发'}]}
*/

引入外部属性文件

应用场景:在一个文件中如果出现多个bean的创建和注入,维护就会比较困难。可以将一些特定的文件放在特定位置在spring中进行引入,如数据库文件。

实现步骤(数据库的配置文件引入)

1、引入相关依赖
 <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.16</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.33</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-dbutils/commons-dbutils -->
<dependency>
    <groupId>commons-dbutils</groupId>
    <artifactId>commons-dbutils</artifactId>
    <version>1.7</version>
</dependency>
2、创建Dbutils.properties
username=root
password=root
url=jdbc:mysql://localhost:3306/spring
driver=com.mysql.cj.jdbc.Driver
3、创建spring的配置文件

引入context命名空间,引入属性文件,使用表达式完成注入。

context命名空间

xmlns:contex="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"

引入属性文件

<!--引入外部属性文件-->
<contex:property-placeholder location="classpath:Dbutils.properties"></contex:property-placeholder>

完整配置

<?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:contex="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--引入外部属性文件-->
    <contex:property-placeholder location="classpath:Dbutils.properties"></contex:property-placeholder>
<!--完成数据库信息注入-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${url}"></property>
        <property name="username" value="${username}"></property>
        <property name="password" value="${password}"></property>
        <property name="driver" value="${driver}"></property>
    </bean>
</beans>
4、测试
@Test
public void testDbutils(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean-Dbutils.xml");
    DruidDataSource dataSource = applicationContext.getBean("druidDataSource", DruidDataSource.class);
    logger.info("dataSource" + dataSource);
}
/*
* [2023-06-23 15:36:52:008] [INFO] - TestBeanById.testDbutils(TestBeanById.java:189) - dataSource{
    CreateTime:"2023-06-23 15:36:51",
    ActiveCount:0,
    PoolingCount:0,
    CreateCount:0,
    DestroyCount:0,
    CloseCount:0,
    ConnectCount:0,
    Connections:[
    ]
}
* */

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/43081.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

K8S下如何搭建eureka集群

背景 传统应用上云&#xff0c;基于传统应用需要考虑上云的方案和改造成本&#xff0c;这也是传统应用上云过程中的难点&#xff0c;本篇介绍3台eureka搭建的方案。 方案一 此方案借助了K8S中Service的一些功能。 这种方案是传统方案的简单迁移版本&#xff0c;比较易于理解…

19.主题时钟

主题时钟 html部分 <div class"btn">黑色</div><div class"clock-container"><div class"time">21</div><div class"date">21</div><div class"clock"><div class&qu…

MOS,PCB如何添加散热孔、过孔

一、什么是 PCB 散热孔&#xff1f; 散热孔是利用贯通PCB板的通道&#xff08;过孔&#xff09;使热量传导到背面来散热的手法&#xff0c;配置在发热体的正下方或尽可能靠近发热体。 散热孔是利用PCB板来提高表面贴装部件散热效果的一种方法&#xff0c;在结构上是在PCB板上…

IMU和视觉融合学习笔记

利用纯视觉信息进行位姿估计&#xff0c;对运动物体、光照干扰、场景纹理缺失等情况&#xff0c;定位效果不够鲁棒。当下&#xff0c;视觉与IMU融合(VI-SLAM&#xff09;逐渐成为常见的多传感器融合方式。视觉信息与IMU 数据进行融合&#xff0c;根据融合方式同样可分为基于滤波…

【《机器学习和深度学习:原理、算法、实战(使用Python和TensorFlow)》——以机器学习理论为基础并包含其在工业界的实践的一本书】

机器学习和深度学习已经成为从业人员在人工智能时代必备的技术&#xff0c;被广泛应用于图像识别、自然语言理解、推荐系统、语音识别等多个领域&#xff0c;并取得了丰硕的成果。目前&#xff0c;很多高校的人工智能、软件工程、计算机应用等专业均已开设了机器学习和深度学习…

「网络编程」传输层协议_ TCP协议学习_及原理深入理解(一)[万字详解]

「前言」文章内容大致是传输层协议&#xff0c;TCP协议讲解&#xff0c;续上篇UDP协议。 「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、TCP协议介绍二、TCP协议2.1 解包与分用2.2 谈谈可靠性2.3 TCP的工作模式2.4 确认应答(ACK)机制2.5 16位序号与…

绘出「星辰大海」:华为云Astro轻应用新手指南-第二章

第2章 Astro轻应用奇遇——用鼠标「拖拽」的开发 不被编程所困&#xff0c;像玩拼图一样打造订购系统&#xff01; 今天&#xff0c;我们用鼠标拖拽的方式开发订餐应用。 读过本章&#xff0c;你可以同理开发出各异的订购小程序。 继续Astro轻应用旅行吧&#xff01; 第1站…

WebSocket笔记

1. websocket介绍 WebSocket 是基于 TCP 的一种新的网络协议。它实现了浏览器与服务器全双工通信——浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c; 并进行双向数据传输。 HTTP协议和WebSocket协议对比&#xff1a; HTTP是短连接W…

【JavaWeb】Tomcat底层机制和Servlet运行原理

&#x1f384;欢迎来到dandelionl_的csdn博文&#xff0c;本文主要讲解Java web中Tomcat底层机制和Servlet的运行原理的相关知识&#x1f384; &#x1f308;我是dandelionl_&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一…

iNav开源代码之Filters

iNav开源代码之Filters 1. 源由2. 滤波器应用类型2.1 一般滤波2.1.1 pt1Filter2.1.2 pt2Filter2.1.3 pt3Filter2.1.4 biquadFilter2.2 kalman滤波2.3 动态gyro带通滤波2.3.1 dynamicGyroNotchFilters2.3.2 secondaryDynamicGyroNotchFilters 2.4 rpm滤波 3. 滤波器技术类型3.1 …

C# SolidWorks 二次开发 -从零开始创建一个插件(2)

上一篇我详细讲解了如何创建一个插件&#xff0c;但是无界面无按钮&#xff0c;这种插件适合配合事件偷偷的在后台做点什么事情。今天这篇讲一下如何增加一些按钮到工具栏、菜单上去。 先告诉大家这个东西注册表在哪&#xff0c;因为solidworks在这方面做的不太好&#xff0c;…

prometheus监控mysql8.x以及主从监控告警

mysql8.x主从部署请看下面文档 docker和yum安装的都有 Docker部署mysql8.x版本互为主从_争取不加班&#xff01;的博客-CSDN博客 Mysql8.x版本主从加读写分离&#xff08;一&#xff09; mysql8.x主从_myswl8双主一从读写分离_争取不加班&#xff01;的博客-CSDN博客 安装部署…

uniapp 微信小程序 placeholder字体、颜色自定义

效果图&#xff1a; 1、template <input type"text" placeholder"搜索标题" placeholder-class"placeholder-style"></input>2、style .placeholder-style{color: #2D94FF; }

通过nexus3部署公司内部的私有npm仓库

简介&#xff1a; 登录时使用默认用户admin&#xff0c;密码不知道就需要找默认的&#xff0c;点击Sign in时会提示你路径&#xff0c;这里我是这样查的&#xff0c;在linux服务器上输入以下命令 ​编辑 前言&#xff1a; 准备工作&#xff0c;可能需要一台linux服务器&#x…

讯为RK3568开发板入门之-tftpnfs的配置

基础条件 VMware虚拟机 Ubuntu18.04 【网络配置陈桥接模式】 RK3568开发板【我是用讯为的RK3568】 网线连接路由器或者和电脑直连 配置TFTP和NFS的作用 使用tftp和nfs网络挂载可以很方便的进行软件的调试&#xff0c;挂载成功后只要把Ubuntu下编译好的文件程序放到挂载的目录…

思科路由器交换机密码破解教程

1. 路由器密码的恢复. 2600、3600等新系列路由器步骤&#xff1a; 1、启动路由器&#xff0c;60秒内按下ctrlbreak键2、rommon>confreg 0x21423、rommon>reset4、router#copy startup-config running-config5、router(config)#no enable secrect //可以删除密码也可以更…

一键批量JSON标注转PNG图片工具V1.1,支持labelme快捷矩形、圆以及轮廓标注

上次发布了一个批量将labelme标注的json文件转换为png文件工具&#xff0c;但是当时只是想着自己用的&#xff0c;功能相当简单&#xff0c;一些网友使用之后跟我反馈这玩意真”垃圾“&#xff0c;很多情况都没有进行设想&#xff0c;所以在功能上很欠缺。由于小陶这几天在外地…

如何提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析能力

专题一、空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 Geodatabase地理数据库 专题二、ArcGIS专题地图制作 2.1专题地图制作规范 2.2 空间数据的准备与处理 2.3 空间数据可视化&#xff1a;地图符号与…

HTTP超本文传输协议

HTTP超本文传输协议 HTTP简介HTTP请求与响应HTTP请求请求行请求头空行请求体 HTTP响应响应行响应头空行响应体 HTTP请求方法GET和POST之间的区别HTTP为什么是无状态的cookie原理session 原理cookie 和 session 的区别cookie如何设置cookie被禁止后如何使用session HTTP简介 HT…

Java基础之stream流最新版,stream流的基本操作

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…