1. 环境搭建
参考我之前的笔记: Spring6 基础入门-CSDN博客
2. 获取Bean的方式
2.1 根据Id 获取
参考之前的笔记: Spring6 基础入门-CSDN博客
@Testpublic void testGetBeanById(){//加载spring配置文件ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");//获取创建的对象User user = (User) context.getBean("user");System.out.println(user);//使用对象调用方法进行测试user.add();}
2.2 根据类型获取Bean
@Testpublic void testGetBeanByType(){//加载spring配置文件ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");//获取创建的对象User user = (User) context.getBean(User.class);System.out.println(user);//使用对象调用方法进行测试user.add();}
如果bean.xml文件中有相同的对象(class一样,id不一样),例如:
<bean id="user" class="org.example.User"/> <bean id="user2" class="org.example.User"/>
就会出现这个错误:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.example.User' available: expected single matching bean but found 2: user,user2
当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个
2.3 根据类型和id获取Bean
@Testpublic void testGetBeanByIdAndType(){//加载spring配置文件ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");//获取创建的对象User user = (User) context.getBean("user",User.class);System.out.println(user);//使用对象调用方法进行测试user.add();}
3. 依赖注入之 setter
类有属性,创建对象的过程中,向属性设置值。
创建Book.java
package org.example.entity;public class Book {private String bookName;private String bookAuthor;// 创建无参构造器public Book(){}// 创建有参构造器public Book(String bookName){this.bookName = bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public void setBookAuthor(String bookAuthor) {this.bookAuthor = bookAuthor;}public String getBookName() {return bookName;}public String getBookAuthor() {return bookAuthor;}@Overridepublic String toString() {return "Book{" +"bookName='" + bookName + '\'' +", bookAuthor='" + bookAuthor + '\'' +'}';}
}
3.1 原生注入
@Testpublic void testSetBookName1(){Book book = new Book();book.setBookName("Think in Java");}@Testpublic void testSetBookName2(){Book book = new Book("Think in Java","Dylan");}
3.2. 用spring的方式注入值
修改xml文件
<bean id="book" class="org.example.entity.Book"><property name="bookName" value="西游记" /><property name="bookAuthor" value="吴承恩" /></bean>
测试
@Testpublic void testSetBookNameBySpring(){ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");Book book = (Book)context.getBean("book");System.out.println(book);}Book{bookName='西游记', bookAuthor='吴承恩'}
4. 依赖注入之 构造器
创建类,定义属性,生成有参构造方法
4.1 还是使用Book.java
修改xml配置文件
<!--构造器 方法注入--><bean id="bookConst" class="org.example.entity.Book"><constructor-arg name="bookName" value="水浒传" /><constructor-arg name="bookAuthor" value="施耐庵" /></bean>
测试
@Testpublic void testSetBookNameBySpring2(){ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");Book book = (Book)context.getBean("bookConst");System.out.println(book);}
5. 依赖注入特殊值处理
5.1 字面量赋值
什么是字面量?
int a = 10;声明一个变量a,初始化为10,此时a就不代表字母a了,而是作为一个变量的名字。当我们引用a的时候,我们实际上拿到的值是10。
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="bookName" value="西游记" />
5.2 null值的处理
<!-- null 值的处理--><bean id="book2" class="org.example.entity.Book"><property name="bookName" ><null/></property></bean><!--如果是这样,bookName的值就是 字符串 "null"--><bean id="book2" class="org.example.entity.Book"><property name="bookName" value="null" /></bean>
5.3 xml 实体
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 使用XML实体来代替 -->
<property name="expression" value="a < b"/>
5.4 CDATA
<!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 --><!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 --><!-- 所以CDATA节中写什么符号都随意 --><bean id="book3" class="org.example.entity.Book"><property name="bookName" ><value><![CDATA[a < b]]></value></property></bean>
6. 特殊类型的注入
6.1 对象类型注入
创建Dept.java
package org.example.entity;public class Dept {private String dname;public String getDname() {return dname;}public void setDname(String dname) {this.dname = dname;}public void info(){System.out.println("部门名称:"+dname);}
}
创建Emp.java
package org.example.entity;public class Emp {//员工属于某个部门private Dept dept;private String ename;private Integer age;public Dept getDept() {return dept;}public void setDept(Dept dept) {this.dept = 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 void work(){System.out.println("员工:"+ename+" 年龄:"+ age + " work...");dept.info();}
}
6.1.1 引用外部bean
修改xml 配置文件:
<bean id="debt" class="org.example.entity.Dept"><property name="dname" value="财务部"/></bean><bean id="emp" class="org.example.entity.Emp"><!--普通注入--><property name="ename" value="Dylan"/><property name="age" value="18"/><!-- 对象注入,不能用value 要用ref引用外部类 --><property name="dept" ref="debt"/></bean>
测试:
@Testpublic void testEmpBySpring(){ApplicationContext context = new ClassPathXmlApplicationContext("bean-di-test.xml");Emp emp = (Emp)context.getBean("emp");emp.work();}
6.1.2 内部bean
修改xml配置文件(就是在property标签内部再写一个bean标签 )
<bean id="emp2" class="org.example.entity.Emp"><!--普通注入--><property name="ename" value="Frank"/><property name="age" value="20"/><!-- 对象注入,不能用value 要用ref引用外部类 --><property name="dept"><bean class="org.example.entity.Dept"><property name="dname" value="安保部"/></bean></property></bean>
6.1.3 级联属性赋值
<bean id="debt" class="org.example.entity.Dept"><property name="dname" value="财务部"/></bean><bean id="emp" class="org.example.entity.Emp"><!--普通注入--><property name="ename" value="Dylan"/><property name="age" value="18"/><!-- 对象注入,不能用value 要用ref引用外部类 --><property name="dept" ref="debt"/><property name="dept.dname" value="科研部"/></bean>
6.2 数组类型注入
修改Emp.java ,增加如下代码
private String[] loves;public String[] getLoves() {return loves;}public void setLoves(String[] loves) {this.loves = loves;}
修改Xml 配置文件
<bean id="emp" class="org.example.entity.Emp"><!--普通注入--><property name="ename" value="Dylan"/><property name="age" value="18"/><property name="dept" ref="debt"/><!-- 注入数组 --><property name="loves"><array><value>吃饭</value><value>睡觉</value><value>打豆豆</value></array></property></bean>
6.3 注入集合
6.3.1 注入List
修改 Dept.java,增加如下代码
private List<Emp> empList;public List<Emp> getEmpList() {return empList;}public void setEmpList(List<Emp> empList) {this.empList = empList;}
修改xml配置文件
<bean id="dept" class="org.example.entity.Dept"><property name="dname" value="财务部"/><property name="empList"><list><ref bean="emp"/><ref bean="emp2"/></list></property></bean><bean id="emp" class="org.example.entity.Emp"><property name="ename" value="Dylan"/><property name="age" value="18"/></bean><bean id="emp2" class="org.example.entity.Emp"><property name="ename" value="Tom"/><property name="age" value="28"/></bean>
6.3.2 注入Map
创建Student.java
package org.example.entity;import java.util.Map;public class Student {private String sName;private String sNo;private Map<String,Teacher> teacherMap;public String getsName() {return sName;}public void setsName(String sName) {this.sName = sName;}public String getsNo() {return sNo;}public void setsNo(String sNo) {this.sNo = sNo;}public Map<String, Teacher> getTeacherMap() {return teacherMap;}public void setTeacherMap(Map<String, Teacher> teacherMap) {this.teacherMap = teacherMap;}@Overridepublic String toString() {return "Student{" +"sName='" + sName + '\'' +", sNo='" + sNo + '\'' +", teacherMap=" + teacherMap +'}';}
}
创建Teacher.java
package org.example.entity;public class Teacher {private String tNo;private String tName;public String gettNo() {return tNo;}public void settNo(String tNo) {this.tNo = tNo;}public String gettName() {return tName;}public void settName(String tName) {this.tName = tName;}@Overridepublic String toString() {return "Teacher{" +"tNo='" + tNo + '\'' +", tName='" + tName + '\'' +'}';}
}
修改xml文件
<bean id="student" class="org.example.entity.Student"><property name="sNo" value="0001"/><property name="sName" value="z3"/><property name="teacherMap"><map><entry key="k1" value-ref="techer"/><entry key="k2" value-ref="techer2"/></map></property></bean><bean id="techer" class="org.example.entity.Teacher"><property name="tNo" value="10001"/><property name="tName" value="teacher Zhang"/></bean><bean id="techer2" class="org.example.entity.Teacher"><property name="tNo" value="10001"/><property name="tName" value="teacher Li"/></bean>
6.3.3 引用集合类型的bean(把list 和 map的注入换一种方式实现)
创建Lesson.java
package org.example.entity;public class Lesson {private String lessonName;public String getLessonName() {return lessonName;}public void setLessonName(String lessonName) {this.lessonName = lessonName;}@Overridepublic String toString() {return "Lesson{" +"lessonName='" + lessonName + '\'' +'}';}
}
需改Student.java (增加Lesson的代码)
private List<Lesson> lessonList;public List<Lesson> getLessonList() {return lessonList;}public void setLessonList(List<Lesson> lessonList) {this.lessonList = lessonList;}
修改xml配置文件
使用util:list、util:map标签必须引入相应的命名空间
<?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/utilhttp://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">增加了:xmlns:util="http://www.springframework.org/schema/util"http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsd<bean id="student" class="org.example.entity.Student"><property name="sName" value="z3"/><property name="sNo" value="10000"/><property name="lessonList" ref="lessonList1"/><property name="teacherMap" ref="teacherMap"/></bean><util:list id="lessonList1"><ref bean="lesson"/><ref bean="lesson2"/></util:list><util:map id="teacherMap"><entry key="01" value-ref="teacher"/><entry value-ref="teacher2" key="02"/></util:map><bean id="teacher" class="org.example.entity.Teacher"><property name="tName" value="teanher zhang"/><property name="tNo" value="00001"/></bean><bean id="teacher2" class="org.example.entity.Teacher"><property name="tName" value="teanher Li"/><property name="tNo" value="00002"/></bean><bean id="lesson" class="org.example.entity.Lesson"><property name="lessonName" value="语文"/></bean><bean id="lesson2" class="org.example.entity.Lesson"><property name="lessonName" value="数学"/></bean>
</beans>
记得修改Student.java 的toString()方法,把Lesson也打印出来
7 p命名空间
7.1 引入p命名空间(必须)
<?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"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">增加了:xmlns:p="http://www.springframework.org/schema/p"
7.2 在原有的<bean>标签中加入p
<bean id="student" class="org.example.entity.Student" p:sName="li 4" p:sNo="10000"p:lessonList-ref="lessonList1" p:teacherMap-ref="teacherMap"></bean>
8 引入外部文件
8.1 引入数据库相关依赖
<!-- MySOL 驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.31</version></dependency><!-- 数据源 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.31</version></dependency>
8.2 创建外部文件
创建jdbc.properties
jdbc.user=root
jdbc.password=root
jdbc.url=jdbc:mysql://localhost:3306/myBatis01?useUnicode=true&characterEncoding=utf-8
jdbc.driver=com.mysql.jdbc.Driver
8.3 引入context命名空间及外部文件
<?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:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd">增加了:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd<!-- 引入外部文件 --><context:property-placeholder location="jdbc.properties"/><bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.user}"/><property name="password" value="${jdbc.password}"/><property name="driverClassName" value="${jdbc.driver}"/></bean>
</beans>
9 Bean的作用域
取值 | 含义 | 创建对象的时机 |
singleton(默认) | 在IOC容器中,这个bean的对象始终为但实例 | IOC容器初始化时 |
prototype | 这个bean在IOC容器中有多个实例 |
配置xml
<!-- scope属性:取值singleton(默认值),bean在IOC容器中只有一个实例,IOC容器初始化时创建对象.创建的对应的地址都一样 --><!-- scope属性:取值prototype,bean在IOC容器中可以有多个实例,getBean()时创建对象 --><bean id="dept" class="org.example.entity.Dept" scope="prototype"/>
测试
@Testpublic void testScope(){ApplicationContext context = new ClassPathXmlApplicationContext("bean-di-test.xml");Dept dept1 = context.getBean("dept",Dept.class);Dept dept2 = context.getBean("dept",Dept.class);System.out.println(dept1 == dept2);}
10. bean的生命周期
-
bean对象创建(调用无参构造器)
-
给bean对象设置属性
-
bean的前置处理器(初始化之前)
-
bean对象初始化(需在配置bean时指定初始化方法)
-
bean的后置处理器(初始化之后)
-
bean对象就绪可以使用
-
bean对象销毁(需在配置bean时指定销毁方法)
-
IOC容器关闭
创建User.java
ininMethod()和destroyMethod(),需要在xml配置文件中配置才能生效
package org.example.entity;public class User {private String uName;public User(){System.out.println("生命周期:1、调用无参构造 创建对象");}public String getuName() {return uName;}public void setuName(String uName) {System.out.println("生命周期:2、给bean对象属性注入值");this.uName = uName;}public void ininMethod(){System.out.println("生命周期:4、bean对象初始化,调用指定的方法");}public void destroyMethod(){System.out.println("生命周期:7、bean对象销毁,调用指定的方法");}
}
10.1 创建bean的前/后置处理器
bean的前/后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean前/后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行
创建MyBeanPost.java
package org.example.life;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPost implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("生命周期:3、bean的前置处理器");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("生命周期:5、bean的后置处理器");return bean;}
}
修改xml配置文件
<bean id="user" class="org.example.entity.User" init-method="ininMethod" destroy-method="destroyMethod"><property name="uName" value="dylan"/></bean><!--bean的后置处理器要放入IOC容器中才能生效--><bean id="myBeanPost" class="org.example.life.MyBeanPost"/>
测试
这里使用ClassPathXmlApplicationContext ,因为它有close()方法。
@Testpublic void testBeanLife(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-di-test.xml");org.example.entity.User user = context.getBean("user", org.example.entity.User.class);System.out.println("生命周期:6、bean对象创建完成,可以使用了");System.out.println(user);context.close();}
11. FactoryBean
它是Spring中的一种机制,Spring把复杂的过程做了封装。表面上看是一个简介的展现。
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。
创建MyFactoryBean.java
package org.example.factorybean;import org.example.entity.User;
import org.springframework.beans.factory.FactoryBean;public class MyFactoryBean implements FactoryBean<User> {@Overridepublic User getObject() throws Exception {return new User();}@Overridepublic Class<?> getObjectType() {return null;}
}
修改xml配置文件
<bean id="myfactoryBean" class="org.example.factorybean.MyFactoryBean"/>
测试
@Testpublic void testBeanFactoryBean(){ApplicationContext context = new ClassPathXmlApplicationContext("bean-di-test.xml");org.example.entity.User user = context.getBean("myfactoryBean", org.example.entity.User.class);System.out.println(user);