07ssm_Spring中Bean的管理

回顾:

控制反转和依赖注入都是通过Bean实现的

Bean就是注册到Spring容器中的Java类,任何一个Java类都可以是一个Bean Bean由Spring进行管理

一 、Spring IoC容器

Spring提供相应的API来管理Bean,常用的有BeanFactory和ApplicationContext两个接口。

BeanFactory接口

是Spring容器最基本的接口

实现机制采用的是Java经典的工厂模式接口常用方法如下表

方法名称<br>描述<br>
getBean(String name)<br>根据参数名称获取Bean<br>
getBean(String name,Class type)<br>根据参数名称、参数类型获取Bean<br>
T getBean(Class requiredType)<br>根据参数类型获取Bean<br>
Object getBean(String name,Object... args)<br>根据参数名称获取Bean<br>
isTypeMatch(String name,Resolvable Typetype)<br>判断是否有与参数名称、参数类型匹配的Bean<br>
Class <?>getType(String name)<br>根据参数名称获取类型<br>
String[] getAliases(String name)<br>根据实例的名字获取实例的别名数组<br>
boolean containsBean(String name)<br>根据Bean的名称判断Spring容器是否含有指定的Bean<br>

XmlBeanFactory实现了BeanFactory接口,可以通过读取xml文件中的配置生成实例,用法示例如下。

BeanFactory beanFactory=new XmlBeanFactory(new FileSystemResource(”D:/bean.xml”));

ApplicationContext接口(重点)

ApplicationContext接口丰富了BeanFactory接口的内容

ApplicationContext接口可以为单例的Bean实行预初始化,并根据<property>元素执行setter方法。单例的Bean可以直接使用,提升了程序获取Bean实例的性能

接口实现类

类名称<br>描述<br>
<br>ClassPathXmlApplicationContext<br>从类路径加载配置文件,实例化ApplicationContext接口<br>
<br>FileSystemXmlApplicationContext<br>从文件系统加载配置文件,实例化ApplicationContext接口<br>
AnnotationConfigApplicationContext<br>从注解中加载配置文件,实例化ApplicationContext接口<br>
<br>WebApplicationContext<br>在Web应用中使用,从相对于Web根目录的路径中加载配置文件,实例化ApplicationContext接口<br>
<br>ConfigurableWebApplicationContext<br>扩展了WebApplicationContext类,它可以通过读取XML 配置文件的方式实例化WebApplicationContext类<br>

二 、Bean的配置

Spring容器支持XML和properties两种格式的配置文件

实际开发常用XML进行配置

XML配置的根元素是<beans>,包含是<bean>子元素

每个<bean>元素定义一个Bean,将Bean注册到Spring容器

<bean>元素常用属性

属性<br>描述<br>
<br>id<br>id属性是<bean>元素的唯一标识符,Spring容器对Bean的配置和管理通过id属性完成,装 配Bean时也需要根据id值获取对象。<br>
name<br>name属性可以为Bean指定多个名称,每个名称之间用逗号或分号隔开。<br>
class<br>class属性可以指定Bean的具体实现类,其属性值为对象所属类的全路径。<br>
<br>scope<br>scope属性用于设定Bean实例的作用范围,其属性值有:singleton(单例)、prototype<br>(原型)、request、session和global session。<br>

<bean>元素的子元素

元素<br>描述<br>
<constructor- arg><br>使用<constructor-arg>元素可以为Bean的属性指定值。<br>
<br><property><br><property>元素的作用是调用Bean实例中的setter方法完成属性赋值,从而完成 依赖注入。<br>
<br>ref<br>ref是<property>、<constructor-arg>等元素的属性,可用于指定Bean工厂中某个Bean实例的引用;也可用于指定Bean工厂中某个Bean实例的引用。<br>
<br>value<br>value是<property>、<constructor-arg>等元素的属性,用于直接指定一个常量值;也可以用于直接指定一个常量值。<br>
<br><list><br><list>元素是<property>等元素的子元素,用于指定Bean的属性类型为List或数组。<br>
<set><br><set>元素是<property>等元素的子元素,用于指定Bean的属性类型为set。<br>
<map><br><map>元素是<property>等元素的子元素,用于指定Bean的属性类型为Map。<br>
<br><entry><br><entry>元素是<map>元素的子元素,用于设定一个键值对。<entry>元素的key<br>属性指定字符串类型的键。<br>

