Bean的装配:

  Bean 的装配,即 Bean 对象的创建。容器根据代码要求创建 Bean 对象后再传递给代码的过程,称为 Bean 的装配。
  1. 创建Bean对象的方式:

    1. 通过 getBean()方式从容器获取指定的 Bean 对象。

    Bean的配置:<bean id="someService" class="com.tongji.ba01.SomeServiceImpl"/>

    2. 动态工厂Bean:有些时候,项目中需要通过工厂类来创建 Bean 对象,而不能像第一个方式中,直接由 Spring 容器来装配 Bean 对象。使用工厂模式创建 Bean 对象,就会使工厂类与要创建的 Bean 类耦合到一起。
           Spring 对于使用动态工厂来创建的 Bean,有专门的属性定义。factory-bean 指定相应的工厂 Bean,由 factory-method 指定创建所用方法。此时配置文件中至少会有两个 Bean 的定义:工厂类的 Bean,与工厂类所要创建的目标类 Bean。而测试类中不再需要获取工厂 Bean对象了,可以直接获取目标 Bean 对象。实现测试类与工厂类间的解耦。
    Bean的配置:

    <bean id="someFactory" class="com.tongji.ba02.SomeFactory"/>
        <!-- 表明someService对象是由someFactory这个工厂Bean的getSomeService()方法创建的 -->
        <bean id="someService" factory-bean="someFactory" factory-method="getSomeService"/>

    3. 静态工厂Bean:使用工厂模式中的静态工厂来创建实例 Bean 对象。  
    此时需要注意,静态工厂无需工厂实例,所以不再需要定义静态工厂<bean/>。 而对于工厂所要创建的 Bean,其不是由自己的类创建的,所以无需指定自己的类。但其是由工厂类创建的,所以需要指定所用工厂类。故 class 属性指定的是工厂类而非自己的
类。当然,还需要通过 factory-method 属性指定工厂方法。
    Bean的配置:
    <!-- 表明someService对象是由someFactory这个静态工厂的getSomeService()方法创建的 -->
           <bean id="someService" class="com.tongji.ba03.SomeFactory" factory-method="getSomeService"/>

  上述三种创建Bean对象的测试后代码均是:

 package com.tongji.ba03;

 import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test
public void test01() {
//创建容器
String resource = "com/tongji/ba03/applicationContext.xml";
@SuppressWarnings("resource")
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
//静态工厂bean将测试类与工厂类的耦合解决了
ISomeService service = (ISomeService) ac.getBean("someService");
service.doSome();
}
}

  后两种创建方式仍然存在Bean类与工厂类耦合的问题:

 package com.tongji.ba03;

 //问题:SomeServiceImpl类与工厂类耦合到了一起
public class SomeFactory {
public static ISomeService getSomeService() {
return new SomeServiceImpl();
}
}

  2. 容器中Bean的作用域:

    当通过 Spring 容器创建一个 Bean 实例时,不仅可以完成 Bean 的实例化,还可以通过scope 属性,为 Bean 指定特定的作用域。Spring 支持 5 种作用域。
    (1)singleton:单态模式。即在整个 Spring 容器中,使用 singleton 定义的 Bean 将是单例的,只有一个实例。默认为单态的。
    (2)prototype:原型模式。即每次使用 getBean 方法获取的同一个<bean />的实例都是一个新的实例。
    (3)request:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例。
    (4)session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例。
    (5)global session:每个全局的 HTTP session 对应一个 Bean 实例。典型情况下,仅在使用portlet 集群时有效,多个 Web 应用共享一个 session。一般应用中,global-session 与 session是等同的。

  注意:
    (1)对于 scope 的值 request、session 与 global session,只有在 Web 应用中使用 Spring 时,该作用域才有效。
    (2)对于 scope 为 singleton 的单例模式,该 Bean 是在容器被创建时即被装配好了。
    (3)对于 scope 为 prototype 的原型模式,Bean 实例是在代码中使用该 Bean 实例时才进行装配的。

   <bean id="someService" class="com.tongji.ba04.SomeServiceImpl" scope="prototype"/>
  3. Bean的生命周期:
    Bean 实例从创建到最后销毁,需要经过很多过程,执行很多生命周期方法。  
    Step1:调用无参构造器,创建实例对象。  
    Step2:调用参数的 setter,为属性注入值。 
    Step3:若 Bean 实现了 BeanNameAware 接口,则会执行接口方法 setBeanName(String beanId),使 Bean 类可以获取其在容器中的 id 名称。  
    Step4:若 Bean 实现了 BeanFactoryAware 接口,则执行接口方法 setBeanFactory(BeanFactory factory),使 Bean 类可以获取到 BeanFactory 对象。  
    Step5:若定义并注册了 Bean 后处理器 BeanPostProcessor,则执行接口方法postProcessBeforeInitialization()。  
    Step6:若 Bean 实现了 InitializingBean 接口,则执行接口方法 afterPropertiesSet()。该方法在 Bean 的所有属性的 set 方法执行完毕后执行,是 Bean 初始化结束的标志,即 Bean 实例化结束。  
    Step7:若设置了 init-method 方法,则执行。  
    Step8:若定义并注册了 Bean 后处理器 BeanPostProcessor,则执行接口方法 postProcessAfterInitialization()。  
    Step9:执行业务方法。  
    Step10:若 Bean 实现了 DisposableBean 接口,则执行接口方法 destroy()。
    Step11:若设置了 destroy-method 方法,则执行。
  

    补充:

    1. Step5和Step8中的Bean后处理器:

      Bean 后处理器是一种特殊的 Bean,容器中所有的 Bean 在初始化时,均会自动执行该类的两个方法。由于该 Bean 是由其它 Bean 自动调用执行,不是程序员手工调用,故此 Bean无须 id 属性。 

 <?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="someService1" class="com.tongji.ba07.SomeServiceImpl"
