高效率学习Spring框架(三)-- bean标签详解【重点】

145 阅读8分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

高效率学习Spring框架(三) ---- bean标签详解【重点】

1、bean标签作用

bean作用:  
    用于配置对象让spring 来创建的。 
    【细节】
    默认情况下调用类的无参构造函数。

2、bean标签基本属性

属性说明
idbean的唯一标识名称
class实现类的全限定名称
namebean的名称 * 多个别名使用 ”,” 分割 * bean与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="accountDao" name="accountDao2,accountDao3" class="com.lucky.spring.dao.impl.AccountDaoImpl"></bean>
​
    <bean id="accountService"  class="com.lucky.spring.service.impl.AccountServiceImpl"></bean></beans>

3、bean标签作用范围

属性说明
scope指定对象的作用范围。 * singleton 【默认】: 单例,所有的请求都用一个对象来处理 * prototype : 多例,每个请求用一个新的对象来处理 * request : WEB 项目中,将对象存入到 request 域中. * session : WEB 项目中,将对象存入到 session 域中. * global session : WEB 项目中,应用在集群环境.如果没有集群环境那么相当于session

global session图解

image-20191115160127054.png

【1】思考

单例、多例他们分别在什么场景中使用?他们有什么区别?
spring默认单例,不需要修改,不要随意定义成员变量。
多例:资源共用

【2】目标

1、掌握scope的单例、多例的配置
2、掌握单例和多例的区别

【3】bean作用域实例(6)

步骤:
    1、改造ClientController多次获得对象
    2、装配bean到spring的IOC容器中,修改bean标签中scope的作用域
    3、观察不同作用域下获得的对象内存地址是否一致
【3.1】创建项目

拷贝项目spring-spring-ioc-xml创建spring-bean-scope结构如下

01.png

改造ClientController

package com.lucky.spring.controller;
​
import com.lucky.spring.dao.AccountDao;
import com.lucky.spring.service.AccountService;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
​
import javax.sound.midi.Soundbank;
​
/**
 * @Description:测试
 */
public class ClientController {
    
​
    @Test
    public void saveAccount() {
​
        /**
         * Spring-IOC容器:ApplicationContext
         * 构建方式:通过ClassPathXmlApplicationContext加载配置文件
         * 使用bean:getBean
         */
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        AccountDao accountDaoA = (AccountDao) applicationContext.getBean("accountDao");
        AccountDao accountDaoB = (AccountDao) applicationContext.getBean("accountDao");
​
        System.out.println("accountDaoA的内存地址:"+accountDaoA.hashCode());
        System.out.println("accountDaoB的内存地址:"+accountDaoB.hashCode());
​
    }
​
}
​
​
【3.2】Bean【默认:singleton】

使用bean标签在bean.xml中装配accountDao的scope="singleton"

<?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="accountDao" class="com.lucky.spring.dao.impl.AccountDaoImpl" scope="singleton"></bean>
​
    <!--创建accountServic-->
    <bean id="accountServic" class="com.lucky.spring.service.impl.AccountServicImpl"></bean>
</beans>
【3.3】singleton运行结果

image-20200105151113645.png

【3.4】bean【多例:prototype】

使用bean标签在bean.xml中装配accountDao的scope="prototype"

<?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="accountDao" class="com.lucky.spring.dao.impl.AccountDaoImpl" scope="prototype"></bean>
​
    <!--创建accountServic-->
    <bean id="accountServic" class="com.lucky.spring.service.impl.AccountServicImpl"></bean>
</beans>
【3.5】prototype运行结果

image-20200105151235884.png

【4】bean作用域小结

1、单例和多里创建方式、内存地址
    【singleton单例】:所有请求只创建一个对象,内存地址相同
    【prototype多例】:每次请求都创建新的对象,内存地址不同
2、为什么使用单例?
    节省内存、CPU的开销,加快对象访问速度
3、为什么使用多例?
    如果你给controller中定义很多的属性,那么单例肯定会出现竞争访问,不要在controller层中定义成员变量(dao、service注入的bean)
    当web层的对象是有状态的时候 使用多例,防止并发情况下的互相干扰
4、单例、多例的场景
    单例===》spring中的Dao,Service,controller都是单例的
    多例====》struts2的Action是多实例

4、bean生命周期

sevlet的生命周期回顾

