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对象 |
ConfigurableApplicationContext | ApplicationContext的子接口,包含一些扩展方法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="<>"></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:[
]
}
* */