ApplicationContext VS BeanFactory
ApplicationContext
比
BeanFactory
更为强大,它具备
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:
byName
,
byType
,
constructor
,
autodetect
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
的前提是:
被引用的
bean
的
id
值必须与引用它的
bean
的对应的引用变量名字相同。
例如上例中,
Instrumentalist
class
里的
Saxophone
变量名必须为
instrument
。
Autowire by type
则很容易理解,不需要举例子。唯一要注意的是,
使用
autowiring by type or constructor
的前提是:所指定的
type
必须保证只有一个
bean
定义。
Autowire by constructor
,
Autowire 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;
.....
@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();
}
}
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();
}
}
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();
}
}