普通的Bean通常只需定义id(或者name)和class两个属性

【示例】阅读下述配置文件,理解Bean的配置属性。

<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">

<!--使用id属性定义bean1,对应的实现类为com.bean.Bean1-->

<bean id="bean1" class="com.bean.Bean1">

</bean>

<!--使用name属性定义bean2,对应的实现类为com.bean.Bean2-->

<bean name="bean2" class="com.bean.Bean2"/>

</beans>

三 、Bean的实例化

实验环境准备

第一步:在ssm_spring项目下建spring-chap07-bean模块,目录结构如下:

 

第二步:为项目的模块添加依赖,依赖上一单元配置好的lib库

 

构造方法实例化

指Spring容器通过Bean对应类的默认无参构造方法来实例化Bean

【示例1】阅读代码,理解构造方法实例化bean的一般步骤。

  1. 创建类Bean1**(放com.bean包中)**

package com.bean;

public class Bean1 { public Bean1(){

System.out.println("正在实例化Bean1...");

}

}

  1. 创建核心配置文件spring-config.xml**(放resources文件夹下)**,并做如下配置

<?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="Index of /schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--配置Bean1类的bean-->

<bean id="bean1" class="com.bean.Bean1"/>

</beans>

  1. 编写测试类

import com.bean.Bean1;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBean1 {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("spring- config.xml");

Bean1 bean = (Bean1) context.getBean("bean1"); System.out.println(bean);

}

}

运行结果如下图。

 

静态工厂实例化

要求开发者定义一个静态工厂类(指用静态方法创建实例的工厂) 该静态工厂类中定义返回某个Bean实例的静态方法

配置文件Bean的class属性指向静态工厂类,且factory-method属性为创建Bean实例的静态方法

【示例2】阅读代码,理解静态工厂实例化bean的一般步骤。

  1. 创建类Bean2**(放com.bean包中)**

package com.bean;

public class Bean1 { public Bean1(){

System.out.println("正在实例化Bean2...");

}

}

  1. 创建静态工厂类MyBean2Factory**(放com.bean包中)**

package com.bean;

public class Bean2Factory {

//静态方法创建Bean2的实例

public static Bean2 createBean(){ return new Bean2();

}

}

  1. 创建核心配置文件spring-config.xml**(放resources文件夹下)**,并做如下配置。该文件如果已存在 直接加入新的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="Index of /schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--静态工厂方法配置Bean2。class指向静态工厂,factory-method指向创建Bean2的静态方法--

<bean id="bean2" class="com.bean.Bean2Factory" factory-method="createBean"/>

</beans>

(3)编写测试类

自己写,与前述类似!

  1. 实例工厂实例化

要求用户定义一个工厂类

该工厂类中定义一个能返回某个Bean实例的非静态方法配置文件中先要配置该工厂类的Bean

之后配置需要实例化的Bean:将其factory-bean属性指向实例工厂Bean,factory-method属性指向该工厂中创建实例的方法

【示例3】阅读代码,理解静态工厂实例化bean的一般步骤。

  1. 创建类Bean3**(放com.bean包中)**

package com.bean;

public class Bean3 { public Bean3(){

System.out.println("正在实例化Bean3...");

}

}

  1. 创建静态工厂类MyBean3Factory**(放com.bean包中)**

package com.bean;

public class Bean3Factory {

//静态方法创建Bean3的实例public Bean3 createBean(){

return new Bean3();

}

}

  1. 创建核心配置文件spring-config.xml**(放resources文件夹下)**,并做如下配置。该文件如果已存在 直接加入新的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="Index of /schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--实例化工厂配置Bean3-->

<!--第一步,配置工厂的Bean-->

<bean id="factory" class="com.bean.Bean3Factory"/>

<!--第二步,配置Bean3。factory-bean指向工厂的bean,factory-method指向创建Bean3的方 法-->

<bean factory-bean="factory" factory-method="createBean"/>

</beans>

(3)编写测试类

自己写,与前述类似!

** ****、Bean的作用域 **

Spring容器创建的Bean有使用范围,又称作用域作用域通过bean元素的scope属性设置

