本文是王福强所著<<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. Linux基础指令

    Linux基础指令 只写了最简单的一些文件操作,基本没有带参数 查看当前目录 pwd 跳转到某路径 cd 查看当前目录下的文件 ls ls -l // -l 查看详细信息 打开当前所在文件夹 open ...

  2. 在ubuntu上搭建交叉编译环境---arm-none-eabi-gcc

    最近要开始搞新项目,基于arm的高通方案的项目. 那么,如何在ubuntu上搭建这个编译环境呢? 1.找到相关的安装包:http://download.csdn.net/download/storea ...

  3. mysql进阶(二十八)MySQL GRANT REVOKE用法

    mysql进阶(二十八)MySQL GRANT REVOKE用法   MySQL的权限系统围绕着两个概念: 认证->确定用户是否允许连接数据库服务器: 授权->确定用户是否拥有足够的权限执 ...

  4. maven跳过单元测试的两个参数区别

    maven在打包过程中需要执行单元测试.但有些时候单元测试已经通过只是想打包时,想跳过测试.maven提供了两个参数跳过测试:maven.test.skip=true 和skipTests. 例子 m ...

  5. iOS9中如何注册远程通知

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在以往的版本中,我们可以通过: [[UIApplication ...

  6. Python图片处理库之PIL

    这个模块对于Python2.7 的windows64位电脑而言,还真的是不好找啊.这里分享一个下载链接吧,需要的朋友可以下载下来.PIL For Windows64 Python2.7下面分享一下这个 ...

  7. API创建员工联系人

    DECLARE ln_contact_rel_id PER_CONTACT_RELATIONSHIPS.CONTACT_RELATIONSHIP_ID%TYPE; ln_ctr_object_ver_ ...

  8. 流量控制闸门——LimitLatch套接字连接数限制器

    Tomcat作为web服务器,对于每个客户端的请求将给予处理响应,但对于一台机器而言,访问请求的总流量有高峰期且服务器有物理极限,为了保证web服务器不被冲垮我们需要采取一些措施进行保护预防,需要稍微 ...

  9. 解读“Deep Neural Decision Forests” 2015 Winner of the David Marr Prize

    2015ICCV会议最佳论文奖,即有着"计算机视觉界最高奖"之称的马尔奖(Marr Prize)授予了由微软剑桥研究院(Microsoft Research, Cambridge  ...

  10. pyinstaller相关错误

    http://blog.csdn.net/pipisorry/article/details/50620495 目录结构   将主文件testMain.py转换成exe可执行文件 主文件调用了自定义包 ...