init-method="initPost" destroy-method="preDestory">
<property name="dao1" value="myDao1"/>
<property name="dao2" value="myDao2"/>
<property name="dao3" value="myDao3"/>
</bean> <bean class="com.tongji.ba07.MyBeanPostProcessor"/> </beans>

      需要做的是,在 Bean 后处理器类方法中,只要对 Bean 类与 Bean 类中的方法进行判断,就可实现对指定的 Bean 的指定方法进行功能扩展与增强。方法返回的 Bean 对象,即是增过的对象。
      代码中需要自定义 Bean 后处理器类。该类就是实现了接口 BeanPostProcessor 的类。该接口中包含两个方法,分别在目标 Bean 初始化完毕之前与之后执行。它们的返回值为:功能被扩展或增强后的 Bean 对象。    

 package com.tongji.ba07;

 import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor { //bean:当前正在被初始化的Bean
//beanName:当前正在被初始化的Bean的id
//在当前Bean的所有属性均被初始化完毕之前 执行该方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("Step5:执行Bean后处理器的before方法");
//返回bean,在下一个bean初始化时继续执行
return bean;
} //在当前bean的所有属性均被初始化完毕之后 执行该方法
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName)
throws BeansException {
System.out.println("Step8:执行Bean后处理器的after方法");
return bean;
} }

      Bean 初始化完毕有一个标志:Step6中 afterPropertiesSet() 方法将被执行。即当该方法被执行时,表示该 Bean 被初始化完毕。所以 Bean 后处理器中两个方法的执行,是在这个方法之前之后执行。

    2. Step7和Step11中的Bean的定制生命始末:

      可以为 Bean 定制初始化后的生命行为,也可以为 Bean 定制销毁前的生命行为。首先,这些方法需要在 Bean 类中事先定义好:是方法名随意的 public void 方法。其次,在配置文件的<bean/>标签中增加如下属性(配置文件见上面的补充1):  
        init-method:指定初始化方法的方法名  
        destroy-method:指定销毁方法的方法名

 package com.tongji.ba07;

 import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean; public class SomeServiceImpl implements ISomeService, BeanNameAware,
BeanFactoryAware, InitializingBean, DisposableBean{
private String dao1;
private String dao2;
private String dao3; public SomeServiceImpl() {
System.out.println("Step1:调用Bean的无参构造器");
} public void setDao1(String dao1) {
this.dao1 = dao1;
System.out.println("Step2:调用属性的setter(dao1)");
} public void setDao2(String dao2) {
this.dao2 = dao2;
System.out.println("Step2:调用属性的setter(dao2)");
} public void setDao3(String dao3) {
this.dao3 = dao3;
System.out.println("Step2:调用属性的setter(dao3)");
} @Override
public void setBeanName(String name) {
System.out.println("Step3:当前Bean的id为" + name);
} @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Step4:获取BeanFactory容器");
} @Override
public void afterPropertiesSet() throws Exception {
System.out.println("Step6:Bean的初始化工作全部完成");
} public void initPost() {
System.out.println("Step7:Bean刚被初始化");
} @Override
public String doSome() {
System.out.println("Step9:执行doSome()");
return "China";
} @Override
public String doOther() {
System.out.println("执行doOther()");
return "abcde";
} @Override
public void destroy() throws Exception {
System.out.println("Step10:Bean销毁前的工作");
} public void preDestory() {
System.out.println("Step11:Bean马上就要Game Over了");
}
}

      注意,若要看到 Bean 的 destroy-method 的执行结果,需要满足两个条件:
        (1)Bean 为 singleton,即单例
        (2)要确保容器关闭。接口 ApplicationContext 没有 close()方法,但其实现类有。所以,可以将 ApplicationContext 强转为其实现类对象,或直接创建的就是实现类对象。

 package com.tongji.ba07;

 import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class MyTest { @Test
public void test01() {
//创建容器
String resource = "com/tongji/ba07/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
ISomeService someService1 = (ISomeService) ac.getBean("someService1");
someService1.doSome();
//要看到销毁方法的执行,需要两个条件:
//1.Bean需要singleton的
//2.手工将容器关闭
((ClassPathXmlApplicationContext)ac).close(); }
}

  4. <bean/>标签的 id 属性与 name 属性 :
    一般情况下,命名<bean/>使用 id 属性,而不使用 name 属性。在没有 id 属性的情况下,name 属性与 id 属性作用是相同的。但,当<bean/>中含有一些特殊字符时,就需要使用 name属性了。  
    id 的命名需要满足 XML 对 ID 属性命名规范:必须以字母开头,可以包含字母、数字、下划线、连字符、句话、冒号。且要求名称在容器中必须唯一。  
    name 则可以包含各种字符,且对名称没有唯一性要求。若名称不唯一,则后面的会覆盖前面的。

