spring揭秘 读书笔记 二 BeanFactory的对象注册与依赖绑定
本文是王福强所著<<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的对象注册与依赖绑定的更多相关文章
- spring揭秘 读书笔记 二 BeanFactory的对象注冊与依赖绑定
本文是王福强所著<<spring揭秘>>一书的读书笔记 我们前面就说过,Spring的IoC容器时一个IoC Service Provider,并且IoC Service Pr ...
- Spring中BeanFactory的对象注册与依赖绑定方式
概念 BeanFactory是spring的基础类型IOC容器,提供完整的IOC服务支持 默认采用延迟初始化策略,当客户端对象访问受管对象时,才对其进行初始化和依赖注入 理解 BeanFactory将 ...
- Spring揭秘 读书笔记 七 BeanFactory的启动分析
首先,先看我自己画的BeanFactory启动时的时序图. 第一次接触时序图,可能有些地方画的不是很符合时序图的规则,大家只关注调用顺序即可. public static void main(Stri ...
- spring揭秘读书笔记----spring的ioc容器之BeanFactory
spring的ioc容器是一种特殊的Ioc Service Provider(ioc服务提供者),如果把普通的ioc容器认为是工厂模式(其实很相似),那spring的ioc容器只是让这个工厂的功能更强 ...
- Spring揭秘 读书笔记 三 bean的scope与FactoryBean
本书可作为王富强所著<<Spring揭秘>>一书的读书笔记 第四章 BeanFactory的xml之旅 bean的scope scope有时被翻译为"作用域&quo ...
- spring揭秘 读书笔记 一 IoC初探
本文是王福强所著<<spring揭秘>>一书的读书笔记 ioc的基本概念 一个例子 我们看下面这个类,getAndPersistNews方法干了四件事 1 通过newsList ...
- Spring揭秘读书笔记 八 数据访问异常体系
这篇博客 来自spring揭秘一书的第十三章 为什么要有访问异常都有一个体系,这个我们得从DAO模式说起. DAO模式 任何一个系统,不管是一个最简单的小系统,还是大规模的系统,都得跟数据打交道,说白 ...
- spring揭秘读书笔记----ioc的基本概念
在看ico概念之前,先想一下我们平常需要依赖某个类时会怎么做? 无非是在要用到的地方写如下代码: Person person = new Person(); //然后就可以用person对象来获取Pe ...
- spring揭秘 读书笔记 六 bean的一生
我们知道,Spring容器具有对象的BeanDefinition来保存该对象实例化时需要的数据. 对象通过container.getBean()方法是才会初始化该对象. BeanFactory 我们知 ...
随机推荐
- 实验与作业(Python)-03 Python程序实例解析
截止日期: 要求: 下周实验课前上交,做好后在实验课上检查可获取平时分. 做出进阶或选做的的请用清晰的标致标识出来,方便老师批改 本次作业:可提交也可不提交.作业算平时成绩. 本次作业内容量较大,请组 ...
- Android开发艺术探索第五章——理解RemoteViews
Android开发艺术探索第五章--理解RemoteViews 这门课的重心在于RemoteViews,RemoteViews可以理解为一种远程的View,其实他和远程的Service是一样的,Rem ...
- JVM:类的生命周期
类的生命周期 综述 1. 只有当一个类被切实使用到的时候才会被加载到虚拟机中(例如:new, 方法调用, A a = null;不算) 2. 若在加载一个类的过程中,有其他类被切实使用到, ...
- python 列表解析与map和filter函数
不知哪儿看到一个说法,大概是当map的函数参数可以直接引用一个已有的函数变量时(比如内建函数int,str之类的),用map更优美些,否则还是用列表解析更直观和快速. 我同意此说法. 昨天在写一个函数 ...
- Linux 高性能服务器编程——多进程编程
问题聚焦: 进程是Linux操作系统环境的基础. 本篇讨论以下几个内容,同时也是面试经常被问到的一些问题: 1 复制进程映像的fork系统调用和替换进程映像的exec系列系统调 ...
- [django]urls.py 中重定向
Django 1.5 有时候需要对一个链接直接重定向,比如首页啥的重定向到一个内容页等等,在views.py 中可以设定,如果没有参数啥的在urls.py 中设定更加方面 from django.vi ...
- 在Windows Service 2012上安装IIS 8.0 IIS 6
我的目的是在服务器上安装IIS6 ,但是受到这边文章的启发和按照他的步骤,看到了"IIS 6管理兼容性",我的问题就决解了,我这里是因为要安装vss 2005 和u8等比较早期的软 ...
- 全文检索概念,Lucene大致结构
1.1 常见的全文检索 1) 在window系统中,可以指定磁盘中的某一个位置来搜索你想要得到的东西. 2) 在myeclipse中,点击Help->Help Contents,可以利用搜索功能 ...
- 带你深入理解STL之迭代器和Traits技法
在开始讲迭代器之前,先列举几个例子,由浅入深的来理解一下为什么要设计迭代器. //对于int类的求和函数 int sum(int *a , int n) { int sum = 0 ; for (in ...
- Android开发优化之——使用软引用和弱引用
Java从JDK1.2版本开始,就把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期.这四种级别由高到低依次为:强引用.软引用.弱引用和虚引用. 这里重点介绍一下软引用和弱引用. 如果 ...