本文是王福强所著<<spring揭秘>>一书的读书笔记

我们前面就说过,Spring的IoC容器时一个IoC Service Provider,而且IoC Service Provider提供两个功能对象的创建,依赖关系的管理。

不过,IoC容器这个词中,我们还得关注容器二字。它还包含了一些别的功能,如下图







Spring提供了两种类型的容器,分别是BeanFactory与ApplicationContext。

它们的区别在于:

BeanFactory:对于它所管理的bean,采取的是延迟加载模式,也就是说等用户使用某个bean的时候,采取加载它;另外,它启动所需要的资源也比较少。

ApplciationContext:除了拥有BeanFctory的全部功能外,它还提供了一些高级特性。对应它所管理的对象,在容器启动的时候就把所有的bean都加载了,而且启动时需要的资源也比较多。

两个容器的关系如下:







我们看看BeanFactory的接口说明,都是些跟查询相关的方法。

拥有BeanFactory之后的生活

FXNewsProvider与DowJonesNewsListener等等的代码,我就不写了。

在采用IoC模式之前,我们是这么写代码的

FXNewsProvider newsProvider = new FXNewsProvider();
newsProvider.getAndPersistNews(); 

在之前的章节里,我们就说了IoC模式的好处就是用户不用处理各个组件间的依赖问题了。

那谁来处理呢?丢给BeanFactory。

首先,我们用xml来说明依赖关系

<beans>
  <bean id="djNewsProvider" class="..FXNewsProvider"> 

  <constructor-arg index="0">
	 <ref bean="djNewsListener"/>
   </constructor-arg> 

   <constructor-arg index="1">
	<ref bean="djNewsPersister"/>
   </constructor-arg>
  </bean>
  ...
</beans> 

看看客户端的代码

BeanFactory container = new XmlBeanFactory(new ClassPathResource("配置文件路径"));
FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
newsProvider.getAndPersistNews(); 

至于XmlBeanFactory是个什么东西,大家看名字猜也能猜出来,就是一个实现了BeanFactoy且能从xml中读取依赖关系的对象嘛。

或者

ApplicationContext container = new ClassPathXmlApplicationContext("配置文件路径");
FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
newsProvider.getAndPersistNews(); 

OK,这次使用了ClassPathXmlApplicationContext,就是一个实现了ApplicationContext且能从xml中读取依赖关系的对象嘛。

再或者

ApplicationContext container = new FileSystemXmlApplicationContext("配置文件路径");
FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
newsProvider.getAndPersistNews();  

后两者有什么区别?

1、ClassPathXmlApplicationContext

这个方法是从classpath下加载配置文件(适合于相对路径方式加载),例如:

ApplicationContext ctx = new ClassPathXmlApplicationContext( "/applicationcontext.xml ");

该方法参数中classpath: 前缀是不需要的,默认就是指项目的classpath路径下面;这也就是说用ClassPathXmlApplicationContext时默认的根目录是在WEB-INF/classes下面,而不是项目根目录。这个需要注意!





2、FileSystemXmlApplicationContext

这个方法是从文件绝对路径加载配置文件,例如:

ApplicationContext ctx = new FileSystemXmlApplicationContext( "G:/Test/applicationcontext.xml ");

如果在参数中写的不是绝对路径,那么方法调用的时候也会默认用绝对路径来找,我测试的时候发现默认的绝对路径是eclipse所在的路径。

采用绝对路径的话,程序的灵活性就很差了,所以这个方法一般不推荐。

(如果要使用classpath路径,需要加入前缀classpath:   )

BeanFactory的对象注册与依赖绑定方式

在上一章,我们就提到spring绑定依赖关系的方式有三种:直接编码,通过配置文件,通过注解方式。

我们一个一个来看

直接编码

public static void main(String[] args)  {
  DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
  BeanFactory container = (BeanFactory)bindViaCode(beanRegistry);
  FXNewsProvider newsProvider =
  (FXNewsProvider)container.getBean("djNewsProvider");
  newsProvider.getAndPersistNews();
} 

