《spring 2.0 in action》点滴 (Chapter 02)

来源:互联网 发布:考勤机表格修改数据 编辑:程序博客网 时间:2024/04/30 06:06
 
ApplicationContext VS BeanFactory
 
ApplicationContextBeanFactory更为强大,它具备BeanFactory的所有功能,另外还提供一些BeanFactory没有的功能:
 
l       support I18N
l       provide a way to load file resource, such as image
l       publish events to beans which are registered as listener
 
因此,在几乎所有情况下,都是选用ApplicationContext
 
 
 
inner beans
 
我们都熟悉什么是JAVA的inner class —— 定义在另一个class内的class就叫inner class。Inner bean则与其类似。下列代码就是定义了一个inner bean:
 
<bean id="kenny"
class="com.springinaction.springidol.Instrumentalist">
<property name="song" value="Jingle Bells" />
<property name="instrument">
<bean class="org.springinaction.springidol.Saxophone" />
    </property>
</bean>
 
使用inner beans的一个最主要的缺陷在于:不能被reuse。Inner bean are only useful for injection once and can’t be referred to by other beans.
 
 
Autowire
在一个大的project里,如果所有bean对bean的引用(ref)都要进行显式的定义,那么就会导致你的configure xml file会很大也很难维护。Spring提供了自动引用(autowire)功能来解决这个问题,方法是在<bean> elelement里添加autowire属性
 
Spring提供了4种类型的autowire: byNamebyTypeconstructorautodetect
 
Autowire by name例子:
 
针对显式的:
<bean id="instrument" class="com.springinaction.springidol.Saxophone" />
 
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist">
    <property name="song" value="Jingle Bells" />
    <property name="instrument" ref="saxophone" />
</bean>
 
 
使用autowire by name:
<bean id="instrument" class="com.springinaction.springidol.Saxophone" />
 
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist"
         autowire="byName">
    <property name="song" value="Jingle Bells" />
</bean>
 
使用autowiring by name的前提是:被引用的beanid值必须与引用它的bean的对应的引用变量名字相同。例如上例中,Instrumentalist class里的Saxophone变量名必须为instrument
 
Autowire by type则很容易理解,不需要举例子。唯一要注意的是,使用autowiring by type or constructor的前提是:所指定的type必须保证只有一个bean定义
 
Autowire by constructorAutowire by autodetect则不常用到,用到再说吧。
 
缺省情况下,bean是不会autowire的,除非你对某个bean设置了autowire属性。当然,你也可以设置在缺省情况下所有bean都是autowire的,这就要在root element <beans>里设置“default-autowire”属性
 
<beans default-autowire="byName">
</beans>
 
You can also use annotation for autowire:
public class AnnotatedTarget {
   @Autowired
   private Foo foo;
   @Autowired
   private Bar bar;
    .....
}
 
 
使用autowire会有一些缺陷的,如autowire使得你的bean configure不够清晰等等。还有上述的前提问题。因此你要权衡是否使用autowire,建议不要使用
 
 
Initializing and destroying beans
<bean id="kenny"
    class="com.springinaction.springidol.Instrumentalist"
         init-method="tuneInstrument"
         destroy-method="cleanInstrument">
        <property name="song" value="Jingle Bells" />
        <property name="instrument" ref="saxophone" />
</bean>
 
注意init-method方法是在setter DI都完成之后才调用。如上述代码,是在注入了song and instrument之后才调用tuneInstrument方法。
 
Defaulting init-method and destroy-method
如果你的APP有许多的bean都使用同名的initialization or destroy方法,那么你不需要为每个bean逐个逐个的声明属性init-method or destroymethod。只需要在<beans> root element上设置defaultinit-method and default-destroy-method属性:
 
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
         default-init-method="tuneInstrument"
         default-destroy-method="cleanInstrument">
</beans>
 
 
InitializingBean and DisposableBean
另外一个能够替代init-method and destroy-method作用的方法是:让bean class实现两个special Spring interfaces: Initializing-Bean and DisposableBean.
 
public class Instrumentalist implements Performer,InitializingBean, DisposableBean{
   。。。。
   //InitializingBean method
   public void afterPropertiesSet() throws Exception {
      ....
   }
 
   //DisposableBean method
   public void destroy() {
      ....
   }
}
 
NOTE:
destruction callbacks唯一的缺点就是spring并不会自动调用它们,你必须在你的application close之前call destroySingletons()方法来调用它们。
 
如果是web app,你可以simply call destroySingletons() in the servlet’s destroy() method。
 
而如果是stand-alone application,你需要create a shutdown hook来call destroySingletons() method, a thread that is executed just before the application shuts down. 然后把这个shutdown hook加到java runtime的shutdown hooks里
 
public class ShutdownHook implements Runnable {
   private ConfigurableListableBeanFactory beanFactory;
   public ShutdownHook(ConfigurableListableBeanFactory beanFactory) {
        Assert.notNull(beanFactory, "The 'beanFactory' argument must not be null.");
         this.beanFactory = beanFactory;
   }
   public void run() {
      this.beanFactory.destroySingletons();
   }
}
 
public class ShutdownHookDemo {
    public static void main(String[] args) throws IOException {
          XmlBeanFactory factory = new XmlBeanFactory(
                new ClassPathResource("/META-INF/spring/lifecycledemo5-context.xml"));
          Runtime.getRuntime().addShutdownHook(new Thread(new ShutdownHook(factory)));
          new BufferedInputStream(System.in).read();
    }
}