zoukankan      html  css  js  c++  java
  • 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> 
    看看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
  • 相关阅读:
    HTTP POST GET 本质区别详解< Reprinted>
    Java的反射机制
    简单的KKL诊断线~~~自己在家都可以制作obd诊断接口了 ~~
    URL-编码窗体数据无效
    没有对“C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/Temporary ASP.NET Files”的写访问权限
    ARM中的---汇编指令
    allegro中原理图和pcb中元件的交互
    运算放大器
    电流表接法
    一款单端反激开关电源的设计
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7050561.html
Copyright © 2011-2022 走看看