Core模块主要的功能是实现了反向控制IOC(Inversion of Control)与依赖注入DI(Dependency Injection)、Bean配置以及加载。Core模块中有Beans、BeanFactory、BeanDefinitions、ApplicationContext等几个重要概念。
Beans为Spring里的各种对象,一般要配置在Spring配置文件中:BeanFactory为创建Beans的Factory,Spring通过BeanFactory加载各种Beans;BeanDefinition为Bean在配置文件中的定义,一般要定义id与class:ApplicationContext代表配置文件。
这些类都位于org.springframework.beans和org.springframework.context中。这是Spring最核心的包。Core模块依赖于Spring的Core类库。
BeanFactory工厂
BeanFactory是实例化、配置、管理众多Bean的容器。这些Bean类一般是离散的,但在Spring中被配置为相互依赖。BeanFactory根据配置实例化Bean对象,并设置相互的依赖性。
BeanFactory可用接口org.springframework.beans.factory.BeanFactory表示。BeanFactory有多种实现,最常用的为org.springframework.beans.factory.xml.XmlBeanFactory。XmlBeanFactory能加载XML格式的配置文件。
实例化BeanFactory
在Web程序中用户不需要实例化BeanFactory,Web程序加载的时候会自动实例化BeanFactory,并加载所有的Beans,将各种Bean设置到各个Servlet中、Struts的Action中、或者Hibernate资源中。开发者直接编写Servlet、Action、Hibernate相关的代码即可,无须操作 BeanFactory。
在Java桌面程序中,需要从BeanFactory中获取Bean,因此需要实例化BeanFactory,构造函数的参数为配置文件的路径。例如加载ClassPath下的配置文件可以用ClassPathResource加载,然后传递给XmlBeanFactory构造函数。代码如下:
ClassPathResource res = new ClassPathResource("applicationContext.xml"); // 获取配置资源 XmlBeanFactory factory = new XmlBeanFactory(res); // 获取对象工厂 IService hello = (IService)factory.getBean("service"); // 获取对象 ...// 其他代码略 factory.destorySingletons(); // 销毁对象
参数applicationContext.xml为ClassPath根目录下的文件。applicationContext.xml为Spring默认的配置文件名称,默认存储在ClassPath根目录下。或者使用文件流加载任意位置的配置文件,并传递给XmlBeanFactory构造函数,例如:
InputStream is = new FileInputStream("C:\\ApplicationContext.xml"); // 获取配置资源 XmlBeanFactory factory = new XmlBeanFactory(is); // 获取对象工厂 IService hello = (IService)factory.getBean("service"); // 获取对象
或者用ClassPathXmlApplicationContext加载多个配置文件(多个配置文件以字符串数组形式传入),并传递给XmlBeanFactory构造函数:
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml", "applicationContext-part2.xml"}); // 多个配置 BeanFactory factory = (BeanFactory)appContext; // ApplicationContext继承自BeanFactory接口
XmlBeanFactory配置格式
一个BeanFactory中配置了多个Bean。在XmlBeanFactory中,配置文件的根节点为
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="..." class="..."> ... bean> <bean id="..." class="..."> <property name="..." value="...">property> <property name="..." ref="...">property> bean> beans>
配置Java Bean
一个BeanDefinition定义一个Bean,在XML中对应一个
基本配置
一个
<bean id="exampleBean" class="example.ExampleBean">bean>
上面代码等价于
ExampleBean exampleBean = new ExampleBean();
其中,对象名exampleBean相当于配置中的id属性。
工厂模式factory-method
如果一个Bean不能通过new直接实例化,而是通过工厂类的某个方法建的,可以把class设为工厂类,用factory-method指向创建对象的法:
<bean id="exampleBean" class="example.MyFactoryBean" factory-method="createInstance" /> <bean id="exampleBean2" factory-bean="myFactoryBean" factory-method="createInstance" />
构造函数
如果Bean的构造函数带参数,那就需指定参数,用
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg><ref bean="anotherExampleBean" />constructor-arg> <constructor-arg><ref bean="yetAnotherBean" />constructor-arg> <constructor-arg><value>1value>constructor-arg> bean>
每个
public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public ExampleBean(AnotherBean beanOne, YetAnotherBean beanTwo, int i){ this.beanOne = beanOne; this.beanTwo = beanTwo; this.i = i; } }
单态模式singleton
Bean可以定义为单态模式(Singleton)。即在程序中只有一个实例,像数据源等一般设为单例。Spring默认是单态模式,如果想使用非单例模式(称为Prototype模式),需把singleton属性置为false:
<bean id="exampleBean" class="examples.ExampleBean" singleton="false" />
非单例下,每次请求该Bean,都会生成一个新的对象。
配置属性
Spring通过Bean的setter方法设置属性。因此,需要由Spring注射的属性一般都具有公共的setter,getter方法。例如下面的配置代码:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/spring?characterEncoding=UTF-8" /> <property name="username" value="root" /> <property name="password" value="admin" /> bean>
destroy-method属性配置关闭方法。在销毁对象时会调用该方法。
注意:
<property name="password"><value>value>property> <property name="password"><null />property>
使用ref标签配置Bean的id属性使用。如:
<bean id="dao" class="com.helloweenvsfei.forum.dao.impl.DaoImpl"> <property name="sessionFactory" ref="sessionFactory">property> bean> <bean class="com.helloweenvsfei.forum.service.impl.ThreadServiceImpl"> <property name="dao" ref="dao">property> bean>
ref的内容为引用的Bean的id属性。
也可使用内部配置(或者内联配置),类似于JAVA中的匿名类对象。因为内部配置一般不会被其他的Bean引用,因此不需要配置内部Bean的id。例如:
class="example.DaoImpl">
配置List属性
配置java.util.List类型的属性。list属性中可配置任意类型对象,如果为java对象,使用ref指定,或者
中的元素会按配置的先后顺序排序,例如:
<property name="someList"> <list> <value>String,Integer,Double,Boolean等类型对象value> <ref bean="myDataSource" /> list> property>
配置Set属性
<property name="someSet"> <set> <value>String,Integer,Double,Boolean等类型对象value> <ref bean="myDataSource" /> <set> property>
配置Map属性
<property name="someMap"> <map> <entry key="yup an entry"> <value>just some stringvalue> entry> <entry key-ref="myDataSource"> <ref bean="serviceImpl" /> entry> map> property>
配置Properties属性
使用
<props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialectprop> <prop key="hibernate.show_sql">trueprop> <prop key="hibernate.format_sql">falseprop> <prop key="hibernate.hbm2ddl.auto">createprop> props>
<idref local="dataSource" />
Spring加载XML配置文件时,会检查
设置destory-method销毁方法
有的对象(例如数据源,JDBC连接,输入输出流等)在使用完毕后需要执行close()方法释放资源。可以使用destory-method配置。Spring在注销这些资源时会调用destory-method里配置的方法。例如:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
..... bean>
设置depends-on依赖对象
Spring默认按照配置文件里Bean配置的先后顺序实例化Bean,但有时候在实例化A对象之前需要先实例化后面的B对象。这时候可以使用depends-on,强制先实例化B对象。如:
<bean id="a" class="examples.A" depends-on="b">bean> <bean id="b" class="examples.B">bean>
在实例化A的时候会检查B的实例是否存在,如果不存在,先实例化B
初始化方法init-method
与destory-method相反,有的对象在实例化后需要执行某些初始化代码,但这些初始化代码不能写在构造函数中。这时候可以把这部分初始化代码写在一个方法中,如init(),使用init-method属性,强制Spring执行该方法进行初始化,如:
<bean id="c" class="example.C" init-method="init">bean>
属性自动装配autowire
为了防止配置文件过大,可以使用autowire属性
配置autowire自动装配
使用
<bean id="d" class="examples.D" autowire="byType">bean>
autowire取值范围
autowire属性定义的不是需要自动装配的属性名,而是自动装配的规则。一但配置,所有的属性都将遵循autowire定义的规则。autowire所有的取值以及意义见下表
如果显示定义了
注意:在大型项目中不推荐使用,因为自动装配会隐藏依赖装配的细节。降低可读性与可维护性,并可能带来意想不到的麻烦。
依赖检查dependency
有时候某些Bean的属性配置有错误,比如某个属性没有设置。这种错误在程序启动的时候不会有任何异常表现,会一直潜伏到Spring调用该Bean时才会被发现。为了防止这种情况,Spring提供依赖检查,在程序启动的时候检查依赖配置。如果有错误,启动时就会抛出异常,以便发现配置错误。
配置dependency依赖检查
依赖检查能够检查属性是否被设置。如果配置了依赖检查,程序启动时会进行配置校验,以便及时地发现配置错误。通过设置
<bean id="bean" class="examples.Bean" dependency-check="all">bean>
dependency属性取值范围
dependency属性有多种取值,分别应对不同的情况。但是需要注意,dependency依赖检查是很生硬的,例如设置为object,将会检查所有的java对象属性,只要有一个属性没有设置,就会抛出异常,即某属性明明不需要设置,但是没法避免dependency检查,容易造成“一竿子全打死”的现象。dependency的取值以及意义见表
Bean的高级特性
Spring程序中,JAVA Bean一般与Spring是非耦合的,不会依赖于Spring类库。这也是Spring的优点。但有时候Java Bean需要知道自己在Spring框架中的一些属性。Spring提供了一些接口,实例化Java Bean对象后Spring会调用接口的方法。
BeanNameAware接口获取Bean的id
BeanNameAware接口帮助Java Bean知道自己在配置文件中的id,实现BeanNameAware,实现方法名为setBeanName()方法,初始化该对象后Spring就会执行该回调方法,将id设置进来。Bean中设置一个变量,接受id名称即可,例如:
package com.helloweenvsfei.spring.example; import org.springframework.beans.factory.BeanNameAware; public class WhatsTheNameBean implements BeanNameAware { private String beanName; public void setBeanName(String beanName) { this.beanName = beanName; } }
提示:setBeanName()方法的回调发生在所有参数被设置完之后,初始化方法(init-method属性)被执行之前。
BeanFactoryAware接口获取BeanFactory
BeanFactoryAware接口帮助java Bean知道哪个BeanFactory实例化了自己,BeanFactoryAware接口中有setBeanFactory的回调方法,初始化该对象后,会回调该方法,将BeanFactory传递进来。BeanFactoryAware接口的代码如下:
public interface BeanFactoryAware{ void setBeanFactory(BeanFactory beanFactory) throws BeanException }
用法同BeanNameAware,实现了BeanFactoryAware接口的Java Bean能够获取到BeanFactory,从BeanFactory中能够获取到BeanFactory中配置的其他Java Bean。Spring不推荐这样做,因为这样会与Spring耦合。获取其它Java Bean一般通过设置getter、setter方法,用依赖注入实现
InitializingBean接口执行初始化方法
实现了InitializingBean接口的Java Bean会在实例后、所有属性被设置后调用初始化方法。但使用该接口会与Spring代码发生耦合,因此不推荐使用。InitializingBean接口代码如下:
public interface InitializingBean{ public void afterPropertiesSet(); }
Spring推荐使用init-method配置,效果等价:
<bean id="d" class="examples.D" init-method="afterPropertiesSet">bean>
DisposableBean接口执行销毁方法
实现了DisposableBean接口的Java Bean会在对象丢弃的时候调用销毁方法。但使用该接口会与Spring代码发生耦合,因此不推荐使用。DisposableBean接口代码如下:
public interface DisposableBean{ void destory() throws Exception; }
Spring推荐使用destory-method配置,效果等价:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destory-method="close">bean>
BeanFactory高级特性
如果Java Bean实现了BeanFactoryAware接口,就能够获得BeanFactory对象。BeanFactory有下面几个常用的方法:
属性覆盖器
对于一些参数,更实用更简单的方法是使用properties配置,而不是配置在Spring的配置文件中。Spring提供属性替代配置,允许把某些属性配置在properties文件中。
配置PropertyOverrideConfigurer属性覆盖器
PropertyOverrideConfigurer允许把XML配置里的某些参数配置到properties文件中。这在数据库配置中很常见。配置时需要配置一个PropertyOverrideConfigurer对象,指定properties文件的位置,然后把替换的属性用形如${jdbc.url}的字符串替代,如:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> bean> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties" />
PropertyOverrideConfigurer对象会到指定名称的properties文件(例如jdbc.properties)中,寻找属性名为${}变量的配置,${}中最好不要有空格
properties配置
具体的数据库配置是写在jdbc.properties里面的。properties中的配置比applicationContext.xml中更便于阅读、修改与维护。代码如下:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/forum?characterEncoding=UTF-8
jdbc.username=root
jdbc.password="admin