共5种使用范围,默认作用域是singleton,具体如下表

作用域名城<br>描述<br>
<br>singleton<br>单例模式。在单例模式下,Spring 容器中只会存在一个共享的Bean实例,所有对Bean的请求,只要请求的id(或name)与Bean的定义相匹配,会返回Bean的同一 个实例。<br>
prototype<br>原型模式,每次从容器中请求Bean时,都会产生一个新的实例。<br>
<br>request<br>每一个HTTP请求都会有自己的Bean实例,该作用域只能在基于Web的Spring ApplicationContext中使用。<br>
<br>session<br>每一个HTTPsession请求都会有自己的Bean实例,该作用域只能在基于Web的<br>Spring ApplicationContext中使用。<br>
global session<br>限定一个Bean的作用域为Web应用(HTTPsession)的生命周期,只有在Web应用中使用Spring时,该作用域才有效。<br>

singleton作用域示例

该作用域的实例Bean,对任何Bean请求均创建同一个对象

【示例4】阅读代码,理解singleton的实验结果。

首先,将示例1的bean配置加上singleton作用域**(不配置scope,系统会默认singleton。此步也可以不做!)**

<bean id="bean1" class="com.bean.Bean1" scope="singleton"/>

之后,写测试案例

import com.bean.Bean1; import com.bean.Bean2;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestScope {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("spring- config.xml");

Bean1 bean1 = (Bean1) context.getBean("bean1"); Bean1 bean2 = (Bean1) context.getBean("bean1"); System.out.println(bean1== bean2);

}

}

运行结果如下图。

 

prototype作用域

该作用域的实例Bean,对任何Bean请求均创建新的对象

【示例5】阅读代码,理解singleton的实验结果。 首先,将示例1的bean配置加上prototype作用域

<bean id="bean1" class="com.bean.Bean1" scope="prototype"/>

之后,运行示例4的测试案例运行结果如下图。

 

五 、Bean的装配方式

Bean的装配就是Bean的依赖注入有3种方式:基于XML的装配、基于注解的装配、自动装配。

基于XML的装配方式

指通过读取XML文件中的配置信息完成依赖注入。有两种方式:基于setter方法注入和基于构造方法注入。

基于setter方法注入(重点掌握)

前提条件

Bean类必须提供一个默认无参构造方法

Bean类必须为需要注入的属性提供对应的setter方法

配置方法:在<bean>元素内加子元素是<property>,该元素常用属性name,value,ref。

【示例6】理解setter方法注入的XML配置。首先,创建类Teacher**(放com.bean包)**

package com.bean;

public class Teacher { public String name; public String course;

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

}

public void setCourse(String course) { this.course = course;

}

public void print(){

System.out.println(name+"老师,教授课程:"+course);

}

}

之后,配置spring容器

<!--配置Teacher的Bean,并通过setter方法注入属性-->

<bean id="teacher_setter" class="com.bean.Teacher">

<property name="name" value="张小火"/>

<property name="course" value="java,h5+css"/>

</bean>

最后,写测试类。(略)

构造方法注入

前提条件:Bean类必须提供配置时需要的构造方法

配置方法:在<bean>元素内加子元素是<property>,该元素常用属性name,value,ref。

【示例7】理解构造方法注入的XML配置。

首先,为示例6中Teacher类添中下述两个构造方法

//必须显示定义无参构造方法,否则示例5会出错public Teacher() {

}

//此构造方法对应配置里构造方法注入

public Teacher(String name, String course) { this.name = name;

this.course = course;

}

之后,配置spring容器

<!--配置Teacher的Bean,并通过setter方法注入属性-->

<bean id="teacher_con" class="com.bean.Teacher">

<constructor-arg name="name" value="张小天"/>

<constructor-arg name="course" value="中国文学,英语"/>

</bean>

最后,写测试类。(略)

基于注解的装配方式(重点掌握)

实际工作中Bean数量较多,使用XML装配很不方便 注解装配非常方便,便于后期维护和升级

装配常用注解

