1. 环境搭建
参考我之前的笔记: Spring6 基础入门-CSDN博客
2. 获取Bean的方式
2.1 根据Id 获取
参考之前的笔记: Spring6 基础入门-CSDN博客
java
@Test
public void testGetBeanById(){
//加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//获取创建的对象
User user = (User) context.getBean("user");
System.out.println(user);
//使用对象调用方法进行测试
user.add();
}
2.2 根据类型获取Bean
java
@Test
public 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
java
@Test
public 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
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;
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
", bookAuthor='" + bookAuthor + '\'' +
'}';
}
}
3.1 原生注入
java
@Test
public void testSetBookName1(){
Book book = new Book();
book.setBookName("Think in Java");
}
@Test
public void testSetBookName2(){
Book book = new Book("Think in Java","Dylan");
}
3.2. 用spring的方式注入值
修改xml文件
java
<bean id="book" class="org.example.entity.Book">
<property name="bookName" value="西游记" />
<property name="bookAuthor" value="吴承恩" />
</bean>
测试
java
@Test
public 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配置文件
java
<!--构造器 方法注入-->
<bean id="bookConst" class="org.example.entity.Book">
<constructor-arg name="bookName" value="水浒传" />
<constructor-arg name="bookAuthor" value="施耐庵" />
</bean>
测试
java
@Test
public 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。
java
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="bookName" value="西游记" />
5.2 null值的处理
java
<!-- 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 实体
java
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 使用XML实体来代替 -->
<property name="expression" value="a < b"/>
5.4 CDATA
java
<!-- 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
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
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 配置文件:
java
<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>
测试:
java
@Test
public 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标签 )
java
<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 级联属性赋值
java
<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 ,增加如下代码
java
private String[] loves;
public String[] getLoves() {
return loves;
}
public void setLoves(String[] loves) {
this.loves = loves;
}
修改Xml 配置文件
java
<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,增加如下代码
java
private List<Emp> empList;
public List<Emp> getEmpList() {
return empList;
}
public void setEmpList(List<Emp> empList) {
this.empList = empList;
}
修改xml配置文件
java
<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
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;
}
@Override
public String toString() {
return "Student{" +
"sName='" + sName + '\'' +
", sNo='" + sNo + '\'' +
", teacherMap=" + teacherMap +
'}';
}
}
创建Teacher.java
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;
}
@Override
public String toString() {
return "Teacher{" +
"tNo='" + tNo + '\'' +
", tName='" + tName + '\'' +
'}';
}
}
修改xml文件
java
<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
java
package org.example.entity;
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 + '\'' +
'}';
}
}
需改Student.java (增加Lesson的代码)
java
private List<Lesson> lessonList;
public List<Lesson> getLessonList() {
return lessonList;
}
public void setLessonList(List<Lesson> lessonList) {
this.lessonList = lessonList;
}
修改xml配置文件
使用util:list、util:map标签必须引入相应的命名空间
java
<?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">
增加了:xmlns:util="http://www.springframework.org/schema/util"
http://www.springframework.org/schema/util
http://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命名空间(必须)
java
<?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/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">
增加了:xmlns:p="http://www.springframework.org/schema/p"
7.2 在原有的<bean>标签中加入p
java
<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 引入数据库相关依赖
java
<!-- 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
java
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命名空间及外部文件
java
<?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/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">
增加了:
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
java
<!-- scope属性:取值singleton(默认值),bean在IOC容器中只有一个实例,IOC容器初始化时创建对象.创建的对应的地址都一样 -->
<!-- scope属性:取值prototype,bean在IOC容器中可以有多个实例,getBean()时创建对象 -->
<bean id="dept" class="org.example.entity.Dept" scope="prototype"/>
测试
java
@Test
public 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配置文件中配置才能生效
java
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
java
package org.example.life;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("生命周期:3、bean的前置处理器");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("生命周期:5、bean的后置处理器");
return bean;
}
}
修改xml配置文件
java
<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()方法。
java
@Test
public 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
java
package org.example.factorybean;
import org.example.entity.User;
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
return new User();
}
@Override
public Class<?> getObjectType() {
return null;
}
}
修改xml配置文件
java
<bean id="myfactoryBean" class="org.example.factorybean.MyFactoryBean"/>
测试
java
@Test
public 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);