目录
IoC容器
概述
依赖注入
IoC容器在Spring中的实现
基于xml管理bean
获取bean
依赖注入
setter注入
构造器注入
特殊值处理
字面量赋值
null值
xml实体
CDATA节
特殊类型属性注入
对象类型属性注入
方式一:引用外部bean
方式二:内部bean
方式三:级联属性赋值
数组类型属性注入
集合类型属性注入
list、set集合类型
map集合类型
引用集合类型
p命名空间
引入外部属性文件
bean的作用域
bean的生命周期
FactoryBean
基于xml自动装配
IoC容器
概述
IoC 是 Inversion of Control 的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序
Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别
控制反转是一种思想
控制反转是为了降低程序耦合度,提高程序扩展力
控制反转,反转的是什么?
- 将对象的创建权利交出去,交给第三方容器负责
- 将对象和对象之间关系的维护权交出去,交给第三方容器负责
控制反转这种思想如何实现呢?
- DI(Dependency Injection):依赖注入
依赖注入
DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想
依赖注入:Spring创建对象的过程中,将对象依赖属性通过配置进行注入
依赖注入常见的实现方式包括两种:
- set注入
- 构造注入
Bean管理:Bean对象的创建以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)
IoC容器在Spring中的实现
Spring 的 IoC 容器就是 IoC思想的一个落地的产品实现。IoC容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建IoC 容器。Spring 提供了IoC 容器的两种实现方式:
①BeanFactory
这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用
②ApplicationContext
BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用ApplicationContext,而不是底层的 BeanFactory
ApplicationContext的主要实现类:
类型名 | 简介 |
---|---|
ClassPathXmlApplicationContext | 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象 |
FileSystemXmlApplicationContext | 通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象 |
ConfigurableApplicationContext | ApplicationContext 的子接口,包含一些扩展方法 refresh() 和 close() ,让 ApplicationContext 具有启动、关闭和刷新上下文的能力 |
WebApplicationContext | 专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对象,并将对象引入存入 ServletContext 域中 |
基于xml管理bean
依赖放入父模块
创建新模块spring-ioc-xml
package com.qcby.spring;
public class User {
private String name;
private Integer age;
public void run(){
System.out.println("run...");
}
}
获取bean
①方式一:根据id获取
由于 id 属性指定了 bean 的唯一标识,所以根据 bean 标签的 id 属性可以精确获取到一个组件对象(入门案例)
bean.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">
<!--user对象创建-->
<bean id="user" class="com.qcby.spring.User"></bean>
</beans>
测试类:
package com.qcby.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取bean
User user = (User) context.getBean("user");
System.out.println("根据id获取bean:"+user);
}
}
②方式二:根据类型获取
package com.qcby.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取bean
// User user = (User) context.getBean("user");
// System.out.println("根据id获取bean:"+user);
//根据类型获取bean
User user = context.getBean(User.class);
System.out.println("根据类型获取bean"+user);
}
}
当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个
若配置多个,会抛出异常:org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type
③方式三:根据id和类型
package com.qcby.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取bean
// User user = (User) context.getBean("user");
// System.out.println("根据id获取bean:"+user);
//根据类型获取bean
// User user = context.getBean(User.class);
// System.out.println("根据类型获取bean"+user);
//根据id和类型获取bean
User user = context.getBean("user", User.class);
System.out.println("根据id和类型获取bean:"+user);
}
}
扩展:
如果组件类实现了接口,根据接口类型可以获取 bean 吗?
- 可以,前提是bean唯一
package com.qcby.spring;
public interface UserDao {
public void run();
}
package com.qcby.spring;
public class UserDaoImpl implements UserDao{
@Override
public void run() {
System.out.println("run...");
}
}
<!--一个接口获取类过程-->
<bean id="userDaoImpl" class="com.qcby.spring.bean.UserDaoImpl.UserDaoImpl"></bean>
package com.qcby.spring;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUserDao {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//根据类型获取接口对应bean
UserDao userDao = context.getBean(UserDao.class);
System.out.println(userDao);
userDao.run();
}
}
如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?
- 不行,因为bean不唯一
依赖注入
setter注入
第一步:创建类,生成属性set方法
第二步:在spring配置文件配置
package com.qcby.spring.di;
public class Book {
private String bname;
private String author;
//无参构造
public Book() {
}
//有参构造
public Book(String bname, String author) {
this.bname = bname;
this.author = author;
}
//生成get和set方法
public void setBname(String bname) {
this.bname = bname;
}
public void setAuthor(String author) {
this.author = author;
}
public String getBname() {
return bname;
}
public String getAuthor() {
return author;
}
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
", author='" + author + '\'' +
'}';
}
}
<?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:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<!--set方法注入-->
<!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
<!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
<!-- value属性:指定属性值 -->
<bean id="book" class="com.qcby.spring.di.Book">
<property name="bname" value="前端开发"></property>
<property name="author" value="张三"></property>
</bean>
</beans>
package com.qcby.spring;
import com.qcby.spring.di.Book;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBook {
@Test
public void testSetter(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean_di.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
构造器注入
第一步:创建类,定义属性,生成有参构造方法
第二步:在spring配置文件配置
<!--构造器注入-->
<bean id="bookCon" class="com.qcby.spring.di.Book">
<constructor-arg name="bname" value="java开发"></constructor-arg>
<constructor-arg name="author" value="李四"></constructor-arg>
</bean>
注意:
constructor-arg标签还有两个属性可以进一步描述构造器参数:
- index属性:指定参数所在位置的索引(从0开始)
- name属性:指定参数名
@Test
public void testCon(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean_di.xml");
Book book = context.getBean("bookCon", Book.class);
System.out.println(book);
}
特殊值处理
字面量赋值
什么是字面量?
int a = 10;
声明一个变量a,初始化为10,此时a不代表字母a,而是作为一个变量的名字。当引用a的时候,实际上拿到的值是10。
而如果a是带引号的:'a',那么它现在不是一个变量,它就是代表a这个字母本身,这就是字面量。所以字面量没有引申含义,就是我们看到的这个数据本身
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>
null值
<property name="name">
<null />
</property>
注意:以下写法为name所赋的值是字符串null
<property name="name" value="null"></property>
xml实体
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a < b"/>
CDATA节
<property name="expression">
<!-- 解决方案二:使用CDATA节 -->
<!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
<!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
<!-- 所以CDATA节中写什么符号都随意 -->
<value><![CDATA[a < b]]></value>
</property>
特殊类型属性注入
对象类型属性注入
package com.qcby.spring.ditest;
//部门类
public class Dept {
private String dname;
public void info(){
System.out.println("部门名称:"+dname);
}
public void setDname(String dname) {
this.dname = dname;
}
public String getDname() {
return dname;
}
}
package com.qcby.spring.ditest;
//员工类
public class Emp {
//对象类型属性:员工属于某个部门
private Dept dept;
private String ename;
private Integer age;
public void work(){
System.out.println(ename+"emp work..."+age);
dept.info();
}
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;
}
}
方式一:引用外部bean
使用ref属性
<!--方式一:引入外部bean
1.创建两个类对象:dept emp
2.在emp的bean标签里,使用property引入dept的bean
-->
<bean id="dept" class="com.qcby.spring.ditest.Dept">
<property name="dname" value="安保部"></property>
</bean>
<bean id="emp" class="com.qcby.spring.ditest.Emp">
<!--普通属性注入-->
<property name="ename" value="lucy"></property>
<property name="age" value="50"></property>
<!--对象属性注入
ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值-->
<property name="dept" ref="dept"></property>
</bean>
方式二:内部bean
<!--方式二:内部bean-->
<!-- 在一个bean中再声明一个bean就是内部bean -->
<!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
<bean id="emp2" class="com.qcby.spring.ditest.Emp">
<!--普通属性注入-->
<property name="ename" value="mary"></property>
<property name="age" value="20"></property>
<!--对象属性注入-->
<property name="dept">
<bean id="dept2" class="com.qcby.spring.ditest.Dept">
<property name="dname" value="财务部"></property>
</bean>
</property>
</bean>
方式三:级联属性赋值
<!--方式三:级联赋值-->
<bean id="dept3" class="com.qcby.spring.ditest.Dept">
<property name="dname" value="研发部"></property>
</bean>
<bean id="emp3" class="com.qcby.spring.ditest.Emp">
<!--普通属性注入-->
<property name="ename" value="tom"></property>
<property name="age" value="30"></property>
<!--对象属性注入-->
<property name="dept" ref="dept3"></property>
<property name="dept.dname" value="测试部"></property>
</bean>
数组类型属性注入
员工类:
//爱好
private String[] loves;
public String[] getLoves() {
return loves;
}
public void setLoves(String[] loves) {
this.loves = loves;
}
public void work(){
System.out.println(ename+"emp work..."+age);
dept.info();
System.out.println(Arrays.toString(loves));
}
<!--数组类型属性-->
<property name="loves">
<array>
<value>吃饭</value>
<value>睡觉</value>
<value>看电影</value>
</array>
</property>
完整的配置文件:
<?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="dept" class="com.qcby.spring.ditest.Dept">
<property name="dname" value="技术部"></property>
</bean>
<bean id="emp" class="com.qcby.spring.ditest.Emp">
<!--普通属性-->
<property name="ename" value="lucy"></property>
<property name="age" value="20"></property>
<!--对象类型属性-->
<property name="dept" ref="dept"></property>
<!--数组类型属性-->
<property name="loves">
<array>
<value>吃饭</value>
<value>睡觉</value>
<value>看电影</value>
</array>
</property>
</bean>
</beans>
集合类型属性注入
list、set集合类型
Dept类:
private List<Emp> empList;
public void info(){
System.out.println("部门名称:"+dname);
for (Emp emp : empList) {
System.out.println(emp.getEname());
}
}
public List<Emp> getEmpList() {
return empList;
}
public void setEmpList(List<Emp> empList) {
this.empList = empList;
}
}
<?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="empone" class="com.qcby.spring.ditest.Emp">
<property name="ename" value="lucy"></property>
<property name="age" value="20"></property>
</bean>
<bean id="emptwo" class="com.qcby.spring.ditest.Emp">
<property name="ename" value="mary"></property>
<property name="age" value="30"></property>
</bean>
<bean id="dept" class="com.qcby.spring.ditest.Dept">
<property name="dname" value="技术部"></property>
<property name="empList">
<list>
<ref bean="empone"></ref>
<ref bean="emptwo"></ref>
</list>
</property>
</bean>
</beans>
若为Set集合类型属性赋值,只需要将其中的list标签改为set标签即可
map集合类型
Student和Teacher类:
package com.qcby.spring.dimap;
import java.util.Map;
public class Student {
private Map<String,Teacher> teacherMap;
private String sid;
private String sname;
public void run(){
System.out.println("学生编号:"+sid+"学生名称:"+sname);
System.out.println(teacherMap);
}
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
package com.qcby.spring.dimap;
public class Teacher {
private String teacherId;
private String teacherName;
public String getTeacherId() {
return teacherId;
}
public void setTeacherId(String teacherId) {
this.teacherId = teacherId;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
@Override
public String toString() {
return "Teacher{" +
"teacherId='" + teacherId + '\'' +
", teacherName='" + teacherName + '\'' +
'}';
}
}
<?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">
<!--
1.创建两个对象
2.注入普通类型属性
3.在学生bean注入map集合类型属性
-->
<bean id="teacherone" class="com.qcby.spring.dimap.Teacher">
<!--注入普通类型属性-->
<property name="teacherId" value="100"></property>
<property name="teacherName" value="讲师1"></property>
</bean>
<bean id="teachertwo" class="com.qcby.spring.dimap.Teacher">
<!--注入普通类型属性-->
<property name="teacherId" value="200"></property>
<property name="teacherName" value="讲师2"></property>
</bean>
<bean id="student" class="com.qcby.spring.dimap.Student">
<!--注入普通类型属性-->
<property name="sid" value="2000"></property>
<property name="sname" value="李四"></property>
<!--在学生bean注入map集合类型属性-->
<property name="teacherMap">
<map>
<entry>
<!--key-->
<key>
<value>1</value>
</key>
<!--value为对象-->
<ref bean="teacherone"></ref>
</entry>
<entry>
<!--key-->
<key>
<value>2</value>
</key>
<!--value为对象-->
<ref bean="teachertwo"></ref>
</entry>
</map>
</property>
</bean>
</beans>
引用集合类型
Lesson类:
package com.qcby.spring.dimap;
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 + '\'' +
'}';
}
}
package com.qcby.spring.dimap;
import java.util.List;
import java.util.Map;
public class Student {
private List<Lesson> lessonList;
private Map<String,Teacher> teacherMap;
private String sid;
private String sname;
public void run(){
System.out.println("学生编号:"+sid+"学生名称:"+sname);
System.out.println(teacherMap);
System.out.println(lessonList);
}
public List<Lesson> getLessonList() {
return lessonList;
}
public void setLessonList(List<Lesson> lessonList) {
this.lessonList = lessonList;
}
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
使用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/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.qcby.spring.dimap.Lesson">
<property name="lessonName" value="java"></property>
</bean>
<bean id="lessontwo" class="com.qcby.spring.dimap.Lesson">
<property name="lessonName" value="python"></property>
</bean>
<bean id="teacherone" class="com.qcby.spring.dimap.Teacher">
<property name="teacherId" value="100"></property>
<property name="teacherName" value="讲师1"></property>
</bean>
<bean id="teachertwo" class="com.qcby.spring.dimap.Teacher">
<property name="teacherId" value="200"></property>
<property name="teacherName" value="讲师2"></property>
</bean>
<bean id="student" class="com.qcby.spring.dimap.Student">
<property name="sid" value="001"></property>
<property name="sname" value="lucy"></property>
<!--注入list、map类型属性-->
<property name="lessonList" 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>1001</value>
</key>
<ref bean="teacherone"></ref>
</entry>
<entry>
<key>
<value>1002</value>
</key>
<ref bean="teachertwo"></ref>
</entry>
</util:map>
</beans>
p命名空间
引入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/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">
引入p命名空间后,可以通过以下方式为bean的各个属性赋值:
<bean id="studentSix" class="com.qcby.spring6.bean.Student"
p:id="1006" p:name="小明" p:clazz-ref="clazzOne" p:teacherMap-ref="teacherMap"></bean>
引入外部属性文件
1.加入依赖
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
</dependency>
2.创建外部属性文件
jdbc.user=root
jdbc.password=123456
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
3.配置bean
<?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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!--完成数据库信息注入-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
4.测试
package com.qcby.spring;
import com.alibaba.druid.pool.DruidDataSource;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestJdbc {
@Test
public void demo(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean_jdbc.xml");
DruidDataSource dataSource = context.getBean(DruidDataSource.class);
System.out.println(dataSource.getUrl());
}
}
bean的作用域
在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围,各取值含义参加下表:
取值 | 含义 | 创建对象的时机 |
---|---|---|
singleton(默认) | 在IOC容器中,这个bean的对象始终为单实例 | IOC容器初始化时 |
prototype | 这个bean在IOC容器中有多个实例 | 获取bean时 |
如果是在WebApplicationContext环境下还会有另外几个作用域(但不常用):
取值 | 含义 |
---|---|
request | 在一个请求范围内有效 |
session | 在一个会话范围内有效 |
演示:
1.创建Orders类
2.测试单实例:地址相同
<?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">
<!--通过scope属性配置单实例、多实例-->
<bean id="orders" class="com.qcby.spring.scope.Orders"
scope="singleton"></bean>
</beans>
package com.qcby.spring;
import com.qcby.spring.scope.Orders;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestOrders {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean_scope.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println(orders);
Orders orders1 = context.getBean("orders", Orders.class);
System.out.println(orders1);
}
}
3.测试多实例:地址不同
<?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">
<!--通过scope属性配置单实例、多实例-->
<bean id="orders" class="com.qcby.spring.scope.Orders"
scope="prototype"></bean>
</beans>
bean的生命周期
1.bean对象创建(调用无参构造器)
2.给bean对象设置相关属性
3.bean的后置处理器(初始化之前)
4.bean对象初始化(需在配置bean时指定初始化方法)
5.bean的后置处理器(初始化之后)
6.bean对象就绪可以使用
7.bean对象销毁(需在配置bean时指定销毁方法)
8.IoC容器关闭
演示:
package com.qcby.spring.life;
public class User {
private String name;
//无参构造
public User() {
System.out.println("1.bean对象创建,调用无参构造");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("2.给bean设置属性值");
this.name = name;
}
//初始化的方法
public void initMethod(){
System.out.println("4.bean对象初始化,调用指定的初始化的方法");
}
//销毁的方法
public void destroyMethod(){
System.out.println("7.bean对象销毁,调用指定的销毁的方法");
}
}
bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行
package com.qcby.spring.life;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.Nullable;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3.bean后置处理器,初始化之前执行");
System.out.println(beanName+"::"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("5.bean后置处理器,初始化之后执行");
System.out.println(beanName+"::"+bean);
return bean;
}
}
<?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.qcby.spring.life.User"
scope="singleton" init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="lucy"></property>
</bean>
<!-- bean的后置处理器要放入IOC容器才能生效 -->
<bean id="myBeanProcessor" class="com.qcby.spring.life.MyBeanPost"/>
</beans>
package com.qcby.spring;
import com.qcby.spring.life.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean_life.xml");
User user = context.getBean("user", User.class);
System.out.println("6.bean对象创建完成,可以使用");
System.out.println(user);
context.close();
}
}
FactoryBean
FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们,将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的
演示:
package com.qcby.spring.factorybean;
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 User.class;
}
}
<?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.qcby.spring.factorybean.MyFactoryBean"></bean>
</beans>
package com.qcby.spring;
import com.qcby.spring.factorybean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser1 {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean_factorybean.xml");
User user = (User) context.getBean("user");
System.out.println(user);
}
}
基于xml自动装配
自动装配:根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值
使用bean标签的autowire属性设置自动装配效果
1.自动装配方式:byType(找的是class)
byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值
若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null
若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException
2.自动装配方式:byName(找的是id)
byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值
byType演示:
package com.qcby.spring.auto.controller;
import com.qcby.spring.auto.service.UserService;
import com.qcby.spring.auto.service.UserServiceImpl;
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void addUser(){
System.out.println("controller中的方法执行了");
//调用service的方法
userService.addUserService();
}
}
package com.qcby.spring.auto.service;
public interface UserService {
public void addUserService();
}
package com.qcby.spring.auto.service;
import com.qcby.spring.auto.dao.UserDao;
import com.qcby.spring.auto.dao.UserDaoImpl;
public class UserServiceImpl implements UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void addUserService() {
System.out.println("userService中的方法执行了");
//调用dao中的方法
userDao.addUserDao();
}
}
package com.qcby.spring.auto.dao;
public interface UserDao {
public void addUserDao();
}
package com.qcby.spring.auto.dao;
public class UserDaoImpl implements UserDao{
@Override
public void addUserDao() {
System.out.println("userDao中的方法执行了");
}
}
<?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="userController" class="com.qcby.spring.auto.controller.UserController"
autowire="byType">
</bean>
<bean id="userService" class="com.qcby.spring.auto.service.UserServiceImpl"
autowire="byType">
</bean>
<bean id="userDao" class="com.qcby.spring.auto.dao.UserDaoImpl"></bean>
</beans>
package com.qcby.spring;
import com.qcby.spring.auto.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser1 {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean_auto.xml");
UserController controller = context.getBean("userController", UserController.class);
controller.addUser();
}
}