注解<br>描述<br>
@Component<br>指定一个普通的Bean,可以作用在任何层次。<br>
<br>@Controller<br>指定一个控制器组件Bean,用于将控制层的类标识为Spring中的Bean,功能 上等同于@Component。<br>
<br>@Service<br>指定一个业务逻辑组件Bean,用于将业务逻辑层的类标识为Spring中的<br>Bean,功能上等同于@Component。<br>
<br>@Repository<br>指定一个数据访问组件Bean,用于将数据访问层的类标识为Spring 中的<br>Bean,功能上等同于@Component。<br>
@Scope<br>指定Bean实例的作用域。<br>
@Value<br>指定Bean实例的注入值。<br>
@Autowired<br>指定要自动装配的对象。<br>
@Resource<br>指定要注入的对象。 示例: @Resource(name="bean的名称")<br>
@Qualifier<br>指定要自动装配的对象名称,通常与@Autowired联合使用。<br>
@PostConstruct<br>指定Bean实例完成初始化后调用的方法。<br>
@PreDestroy<br>指定Bean实例销毁前调用的方法。<br>

**建议:**虽然 @Component 可以替代@Controller 、@Service 、@Repository 注解,但实际开发时为了被标注的类本身用途更清晰,定义控制主组用@Controller注解,定义业务逻辑组件用@Service 注解,定义数据访问组件用@Repository 注解

注解装配实现方法

第一步,在类定义前加上相关注解第二步,导入依赖包spring-aop.jar

 

第三步,spring的配置文件中

引入Context约束

,并

启动Bean的自动扫描功能

【示例8】阅读代码,理解注解装配的基本步骤。

首先,创建POJO类User,使用注解装配**(放com.bean.pojo包)**

package com.bean.pojo;

import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component;

@Component("user") //括号里是Bean对象名@Scope("singleton")

public class User { @Value("1")

private int id; @Value(" 张 小 小 ") private String name;

@Value("123")

private String password;

public int getId() { return id;

}

public void setId(int id) { this.id = id;

}

public String getName() { return name;

}

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

}

public String getPassword() { return password;

}

public void setPassword(String password) { this.password = password;

}

@Override

public String toString() { return "User{" +

"id=" + id +

", name='" + name + ''' +

", password='" + password + ''' + '}';

}

}

之后,设置spring配置文件spring-config.xml**(放resources文件夹)**,引入context约束,启动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="Index of /schema/context" xsi:schemaLocation="Index of /schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd Index of /schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<!--启动Bean的自动扫描功能-->

<context:component-scan base-package="com.bean"/>

</beans>

最后,写测试代码

import com.bean.pojo.User;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("spring- config.xml");

User user=context.getBean(User.class); System.out.println(user);

}

}

运行结果如下图:

 

【示例9】上示例8基础上,模拟基于MVC结构,User数据保存业务的实现。

  1. 定义Dao层:创建接口UserDao**(放com.bean.dao包)**

package com.bean.dao;

public interface UserDao {

//保存数据

public void save();

}

  1. 实现Dao层:创建类UserDaoImpl,实现接口UserDao**(放com.bean.dao包)**

package com.bean.dao;

import com.bean.pojo.User;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.stereotype.Repository;

@Repository("userDao")

public class UserDaoImpl implements UserDao{ @Override

public void save() {

ApplicationContext context = new ClassPathXmlApplicationContext("spring- config.xml");

User user=context.getBean(User.class); System.out.println(user);

System.out.println("执行了UserDaoImpl.save()");

}

}

  1. 定义Service层:创建接口UserService**(放com.bean.server包)**

package com.bean.service;

public interface UserService { public void save();

}

  1. 实现Service层:创建类UserServiceImpl**(放com.bean.server包)**

package com.bean.service;

import com.bean.dao.UserDao;

import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("userService")

public class UserServiceImpl implements UserService { @Resource(name="userDao")

private UserDao userDao; @Override

public void save() { userDao.save();

System.out.println("执行了UserServiceImpl.save()");

}

}

  1. 定义Controller层:创建类UserController做为控制层**(放com.bean.controller包)**

package com.bean.controller;

import com.bean.service.UserService;

import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller("userController") public class UserController {

@Resource(name="userService") private UserService userService; public void save(){

userService.save();

System.out.println("执行了UserController.save()");

}

}

  1. 设置spring配置文件,引入context,开启Bean的自动扫描**(同前!) **(7)定义测试类