public static BeanFactory bindViaCode(BeanDefinitionRegistry registry) {
    AbstractBeanDefinition newsProvider =
    new RootBeanDefinition(FXNewsProvider.class,true);
    AbstractBeanDefinition newsListener =
    new RootBeanDefinition(DowJonesNewsListener.class,true);
    AbstractBeanDefinition newsPersister =
    new RootBeanDefinition(DowJonesNewsPersister.class,true); 

    // 将bean定义注册到容器中
    registry.registerBeanDefinition("djNewsProvider", newsProvider);
    registry.registerBeanDefinition("djListener", newsListener);
    registry.registerBeanDefinition("djPersister", newsPersister); 

    // 指定依赖关系
    // 1. 可以通过构造方法注入方式
    ConstructorArgumentValues argValues = new ConstructorArgumentValues();
    argValues.addIndexedArgumentValue(0, newsListener);
    argValues.addIndexedArgumentValue(1, newsPersister);
    newsProvider.setConstructorArgumentValues(argValues); 

    // 2. 或者通过setter方法注入方式
    MutablePropertyValues propertyValues = new MutablePropertyValues();
    propertyValues.addPropertyValue(new ropertyValue("newsListener",newsListener));
    propertyValues.addPropertyValue(new PropertyValue("newPersistener",newsPersister));
    newsProvider.setPropertyValues(propertyValues);
    // 绑定完成
    return (BeanFactory)registry;
}  

我们看看上面几个对象的uml类图。

一个一个说,BeanDefinition,见名知意,是一个对bean的描述对象。RootBeanDefinition与ChildBeanDefinition都是BeanDefinition的实现类。

RootBeanDefinition与ChildBeanDefinition有什么区别?

java中的类是有继承关系,在xml中,bean包含一个parent属性。

RootBeanDefinition:一个bean就是一个顶级对象(没有parent)

ChildBeanDefinition:对应于一个子Bean定义,他是从一个已有的Bean继承而来

ChildBeanDefinitionl里面有一个私有变量parentName。





下来就是BeanDefinitionRegistry

BeanDefinitionRegistry也是一个接口,其方法如下:

registerBeanDefinition干的事情就是把bean与name对应起来,并且把bean的实例与name都存储起来,以后再用。

DefaultListableBeanFactory实现了BeanDefinitionRegistry接口:

里面有这个两个私有属性,看看名字就知道它是干什么的了

        /** Map of bean definition objects, keyed by bean name */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);

	/** List of bean definition names, in registration order */
	private final List<String> beanDefinitionNames = new ArrayList<String>();

说实话,我不明白为什么还需要有一个beanDefinitionNames,beanDefinitionMap的key不就是beanname吗?





解释了这么多了,我想上面使用硬代码绑定依赖关系的例子,我就不解释了,大家都能看懂。

外部配置文件方式

通过xml或者Properties文件加载依赖信息的情况还是比通过硬代码加载依赖关系普遍(或者说通过硬代码加载,本身就是为了说明问题,实际中倒是不会这么用)。

加载外部文件,那么首先就得介绍一个接口。

BeanDefinitionReader。

看名字就知道,这个接口管的是读取BeanDefinition的信息(准确的说是从外部文件读取信息,填充到BeanDefinition中)。

它有两个实现类 PropertiesBeanDefinitionReader, XmlBeanDefinitionReader

看名字就知道,一个从Properties中读,一个从xml中读。

从properties

Properties文件如下:

djNewsProvider.(class)=..FXNewsProvider
# ----------通过构造方法注入的时候-------------
djNewsProvider.$0(ref)=djListener
djNewsProvider.$1(ref)=djPersister
# ----------通过setter方法注入的时候---------
# djNewsProvider.newsListener(ref)=djListener
# djNewsProvider.newPersistener(ref)=djPersister 

djListener.(class)=..impl.DowJonesNewsListener 

djPersister.(class)=..impl.DowJonesNewsPersister 

调用例子如下:

public static void main(String[] args)  {
  DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
  BeanFactory container = (BeanFactory)bindViaPropertiesFile(beanRegistry);
  FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
  newsProvider.getAndPersistNews();
} 