1.被创建:执行init方法,只执行一次
​
  --默认情况下,第一次被访问时,Servlet被创建,然后执行init方法;
​
  --可以配置执行Servlet的创建时机;
​
2.提供服务:执行service的doGet、doPost方法,执行多次
​
3.被销毁:当Servlet服务器正常关闭时,执行destroy方法,只执行一次

spring-IOC中不同作用域中bean的生命周期

作用范围生命周期
单例scope=“singleton”所有请求只创建一次对象出生:应用加载,创建容器,对象就被创建 活着:只要容器在,对象一直活着。 死亡:应用卸载,销毁容器,对象就被销毁
多例scope="prototype"每次请求都创建对象出生:应用加载,创建容器,对象使用创建 活着:只要容器在,对象一直活着。 死亡:对象长时间不用,被垃圾回收器回收

生命周期方法相关

名称说明
init-method指定类中的初始化方法名称
destroy-method指定类中销毁方法名称

【1】目标

1、掌握bean的生命周期配置方式
2、单例和多例下bean的生命周期的区别。

【2】bean生命周期实例(7)

步骤:
    1、创建LifecycBeanServic类
    2、装配LifecycBeanServic
    3、创建测试类
    4、观察默认单例下生命周期
    5、观察多例下生命周期
【2.1】创建项目

新建项目spring-bean-lifecycle

02.png

​
package com.lucky.spring.service;
​
/**
 * @Description:生命周期测试服务
 */
public class LifecycleService {
​
    public LifecycleService() {
        System.out.println("LifecycleService构造");
    }
​
    public void init(){
        System.out.println("LifecycleService初始化");
    }
​
    public void doJob(){
        System.out.println("LifecycleService工作中");
    }
​
    public void destroy(){
        System.out.println("LifecycleService销毁");
    }
}
​
【2.3】装配LifecycleBean

装配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="beanlifecycle"
          scope="prototype"
          class="com.lucky.spring.service.BeanLifecycle"
          init-method="init" destroy-method="destory"></bean>
</beans>
【2.4】创建ClientController
package com.lucky.spring.controller;
​
import com.lucky.spring.service.LifecycleService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
​
/**
 * @Description:客户端
 */
public class ClientContrller {
​
    /**
     * ApplicationContext:spring-IOC容器
     * ClassPathXmlApplicationContext:容器实现类,加载配置文件
     * applicationContext.getBean:获得容器中的bean对象
     */
    @Test
    public void createAccount(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
        System.out.println("applicationContext初始化完成");
        LifecycleService lifecycleService = applicationContext.getBean("lifecycleService", LifecycleService.class);
        lifecycleService.doJob();
        System.out.println("applicationContext容器关闭");
        ((ClassPathXmlApplicationContext) applicationContext).close();
​
    }
}
​
【2.5】单例模式下生命周期:
【2.6】多例模式下生命周期

将配置文件中的单例修改为多例

<?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="lifecycBeanServic" class="com.lucky.spring.service.LifecycBeanServic"
          scope="prototype"  init-method="init" destroy-method="destory"></bean>
</beans>

再次执行方法发现,LifecycleBean被延迟加载了,并且只执行了初始化方法-init,没有执行销毁方法destory.

【3】bean生命周期小结

单例对象:scope="singleton"
    一个应用只有一个对象的实例。它的作用范围就是整个应用。
    生命周期:
        对象出生:当应用加载,创建容器时,对象就被创建了。
        对象活着:只要容器在,对象一直活着。
        对象死亡:当应用卸载,销毁容器时,对象就被销毁了。
​
多例对象:scope="prototype"
    每次访问对象时,都会重新创建对象实例。
    生命周期:
        对象出生:当使用对象时,创建新的对象实例(getBean)。
        对象活着:只要对象在使用中,就一直活着。
        对象死亡:当对象长时间不用时,被垃圾回收器回收。
生命周期方法:
init-method:指定类中的初始化方法名称 
destroy-method:指定类中销毁方法名称

5、bean的实例化方式(8)

bean的实例化方式有以下3种:

  • bean缺省构造函数创建
  • 静态factory方法创建
  • 实例化factory方法创建

【1】目标

1、掌握bean实例化的三种方式
2、了解3中方式应用场景

【2】创建项目

新建项目spring-bean-instance结构如下