import com.bean.controller.UserController; import com.bean.pojo.User;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("spring- config.xml");

UserController user=(UserController)context.getBean("userController"); user.save();

}

}

**注意:**接口不用写注解!!

自动装配

如果不用注解注入,也可以使用Spring的<bean>元素的autowire属性完成自动装配

autowire属性取值如下

属性值<br>描述<br>
default(默认值)<br>由<bean>的上级元素<beans>的default-autowire属性值确定。<br>
byName<br>根据<bean>元素id属性的值自动装配。<br>
<br>byType<br>根据<bean>元素的数据类型(Type)自动装配,如果一个Bean的数据类型,兼 容另一个Bean中的数据类型,则自动装配。<br>
constructor<br>根据构造函数参数的数据类型,进行byType模式的自动装配。<br>
no<br>默认值,不使用自动装配,Bean依赖必须通过<ref>元素或ref属性定义。<br>

【示例10】阅读代码,理解将第6单元“依赖注入的应用”案例中注入改为自动装配的spring配置方法。

<!--配置UserDao的bean-->

<bean id="userDao" class="com.introduce.dao.UserDaoImpl"/>

<!--配置UserService的bean,自动装配userDaoImpl属性-->

<bean id="userService" class="com.introduce.com.introduce.service.UserServiceImpl" autowire="byType">

六 、Bean的生命周期

  1. Bean在不同作用域内的生命周期

Bean的生命周期是指Bean实例被创建、初始化和销毁的过程

singleton作用域的Bean,由Spring容器管理其生命周期,控制着Bean的创建、初始化和销毁prototype作用域的Bean,Spring容器只负责创建Bean实例,不会管理其生命周期

  1. Bean生命周期的两个时间节点

Bean实例初始化后Bean实例销毁前

  1. 监控时间节点的两种方式XML配置文件方式

注解方式**(重点掌握)**

@PostConstruct:写在类的初始化方法上方。实例初始化后,会调用该方法。@PreDestory:写在类的注销方法上方。实例销毁前,会调用该方法。

【示例】阅读代码,理解@PostConstruct和@PreDestory的使用。

  1. 创建类Dog**(放com.bean包)**

package com.bean;

import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct; import javax.annotation.PreDestroy;

@Component

public class Dog {

@Value("牧羊犬")

private String name; @Value("2")

private int age;

public Dog() {

System.out.println("创建Dog实例...");

}

public String getName() { return name;

}

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

}

public int getAge() { return age;

}

public void setAge(int age) { this.age = age;

}

@Override

public String toString() {

return name+",今年"+age+"岁...";

}

@PostConstruct //该注解下的方法会在实例初始化后执行public void init(){

System.out.println("Dog实例初始化成功...");

}

@PreDestroy //该注解下的方法会在实例销毁前执行public void destroy(){

System.out.println("Dog实例即将销毁...");

}

}

  1. 设置spring配置文件spring-config.xml**(放resources文件夹)**

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

<!--启动Bean的自动扫描功能-->

<context:component-scan base-package="com.bean"/>

</beans>

编写测试类(AbstractApplicationContext类的registerShutdownHook()方法销毁Spring中所有

Bean)

import com.bean.Dog;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestDog {

public static void main(String[] args) {

ApplicationContext context = new ClassPathXmlApplicationContext("spring- config.xml");

Dog dog = context.getBean(Dog.class);

System.out.println("====================="); System.out.println(dog); System.out.println("=====================");

AbstractApplicationContext ac=(AbstractApplicationContext) context; ac.registerShutdownHook(); //销毁所有bean

}

}

运行结果如下图:

 

七 、课后练习

**目标:**考察知识点为BeanFactory接口、ApplicationContext接口、Bean的配置、构造方法实例化、静态工厂实例化、实例工厂实例化、singleton作用域、prototype作用域、基于XML的装配、基于注解的 装配、自动装配、Bean的生命周期)

**形式:**单独完成

**题目:**代码演示如何使用注解方式装配Bean,具体要求如下。

  1. 创建项目名称为spring-chap07-bean;
  2. 创建配置文件名称为applicationContext.xml;
  3. 创建包名为com.bean.XXX,controller层、service层、dao层要分别创建3个包; (4)具体业务自定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TechLens

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值