Spring4笔记3--Bean的装配的更多相关文章

  1. Spring4学习笔记 - 配置Bean - 自动装配 关系 作用域 引用外部属性文件

    1 Autowire自动装配 1.1 使用:只需在<bean>中使用autowire元素 <bean id="student" class="com.k ...

  2. SpringInAction读书笔记--第2章装配Bean

    实现一个业务需要多个组件相互协作,创建组件之间关联关系的传统方法通常会导致结构复杂的代码,这些代码很难被复用和单元测试.在Spring中,对象不需要自己寻找或创建与其所关联的其它对象,Spring容器 ...

  3. 【Spring】Spring中的Bean - 5、Bean的装配方式(XML、注解(Annotation)、自动装配)

    Bean的装配方式 简单记录-Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)-Spring中的Bean 文章目录 Bean的装配方式 基于XML的装配 基于注解 ...

  4. Spring bean依赖注入、bean的装配及相关注解

    依赖注入 Spring主要提供以下两种方法用于依赖注入 基于属性Setter方法注入 基于构造方法注入 Setter方法注入 例子: public class Communication { priv ...

  5. Spring学习记录(三)---bean自动装配autowire

    Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系,少写几个ref autowire: no ---默认情况,不自动装配,通过ref手动引用 byName---根据 ...

  6. Spring - 配置Bean - 自动装配 关系 作用域 引用外部属性文件

    1 Autowire自动装配1.1 使用:只需在<bean>中使用autowire元素<bean id="student" class="com.kej ...

  7. spring2——IOC之Bean的装配

    spring容器对于bean的装配提供了两个接口容器分别是"ApplicationContext接口容器"和"BeanFactory接口容器",其中" ...

  8. Spring温故而知新 - bean的装配(续)

    按条件装配bean 就是当满足特定的条件时Spring容器才创建Bean,Spring中通过@Conditional注解来实现条件化配置bean package com.sl.ioc; import ...

  9. Spring温故而知新 - bean的装配

    Spring装配机制 Spring提供了三种主要的装配机制: 1:通过XML进行显示配置 2:通过Java代码显示配置 3:自动化装配 自动化装配 Spring中IOC容器分两个步骤来完成自动化装配: ...

随机推荐

  1. linq 左连接实现两个集合的合并

    //第一个集合为所有的数据 var specilist = new List<Me.SpecificationsInfo>(); var resultall = (from a in db ...

  2. hdu6438 Buy and Resell

    多少年不写题了... (我把每一天看作是一个商品,第i天是第i个商品) 一开始看了半天看出来一个性质:买的所有商品中最贵的不会比卖的所有商品中最便宜的贵,然后似乎没有什么用处.... 所以最后还是看题 ...

  3. 洛谷3732:[HAOI2017]供给侧改革——题解

    https://www.luogu.org/problemnew/show/P3732 Anihc国提高社会生产力水平.落实好以人民为中心的发展思想.决定进行供给侧结构性改革. 为了提高供给品质.你调 ...

  4. Alpha 冲刺 —— 十分之九

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 多次测试软件运行 学习OPENMP ...

  5. Alpha 冲刺 —— 十分之七

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 学习MSI.CUDA 试运行软件并调试 ...

  6. USACO Section 1.5 Superprime Rib 解题报告

    题目 题目描述 超级素数的定义如下:如果有个素数我们从右往左依次去掉一位数,每次去掉一位数剩下的数仍然是素数,那么我们称这个数是超级素数.例如7331,这是一个素数,从右往左依次去掉一位数733, 7 ...

  7. 【Learning】插头DP

    简介 插头DP(轮廓线DP)是用来解决网格图回路问题的一种算法. 插头DP解决的经典问题就是统计经过所有格子的哈密顿回路条数,某些格子有障碍. ​ 如果问题稍微进阶一点的话,不一定要求路径是回路.路径 ...

  8. WEB入门二 表格和表单

    学习内容 Ø        表格的作用和制作 Ø        表单的制作 能力目标 Ø        掌握表格的创建 Ø        掌握设置表格的常用属性: Ø        理解表单的作用 Ø ...

  9. Java之Stream流

    Stream流的初步学习 初次学习Stream流的学习笔记,学习之前先了解一下函数式接口 概述 API是一个程序向使用者提供的一些方法,通过这些方法就能实现某些功能.所以对于流API来 说,重点是怎么 ...

  10. cocoaPods安装、更新第三方库

    pod install 换成 pod install --verbose --no-repo-update pod update 换成 pod update --verbose --no-repo-u ...