本文是王福强所著<<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>

看看client的代码

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启动时的时序图. 第一次接触时序图,可能有些地方画的不是很符合时序图的规则,大家只关注调用顺序即可. public static void main(Stri ...

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

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

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

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

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

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

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

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

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

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

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

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

  9. Spring揭秘 读书笔记 五 容器的启动

    Spring的IoC容器所起的作用,就是生产bean,并维持bean间的依赖关系.它会以某种方式加载Configuration Metadata(通常也就是XML格式的配置信息),然后根据这些信息绑定 ...

随机推荐

  1. HTML5常见的面试题,基础知识点

                                                                                    HTML5常见的面试题 一.HTML 常 ...

  2. php安装redis扩展 windows

    官方php_redis.dll 找了很久,感谢热心的网友,这是php官方的 php_redis.dll http://windows.php.net/downloads/pecl/releases/r ...

  3. 【【henuacm2016级暑期训练】动态规划专题 E】Destroying Roads

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 首先. 这张图是无向无权图. 因此任意两点之间的最短路可以通过N^2的bfs轻易算出来. 即得到d[N+10][N+10] 考虑s[ ...

  4. 【Codeforces Round #482 (Div. 2) B】Treasure Hunt

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 我们考虑每个字符串中出现最多的字母出现的次数cnt[3] 对于这3个cnt的值. 如果cnt+n<=s[i].size 那么显 ...

  5. HDU 2155 Matrix

    Matrix Time Limit: 3000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 215 ...

  6. [Angular] Provide Feedback to Progress Events with Angular’s HttpRequest Object

    In some cases your application might need to upload large amounts of data, such as files. Obviously ...

  7. java mail邮件发送(带附件) 支持SSL

    java mail邮件发送(带附件)有三个类 MailSenderInfo.java package mail; import java.util.Properties; import java.ut ...

  8. android init进程分析 init脚本解析和处理

    (懒人近期想起我还有csdn好久没打理了.这个android init躺在我的草稿箱中快5年了.略微改改发出来吧) RC文件格式 rc文件是linux中常见的启动载入阶段运行的文件.rc是run co ...

  9. 《从零開始学Swift》学习笔记(Day5)——我所知道的标识符和keyword

     Swift 2.0学习笔记(Day5)--我所知道的标识符和keyword   原创文章,欢迎转载.转载请注明:关东升的博客 好多计算机语言都有标识符和keyword,一直没有好好的总结,就是这 ...

  10. m_Orchestrate learning system---十一、thinkphp查看临时文件的好处是什么

    m_Orchestrate learning system---十一.thinkphp查看临时文件的好处是什么 一.总结 一句话总结:可以知道thinkphp的标签被smarty引擎翻译而来的php代 ...