非xml格式的声明
xmlBeanFactory比较流行的BeanFactory接口实现。
Spring还支持两种bean声明的方式:读取属性文件(资源包)或者编程注册方式。
不管bean声明以怎样的格式存储,Spring的使用者总可以用一种统一的方式去使用beanFactory。它们只需要通过beanFactory和ListableBeanFactory接口来查找bean组件。
如何在程序中获得BeanFactory?在web应用中,将BeanFactory保存在ServletContext中。
自动装配:对象关系无歧义时才能完成自动装配。
一般情况下推荐byType的自动装配方式,因为这不需要精确匹配bean的名称,出错的可能性更小。
声明周期回调
bean工厂除了实例化和装配属性外,一般不需要任何回调方法。这样做的好处便是消除了对Spring的依赖。
某些对象希望在初始化或者销毁时有回调的能力。bean工厂有两种方式可以满足需求:
实现回调接口;在bean组件声明中指定回调方法。
Spring提供了两个回调接口:org.springframework.beans.factory.InitializingBean和org.springframework.beans.factory.DisposableBean 。提供了无参的回调方法,可以在属性设置完成之后以及bean工厂销毁之前,发送消息给应用对象。
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
在JavaBean的所有属性设置完成之后,容器会调用afterPropertiesSet方法,应用对象可以在这里执行任何定制的初始化操作。抛出Exception异常,目的简化编程模型。如果在这个声明周期抛出异常,表明在构建的时候就发生了严重的错误,强迫开发人员捕获这个异常没有什么意义。所以Spring会记入日志,不做额外的处理。
在接口上声明Exception是不好的做法。Spring只在回调接口上这么处理。
public interface DisposableBean {
void destroy() throws Exception;
}一些资源服务被垃圾回收,使用这个接口。
还有一种方法,在bean声明中指定回调方法。
另外一个回调方法可用于访问bean组件所在的Bean工厂。只要实现org.springframework.beans.factory.BeanFactoryAware接口,在bean组件完成初始化之后,它的setBeanFactory就会被调用。得到beanFactory的引用。如果bean实现了InitializingBean ,对setBeanFactory的调用会在afterPropertiesSet之前,声明的回调方法也是如此。
public interface BeanFactoryAware {
/**
* Callback that supplies the owning factory to a bean instance.
* <p>Invoked after population of normal bean properties but before an init
* callback like InitializingBean's afterPropertiesSet or a custom init-method.
* @param beanFactory owning BeanFactory (may not be <code>null</code>).
* The bean can immediately call methods on the factory.
* @throws BeansException in case of initialization errors
* @see BeanInitializationException
*/
void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
通常这种方法适用于Spring框架内部的类,应用程序不怎么适合。有时候,应用代码需要在运行时获得自身beanFactory的引用,从而得到其他bean的引用。或者获取prototype形式bean组件的多个实例。
资源设置
除了彼此关联的应用对象之外,几乎所有的应用程序都需要操作资源,例如jdbc DataSource 或者Hibernate SessionFactory。
bean容器中的资源声明
Spring帮助我们避免硬编码只适应于特定环境的资源查找代码。通常,通过JavaBean属性为应用对象提供标准的资源(如连接工厂),而不是由应用对象自己来查找。
Ioc应用于资源:应用对象不需要通过特定的机制来查找资源,只需要依赖由外部提供的连接工厂。
<!-- 生产库数据源-->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>ZFBDataSource</value>
</property>
</bean>
org.springframework.jdbc.datasource.DriverManagerDataSource是一个javax.sql.DataSource的实现
尽可能将查找资源的代码从应用代码中移除。
工厂bean(注意和bean工厂有区别)
工厂bean,实现了org.springframework.beans.factory.FactoryBean这个接口,一个工厂bean引入了一个间接层,既是一个bean工厂中定义的bean,又是创建另外一个bean的工厂。当一个bean在声明中引用一个工厂bean、或者调用bean工厂的getBean()方法获得一个工厂bean时,它们得到的实际上是工厂bean所创建的那个对象。
工厂bean主要在Spring内部使用。应用程序比较少这样做,通常只需要使用Spring内建的资源工厂,包括:
org.springframework.jndi.JndiObjectFactoryBean:通用的工厂bean,通过jndi查找来获得对象。
其他等等。。。。。
工厂bean有两个非常重要的用途:获取JNDI资源,声明本地连接工厂。
Spring框架还借助工厂bean生成AOP代理、访问远程服务。
<!-- 生产库数据源-->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>ZFBDataSource</value>
</property>
</bean>
被其他bean应用时,工厂bean被当成datasource使用,这个datasource是由工厂bean创建的
注意:虽然dataSource被声明为JndiObjectFactoryBean类型,但是调用bean工厂的getBean()方法将得到的是一个DataSource实例。
创建本地连接工厂
org.springframework.orm.hibernate.LocalSessionFactoryBean可以根据配置来创建一个hibernate连接工厂,并将其注册在bean工厂中。
这个工厂bean可以在现有的DataSource基础上建立SessionFactory,不一定由Hibernate来管理链接。
使用时,一般会让Hibernate使用现有的DataSource bean,并在bean工厂中配置指定所有的映射文件和属性。
Spring应用上下文
应用上下文支持beanfactory的全部,还支持其他的东东。
应用上下文的核心接口是org.springframework.context.ApplicationContext,它继承了org.springframework.beans.factory.ListableBeanFactory。所以可以把ApplicationContext当成是beanFactory使用。
应用上下文是应用程序的中心注册机构。应用上下文允许嵌套:从根上下文开始,可以建立一个应用上下文树。
org.springframework.web.context.WebApplicationContext继承了org.springframework.context.ApplicationContext,是web环境的应用上下文。提供了一个方法获得当前的ServletContext。一般ServletContext提供的功能在ApplicationContext接口中几乎都已经以更为通用的方式提供了。一般来说,最好不要依赖servlet环境;应该尽量使用Spring的抽象,因为这样就不会依赖任何环境。
如果bean组件想要得到自己所在的应用上下文,可以实现org.springframework.context.ApplicationContextAware接口。在初始化的时候,回调方法setApplicationContext会得到一个applicationContext的引用。如果bean同时实现了beanFactoryAware接口,那么会先调用setBeanFactory,然后在调用setApplicationContext。
spring框架中很多实现了ApplicationContextAware,应用程序很少需要这么做。这么做一般有两个目的:访问信息资源以及访问文件信息。
一个非常重要的回调接口:
org.springframework.web.context.ServletContextAware;可以得到servletContext的引用
信息源
除了BeanFactory接口以外,ApplicationContext还继承了org.springframework.context.MessageSource接口。这个接口提供了多个用户获取信息字符串的getMessage()方法,分别可以接收信息代码、信息参数以及默认信息值等参数。
如果一个对象实现了org.springframework.context.MessageSourceResolvable,也可以把它传入getMessage()方法。
MessageSourceResourceBundle对java.util.ResourceBundle进行了封装。
文件资源
应用上下文的一个重要特性就是可以翻个访问文件资源。
BeanFactory 后处理
应用上下文又一项特殊的能力:允许在底层bean工厂读取bean声明后进行后处理。最常见的情况下:bean是组件在xml文件中声明的;可以对它们进行后处理,覆盖某几个属性值,或是为某些属性提供占位值。这样,应用程序就可以把某些需要管理的属性值保存在外部文件中,管理员只要管理这个简单的文件即可,不需要连接应用上下文xml文件活或者是Spring的xml格式。
后处理器可以在应用上下文中像普通的bean一样简单声明,只要实现了org.springframework.beans.factory.config.PropertyResourceConfigurer接口。
当应用上下文启动时,它首先呗调用,因此可以动态改变任何其他bean的声明。
public interface BeanFactoryPostProcessor {
/**
* Modify the application context's internal bean factory after its standard
* initialization. All bean definitions will have been loaded, but no beans
* will have been instantiated yet. This allows for overriding or adding
* properties even to eager-initializing beans.
* @param beanFactory the bean factory used by the application context
* @throws org.springframework.beans.BeansException in case of errors
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
一个实现:org.springframework.beans.factory.config.PropertyOverrideConfigurer,它读取属性文件中beanName.propertyName=value格式的内容,并且覆盖bean属性的值。
另一个后处理器的实现是org.springframework.beans.factory.config.PropertyPlaceholderConfigurer,它可以解析类似于ant风格的占位符。从属性文件中读取属性值填入占位符的位置。
一个类似的机制是bean实例的后处理,这是通过org.springframework.beans.factory.config.BeanPostProcessor接口提供的。bean的后处理器可以用于自动创建AOP代理,切入点可以在当前的应用上下文中声明。