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. oracle 慢查询

    一.查询执行最慢的sql select * from (select sa.SQL_TEXT, sa.SQL_FULLTEXT, sa.EXECUTIONS "执行次数", , ) ...

  2. SpringBoot整合Kotlin构建Web服务

    今天我们尝试Spring Boot整合Kotlin,并决定建立一个非常简单的Spring Boot微服务,使用Kotlin作为编程语言进行编码构建. 创建一个简单的Spring Boot应用程序.我会 ...

  3. Java之使用链表实现队列

    import java.util.Iterator; import java.util.NoSuchElementException; /** * 使用链表来实现队列 * 1.考虑结点的结构,包括当前 ...

  4. 学习操作Mac OS 之安装工具组件

    视频软件: MPlayerX 安装MySQL: 下载MySQL: https://dev.mysql.com/downloads/installer/ 设置环境变量:http://www.cnblog ...

  5. python对MySQL的CRUD

    我是闲的没事干,2014过的太浮夸了,博客也没写几篇,哎~~~ 用这篇来记录即将逝去的2014 python对各种数据库的各种操作满大街都是,不过,我还是喜欢我这种风格的,涉及到其它操作,不过重点还是 ...

  6. opencv imread值为空

    调试程序错误如下: 此时test.jpg文件放在了sln解决方案文件夹内,并没有放在proj项目文件夹内,放到项目文件夹下后,调试如下图 这时候img就读取到图像了,最终显示图像如下,显示的很大,再研 ...

  7. C++命名规则 (转载仅作参考)

    如果想要有效的管理一个稍微复杂一点的体系,针对其中事物的一套统一.带层次结构.清晰明了的命名准则就是必不可少而且非常好用的工具. 活跃在生物学.化学.军队.监狱.黑社会.恐怖组织等各个领域内的大量有识 ...

  8. HDU 6249

    Alice’s Stamps Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)To ...

  9. python 异常处理(try...finally...和with...as 方法)

    try...finally... 结构 我们在执行一长串关联命令时,会有一个问题,如果当中一个命令失败了,整个命令串事实上就没有必要执行下去了.在异常发生时,我们也需要执行一些收场工作.比如 clos ...

  10. Git4:Git标签

    目录 简介 新建标签 查看标签详细信息 切换标签 后期添加标签 将标签推送到远端仓库 简介 Git可以对某一时间点上的版本打上标签.人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做.本 ...