public static BeanFactory bindViaPropertiesFile(BeanDefinitionRegistry registry) {
  PropertiesBeanDefinitionReader reader =  new PropertiesBeanDefinitionReader(registry);
  reader.loadBeanDefinitions("classpath:../../binding-config.properties");
  return (BeanFactory)registry;
} 

从xml

xml如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" ➥
"http://www.springframework.org/dtd/spring-beans.dtd"> 

<beans>
  <bean id="djNewsProvider" class="..FXNewsProvider">
   <constructor-arg index="0">
    <ref bean="djNewsListener"/>
   </constructor-arg>
   <constructor-arg index="1">
    <ref bean="djNewsPersister"/>
   </constructor-arg>
  </bean> 

  <bean id="djNewsListener" class="..impl.DowJonesNewsListener">
  </bean>
  <bean id="djNewsPersister" class="..impl.DowJonesNewsPersister">
  </bean>
</beans>     

调用代码如下:

public static void main(String[] args)  {
  DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
  BeanFactory container = (BeanFactory)bindViaXMLFile(beanRegistry);
  FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("djNewsProvider");
  newsProvider.getAndPersistNews();
  } 

public static BeanFactory bindViaXMLFile(BeanDefinitionRegistry registry) {
  XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(registry);
  reader.loadBeanDefinitions("classpath:../news-config.xml");
   return (BeanFactory)registry;
  // 或者直接
  //return new XmlBeanFactory(new ClassPathResource("../news-config.xml"));
}  

跟上面的properties每什么区别,就是多了一个XmlBeanFactory。

通过查看api文档,我们知道XmlBeanFactory直接继承自DefaultListableBeanFactory。

注解方式

自从sping2.5之后,有了注解方式,它就一下子收到了广大程序员的热烈欢迎。

bean示例:

@Component
public class FXNewsProvider  {
  @Autowired
  private IFXNewsListener  newsListener;
  @Autowired
  private IFXNewsPersister newPersistener; 

  public FXNewsProvider(IFXNewsListener newsListner,IFXNewsPersister newsPersister)
  {
   this.newsListener   = newsListner;
   this.newPersistener = newsPersister;
  }
  ...
} 

@Component
public class DowJonesNewsListener implements IFXNewsListener  {
  ...
} 

@Component
public class DowJonesNewsPersister implements IFXNewsPersister  {
  ...
}   

@Component 是告诉spring的扫描器:这是一个bean。

@Autowired 是告诉spring的扫描器:这里需要一个注入对象。

示例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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<context:component-scan base-package="cn.spring21.project.base.package"/>
</beans>

<context:component-scan base-package="cn.spring21.project.base.package"/>就是告诉spring容器,扫描cn.spring21.project.base.package这个包,看哪里有 @Component @Autowired等等。





下面就是大家看到的第一spring程序。

public static void main(String[] args) {
  ApplicationContext ctx = new ClassPathXmlApplicationContext("配置文件路径");
  FXNewsProvider newsProvider = (FXNewsProvider)container.getBean("FXNewsProvider");
   newsProvider.getAndPersistNews();
}    

感谢glt

参考资料

http://blog.csdn.net/souichiro/article/details/6068552

http://blog.csdn.net/turkeyzhou/article/details/2910888

spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定的更多相关文章

  1. spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定

    本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...

  2. Spring中BeanFactory的对象注册与依赖绑定方式

    概念 BeanFactory是spring的基础类型IOC容器,提供完整的IOC服务支持 默认采用延迟初始化策略,当客户端对象访问受管对象时,才对其进行初始化和依赖注入 理解 BeanFactory将 ...

  3. Spring揭秘 读书笔记 七 BeanFactory的启动分析

    首先,先看我自己画的BeanFactory启动时的时序图. 第一次接触时序图,可能有些地方画的不是很符合时序图的规则,大家只关注调用顺序即可. public static void main(Stri ...

  4. spring揭秘读书笔记----spring的ioc容器之BeanFactory

    spring的ioc容器是一种特殊的Ioc Service Provider(ioc服务提供者),如果把普通的ioc容器认为是工厂模式(其实很相似),那spring的ioc容器只是让这个工厂的功能更强 ...

  5. Spring揭秘 读书笔记 三 bean的scope与FactoryBean

    本书可作为王富强所著<<Spring揭秘>>一书的读书笔记  第四章 BeanFactory的xml之旅 bean的scope scope有时被翻译为"作用域&quo ...

  6. spring揭秘 读书笔记 一 IoC初探

    本文是王福强所著<<spring揭秘>>一书的读书笔记 ioc的基本概念 一个例子 我们看下面这个类,getAndPersistNews方法干了四件事 1 通过newsList ...

  7. Spring揭秘读书笔记 八 数据访问异常体系

    这篇博客 来自spring揭秘一书的第十三章 为什么要有访问异常都有一个体系,这个我们得从DAO模式说起. DAO模式 任何一个系统,不管是一个最简单的小系统,还是大规模的系统,都得跟数据打交道,说白 ...

  8. spring揭秘读书笔记----ioc的基本概念

    在看ico概念之前,先想一下我们平常需要依赖某个类时会怎么做? 无非是在要用到的地方写如下代码: Person person = new Person(); //然后就可以用person对象来获取Pe ...

  9. spring揭秘 读书笔记 六 bean的一生

    我们知道,Spring容器具有对象的BeanDefinition来保存该对象实例化时需要的数据. 对象通过container.getBean()方法是才会初始化该对象. BeanFactory 我们知 ...

随机推荐

  1. Python能做些什么?

    前言 网上搜集到的一些python能做什么的资料,利用python能做很多事情,我们可以在多门课程中都使用Python作为我们的教学语言.比如,计算机网络.数据结构.人工智能.图像处理.软件分析与测试 ...

  2. Android简易实战教程--第四十九话《满屏拖动的控件》

    今天做个有意思的效果吧,控件的拖拽,简单实用,逻辑清晰点3分钟看完. 说的很高大上,其实就是拖动Button按钮跟着鼠标位置满手机屏幕跑罢了. 直接上简单的代码吧: public class Main ...

  3. move_uploaded_file的failed to open stream错误处理

    PHP的基本语法学习的差不多了,现在开始学习PHP的文件上传功能实现了.功能中使用到了move_uploaded_file方法,运行时报错: failed to open stream. 经过查资料, ...

  4. oracle手工生成AWR报告方法记录

    AWR(Automatic Workload Repository)报告是我们进行日常数据库性能评定.问题SQL发现的重要手段.熟练掌握AWR报告,是做好开发.运维DBA工作的重要基本功. AWR报告 ...

  5. Servlet - 基础

    Servlet 标签 : Java与Web HTTP协议 HTTP(hypertext transport protocol),即超文本传输协议.这个协议详细规定了浏览器(Browser)和万维网服务 ...

  6. android的消息通知栏

    在android的应用层中,涉及到很多应用框架,例如:Service框架,Activity管理机制,Broadcast机制,对话框框架,标题栏框架,状态栏框架,通知机制,ActionBar框架等等. ...

  7. time,gettimeofday,clock_gettime

    time()提供了秒级的精确度 1.头文件 <time.h> 2.函数原型 time_t time(time_t * timer) 函数返回从UTC1970-1-1 0:0:0开始到现在的 ...

  8. Spark技术内幕: Shuffle详解(三)

    前两篇文章写了Shuffle Read的一些实现细节.但是要想彻底理清楚这里边的实现逻辑,还是需要更多篇幅的:本篇开始,将按照Job的执行顺序,来讲解Shuffle.即,结果数据(ShuffleMap ...

  9. GDAL 2.0版本RPC校正速度测试

    GDAL2.0版本的更新日志中提到了对RPC校正的优化,今天测试了一下,发现提升的速度还是蛮快的,测试的数据是一个IRS-P5的数据. 单线程测试 首先使用一个线程进行测试,使用下面的批处理进行运行, ...

  10. Swift中实现ruby中字符串乘法倍增的功能

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在ruby中对于字符串类型我们可以用乘法生成一个指定数 ...