本文是王福强所著<<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. 部署 Helm - 每天5分钟玩转 Docker 容器技术(162)

    本节我们将安装和部署 Helm 客户端和 Tiller 服务器. Helm 客户端 通常,我们将 Helm 客户端安装在能够执行 kubectl 命令的节点上,只需要下面一条命令: curl http ...

  2. 亲密接触Redis-第三天(Redis的Load Balance)

    前言 上两天讲述了Redis的基本搭建和基于HA的集群布署方式以及相关的策略和注意点.今天开始讲述Redis的Cluster功能,而这块目前来说网上资料不是太全,就算有1,2篇也只是单讲服务端的搭建也 ...

  3. (译)快速指南:用UIViewPropertyAnimator做动画

    翻译自:QUICK GUIDE: ANIMATIONS WITH UIVIEWPROPERTYANIMATOR 译者:Haley_Wong iOS 10 带来了一大票有意思的新特性,像 UIViewP ...

  4. Spring Boot 中应用Spring data mongdb

    摘要 本文主要简单介绍下如何在Spring Boot 项目中使用Spring data mongdb.没有深入探究,仅供入门参考. 文末有代码链接 准备 安装mongodb 需要连接mongodb,所 ...

  5. Java异常处理-----抛出处理

    抛出处理 定义一个功能,进行除法运算例如(div(int x,int y))如果除数为0,进行处理. 功能内部不想处理,或者处理不了.就抛出使用throw new Exception("除数 ...

  6. windows下Eclipse操作MapReduce例子报错:Failed to set permissions of path: \tmp\hadoop-Jerome\mapred\staging\

    windows下Eclipse操作MapReduce例子报错: 14/05/18 22:05:29 WARN util.NativeCodeLoader: Unable to load native- ...

  7. ListView之侧滑删除

    SwipeMenuListView 是一个为listview添加item侧滑菜单的开源库,项目地址:https://github.com/baoyongzhang/SwipeMenuListView ...

  8. Linux网络和进程管理

     1) 计算机网络是通过外围的设备和连接,将分布在相同或不同区域的多台计算机 连接在一起所形成的集合.网络中的计算机实现彼此间互相通信,并且可以共 同使用硬件.软件和数据资源,实现资源共享.Lin ...

  9. Python图片处理库之PIL

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

  10. 6.2、Android Studio内存

    Android Monitor提供了一个Memory Monitor,所以你可以非常容易的监测应用性能和内存使用,可以发现无用的对象,本地内存泄漏和连接设备的内存使用.Memory Monitor显示 ...