03.png

【3】缺省构造函数方式【重点】

【3.1】配置方式
<!--空的构造方法实例化-->
<bean id="account" class="com.lucky.spring.pojo.Account"></bean>
【3.2】注意事项
缺省构造函数实例化Bean的方式是Spring中默认的实例化方式;
被实例化的Bean中必须有无参构造;

【4】静态工厂方法方式

【4.1】配置方式
<!--静态工厂实例化-->
    <bean id="accountStatic" class="com.lucky.spring.factory.StaticFactory" factory-method="createAccount"></bean>
【4.2】静态工厂代码

步骤一:创建静态工厂

package com.lucky.spring.factory;
​
import com.lucky.spring.pojo.Account;
​
/**
 * @Description:静态工厂
 */
public class StaticFactory {
​
    public static Account createAccount(){
        System.out.println("静态工厂构建!");
        return  new Account();
    }
}
​

步骤二:配置静态工厂

通过静态工厂中的createAccount方法给我们创建bean

<!--静态工厂实例化-->
    <bean id="accountStatic" class="com.lucky.spring.factory.StaticFactory" factory-method="createAccount"></bean>

【5】实例工厂方法方式

【5.1】配置方式
<!--实例化工厂实例化-->
<bean id="instanceFactory" class="com.lucky.spring.factory.InstanceFactory"></bean>
<bean id="accountInstance" factory-bean="instanceFactory" factory-method="createAccount"></bean>
【5.2】实例工厂代码

步骤一:创建实例工厂

package com.lucky.spring.factory;
​
import com.lucky.spring.pojo.Account;
​
/**
 * @Description:实例化工厂
 */
public class InstanceFactory {
​
    public Account createAccount(){
        System.out.println("实例工厂构建!");
        return  new Account();
    }
    
    public User createUser(){
        System.out.println("实例工厂构建!");
        return  new User();
    }
}
​

【6】bean实例化小结

【缺省构造函数方式】
    说明:
        在默认情况下会根据默认缺省构造函数来创建类对象。如果bean中没有默认无参构造函数,将会创建失败。
    场景:
        当各个bean的业务逻辑相互比较独立时,或者与外界关联较少时可以使用
​
【静态工厂方法方式】
    说明:
        使用工厂中的静态方法创建对象,并装配到 spring的IOC 容器中。
        id 属性:指定 bean 的 id,用于从容器中获取   
        class 属性:指定静态工厂的全限定类名   
        factory-method 属性:指定生产对象的静态方法
    场景:
        统一管理各个bean的创建
        各个bean在创建之前需要相同的初始化处理,则可用静态factory方法进行统一的处理
​
【实例工厂方法方式】
    说明
        使用工厂中的实例方法创建对象,并装配到容器中。
            1、先把实例工厂做为一个bean装配到 spring容器中。   
            2、然后再引用工厂bean 来调用里面的非静态方法来获取bean并装配到spring的IOC容器中。   
            factory-bean 属性:用于指定实例工厂 bean 的 id。   
            factory-method 属性:用于指定实例工厂中创建对象的方法
    场景:
        1.实例factory方法也作为业务bean控制,可以用于集成其他框架的bean创建管理方法,
        2.能够使bean和factory的角色互换

6、bean标签配置小结

​
    1、bean标签的作用:把自己的类的对象的创建交给Spring管理
​
    2、基本配置:
        id:IOC工厂中bean实例的唯一标识
        class:实现类的全限定路径
        name:别名 
​
    3、bean的作用域:
        单例:默认,IOC工厂创建后,立即创建bean的实例对象(bean只会被实例化一次) 
        多例:scope="prototype"  每次从工厂中获取bean的时候,都会创建一个新的对象返回  
        
    4、bean的生命周期:
        单例:
            创建:IOC工厂创建后,立即创建bean的实例对象
            初始化:对象创建完成之后立刻调用
            工作...................
            销毁:IOC工厂卸载,单例bean销毁
        多例:
            出生:应用加载,创建容器,对象使用创建<br/>
            活着:只要容器在,对象一直活着。<br/>
            死亡:对象长时间不用,被垃圾回收器回收
​
    5、bean实例化的3种方式:获取对象
        bean缺省构造函数创建    
        静态factory方法创建   
        实例化factory方法创建
​