Spring的Core模块
Core模块主要的功能是实现了反向控制和依赖注入DI,Bean配置以及加载。Core模块中有Beans,BeanFactory,BeanDefinitions,ApplicationContext等几个重要的概念。
Beans为Spring里的各种对象,一般配置在Spring配置文件中:BeanFactory为创建Beans的Facotory,Spring通过BeanFactory加载各种Beans:BeanDefinition为Bean在配置文件中的定义,一般要定义id与class;ApplicationContext代表配置文件。
Core模块依赖Spring的Core类库。
BeanFactory工厂
是实例化,配置,管理众多Bean的容器,这些Bean类一般是离散的,在Spring中被配置为下相互依赖。BeanFactory根据配置实例化Bean对象,并设置相互的依赖性。
XmlBeanFactory能加载XML格式的配置文件。
实例化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.destroySingletons();
或者使用文件加载流加载任意位置的配置文件,并传递给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”,“applicationContextpart2.xml”});
BeanFactory factory=(BeanFactory)factory.getBean(“service”);
XmlBeanFactory配置格式
一个BeanFactory中配置了多个Bean,在XmlBeanFactory中,配置文件的根节点为< beans>,里面定义了几个< bean>子节点,每个< bean>定义一个Bean,格式如下:
< beans>
< bean id="" class="" >
< bean/>
< bean id="" class="" >
< property name="" value="">< /property>
< property name="" ref="">< /property>
< /bean>
< /beans>
< property/>表示将使用name属性对应的setter方法设置该属性。
配置java Bean
一个BeanDefination定义一个Bean,在Xml中对应一个< bean>标记,Spring通过< bean>配置来实例化Bean,设置Bean的属性,以及设置Bean之间相互的依赖性。
基本配置< bean>
一个< bean>通常需要定义id与class属性,class属性是必须的。如果配置文件中配置了其他Bean中引用了该Bean,则id属性是必须的,Bean则通过id属性相互访问。例如:
< bean id=“exampleBean” class=“example.ExampleBean”>
< /bean>
上面的代码等价于java代码
ExampleBean exampleBean=new ExampleBean();
其中,对象名exampleBean相当于配置中的id属性。
工厂模式factory-method
如果一个Bean不能通过new直接实例化,而是通过工厂类的某个方法创建的,需要把< bean>的class属性配置为工厂类(或者把factory-bean属性配置为工厂类对象),factory-method属性配置为产生实例的方法是:
< bean id=“exampleBean”
class=“examples.MyFactoryBean”
factory-method=“createInstance”/>
< bean id=“exampleBean2”
factory-bean=“myFactoryBean”
factory-method=“createInstance”/>
构造函数< constructor-arg>
如果java bean的构造函数带有参数,需要指定构造函数的参数,< constructor-arg/>指定构造函数参数所用的Bean或者值,多个参数时,用多个< constructor-arg />配置即可。例如:
< bean id=“exampleBean” class=“example.ExampleBean”>
< constructor-arg>< ref bean=“antherExampleBean”/>< /constructor-arg>
< constructor-arg>< ref bean=“yetAntherBean”/>< /constructor-arg>
< constructor-arg>< value>1< value>< /constructor-arg>
< /bean>
每一个< constructor-arg>配置一个参数,参数有先后顺序,顺序要与构造函数相同,< ref bean=“antherExampleBean”/>表示参数名为antherExampleBean的另一个Bean对象,等同于Java代码。
public class ExampleBean{
private AntherBean beanOne;
private YetAntherBean beanTwo;
private int i;
public ExampleBean(
AntherBean antherBean,YetAntherBean yetAntherBean,int i){
this.beanOne=antherBean;
this.beanTwo=yetAntherBean;
this.i=i;
}
}
单态模式singleton
Bean可以定义是否为单态模式,也叫做单例模式,在程序中只有一个实例,有的java对象在程序中只要一个便足够,多了会浪费资源。比如数据源Bean一般是单态模式,Spring默认为单态模式,如果想用非单态模式,需要修改设置属性。
< bean id=“exampleBean” classs=“example.ExampleBean” singleton=“false” />
配置属性<property>
Spring通过Bean的setter方式设置属性,因此,需要由Spring注射的属性一般都具有公共的getter,setter方法。例如下面的配置代码。
< bean id=“dataSource”
class=“org.apache.commons.dbcp.BasicDataSource”
destroy-method=“close”>
< property name=“driverClassName”>
< value>com.mysql.jdbc.Driver< /value>
< /property>
< property name=“url” value=“jdbc:mysql://localhost:3306/mydb”>
< /property>
< property name=“username” value=“root” />
< property name=“defaultAutoCommit” value=“false” />
< property name=“maxActive” value=“100” />
< /bean>
**destroy-method属性配置关闭方法,**如果有配置,在丢弃java对象时会调用该方法,某些数据源,SessionFactory等对象都需要用destroy-method配置关闭方法。< property>配置了String,boolean,int类型的属性,注意各个< property>的写法略有不同,即可以使用value属性,也可以使用< value>子元素,效果是等价的。等同于java代码:
BasicDataSource dataSource=new BasicDataSource();
dataSource,setDriverClassName(“com.mysql.jdbc.Driver”);
dataSource.setUrl(“jdbc:mysql://localhost://3306/mydb”);
dataSource.setUsername(“root”);
dataSource.setDefaultAutoCommit(false);
dateSource.setMaxActive(100);
注意:
< property name=“password”>
< value> < /value>
< /property>
会将password属性设置为““,而不是null。如果设置为null属性。可以使用< null/>:
< property name=“password”>
< null/>
< /property>
或者干脆不设置。
设置对象属性< ref>
Spring配置文件中的Bean之间可以相互引用,引用时用< ref>标签配合Bean的id属性使用, < ref/>既可以用在< property/>属性中,也可以用在< constructor-arg/>构造函数的参数中,还可以用在其他地方。例如:
< bean id=“dao” class=“com.hello.spring.example.DaoImpl”>< /bean>
< bean id=“serviceImpl” class=“com.hello.spring.example.ServiceImpl”>
< property name=“dao”>
< ref bean=“dao” />
< /property>
< /bean>
< ref>的bean属性为目标< bean>的id属性,也可以使用< property>的ref属性,这是一种简写的方法,适用于只有一个值的情况。例如:
< property name=“dao” ref=“dao” > < /property>
或者使用内部配置,类似于java中的匿名类对象,因为内部配置一般不会被其他的Bean引用,因此不需要配置内部Bean的id,例如:
< property name=“dao”>
< bean class=“com.hello.spring.example.DaoImpl”> < /bean>
< /property>
除了使用< ref>的bean属性,还可以使用local,parent,它们与bean属性的作用是一样的。不同的是,local只能使用本配置文件中的bean,而parent只能使用父配置文件中的bean,但是bean没有任何限制。
配置List属性< list>
< list>配置java。util。List类型的属性。List属性中可以配置任意类型的对象,如果为java对象,则使用ref指定,或者使用< bean>定义新实例,如果是普通类型如String,int,double等,直到用字符串即可,< list/>里的元素会按配置的先后顺序。例如:
< property name=“someList”> //设置List类型
< list>
< value>String,Integer,Double,Boolean等类型对象< /value>
< ref bean=“myDataSource”/> //设置java对象
< /list>
< /property>
配置Set属性< set>
< set>配置java。util。Set类型的属性,Set属性中可以配置任意类型对象,如果是java对象,则使用< ref/>指定,或者使用< bean>重新定义实例。如果是普通类型如String,int,double等,直接用字符串即可,例如:
< property name=“someSet”> //设置Set类型
< set>
< value>String,Integer,Double,Boolean等类型对象< /value>
< ref bean=“myDataSource”/>
< /set>
< /property>
配置Map属性< map>
< map>配置Map类型的属性,< entry>配置Map里的元素,key指定索引,value指定值。如果为java对象,则使用ref指定,或者使用< bean>定义新实例。如果key为对象,使用key-ref属性,例如:
< property name=“someMap”>
< map>
< entry key=“yup an entry”>
< value> just some string< /value>
< /entry>
< entry key-ref=“myDataSource”>
< ref bean=“serviceImpl”/> //bean表示是一个对象。
< /entry>
< map>
< /property>
配置Properties属性< props>
使用< props>与< prop>配置Properties属性。< props/>配置一个Properties对象,< prop/>配置一条属性,属性key配置索引。例如:
< property name=“props”>
< props>
< prop key=“url”>http://www.helloweenvsfei.com< /prop>
< prop key=“name”>helloweenvifei< /prop>
< /props>
< property>
等同于java代码:
Properties props=new Properties()
{
{
put(“url”,“http://www.helloweevifei.com”);
put(“name”,“helloweenvifei”);
}
};
bean.setProps(props);
< idref>与< ref>的区别
作用其实是一样的,都是配置java对象的,用法基本也一致,只是< idref>只有bean和local属性,没有parent属性。
例如:
< idref local=“dataSource”/>
Spring加载XML配置文件时,会检查< idref>配置的Bean存在不存在,而< ref>只会在第一次调用时才会检查,换句话说,如果Bean不存在,< idref>能在启动程序的时候就抛出错误,而< ref>只会在运行中抛出错误。
设置destroy-method销毁方法
有的对象在使用完毕后需要执行close方法释放资源,可以使用destroy-method配置。Spring在注销这些资源时会调用destroy-method里配置的方法,例如:
< bean id=“dataSource” class=“org.apache.common.dbcp.BasicDataSource” destroy-method=“close” >
…
< /bean>
设置depends-on依赖对象
Spring会默认按照配置文件里Bean配置的先后顺序实例化Bean。但有时候在实例化A对象之前需要实例化后面的B对象,这时候可以使用depends-on,强制先B对象,例如:
< bean id=“a” class=“example.A” depends-on=“b”>< /bean>
< bean id=“b” class=“example.B”>< /bean>
这时,在实例化A对象时会检查B是否存在,如果不存在,先实例化B对象。
初始化方法init-method
有的对象在实例化后需要执行某些代码,但这些初始代码不能写在构造函数中,这时候可以把初始化代码写在某个方法中,例如init(),返回使用init-method属性,强制Spring执行该方法进行初始化,例如:
< bean id=“c” class=“example.C” init-method=“init”>< /bean>
定义初始化方法
等价于java代码:
C c=new C(); //先实例化对象
c.init(); //后调用初始化方法
属性自动装配autowire
如果每个属性都使用< ref>设置,一个大项目的Spring配置文件会十分庞大,为此Spring提供了自动装配机制,不用配置< ref>而根据某种规则自动配置属性。
配置autowire自动装配
可以通过< bean>的autowire属性自动装配规则,使用autowire后,不需要再用< property name="" value="" />显式的设置该Bean的属性,
依赖关系,Spring会根据反射,自动寻找符合条件的属性,设置到该Bean属性上,如果autowire设置为byType,将会按照属性的类型自动匹配,例如:
< bean id=“d” class=“example.D” autowire=“byType”>< /bean>
autowire取值范围
autowire属性定义的不是需要自动装配的属性名,而是自动装配的规则,一旦配置,所有的属性都将遵循autowire定义的规则,autowire所有的取值以及意义见表
-
no或者default 默认值,不需要装配任何属性,所有的属性都要使用< ref>或者< idref>配置,在大的部署环境中推荐使用默认值,使用< ref>与< idref>显式配置属性会使依赖性更加明确。
-
byName 根据名称自动装配,如果Bean中有名为dataSource的属性,Spring会把id为dataSource的属性设置到该Bean中。
-
byType 根据类型自动装配,如果Bean中有个DataSource类型的属性,Spring会把DataSource类型的Bean设置到该Bean中,注意如果有多个DataSource类型的Bean,会抛出异常。
-
constructor 根据类型自动装配构造函数,如果没有或者有多个类型匹配的Bean,都会抛出异常。
-
autowire 自动探测,如果构造函数带有参数,则同constructor,否则同byType。
如果显示定义了< property>或者< constructor-arg>,会覆盖默认装配,自动装配一般与下面的依赖检查连用。
注意:在大型的部署环境中,Spring不推荐使用自动装配,因为自动装配会隐藏依赖装配的细节,降低可读性与可维护性,并可能带来意想不到的麻烦。依赖检查dependency
有时候某些Bean的属性配置有错误,比如某个属性没有设置,这种错误在程序启动时不会有任何异常,会一直潜伏到Spring调用该Bean时才会被发现,为防止这种情况,Spring会提供依赖检查,在程序启动的时候检查依赖配置,如果有错误,启动时就会抛出异常,以便发现配置错误。
配置dependency依赖检查
依赖检查能够检查属性是否被设置,如果配置了依赖检查,程序启动会进行配置校验,以便及时发现配置错误,通过设置< bean>的dependency-check设置依赖检查规则,例如:
< bean id=" bean" class=“example.Bean” dependency-check=“all” >< /bean>
dependency属性取值范围
dependency属性有多种取值,分别应付不同的情况,但是需要注意,dependency依赖检查时很生硬的,例如设置为object,将会检查所有的java对象属性,只要有一个属性没有设置,就会抛出异常,即某属性明明不需要设置,但是没法避免dependency检查,容易造成“一竿子打死的”现象,dependency取值以及意义见下
-
no或者default 不做任何检查
-
simple 仅检查基本类型,集合属性,如果有属性没有设置,会抛出异常。
-
object 仅检查java对象属性,如果有属性没有设置,会抛出异常。
-
all 检查所有属性,等同于simple与object的并集
Bean的高级特性
Spring程序中,java bean一般与Spring是非耦合的,不会依赖于Spring类库,这也就是Spring的优点,但有时候java bean需要知道自己在Spring框架中的一些属性,Spring提供了一些接口,实例化java bean对象后Spring会调用接口的方法。
-
BeanNameAware接口获取Bean的id
帮助java bean知道自己在配置文件中的id,实现BeanNameAware接口,实现方法名为setBeanName()方法,初始化对象后Spring就会执行该回调方法,将id设置进来,Bean中设置一个编码,接受id名称即可以,例如:
public class WhatTheNameBean 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 BeansException;
}
用法同于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=“example.D” init-method=" afterPropertiesSet">< /bean> -
DisposableBean接口执行销毁方法
实现了接口的java bean对象丢弃的时候调用销毁方法,但使用该接口会与Spring代码发生耦合,因此不推荐使用,DisposableBean接口代码如下:
public interface DisposableBean{
void destroy() throws Exception;
}
Spring推荐使用destroy-method配置,效果等价:
< bean id= “dataSource” class=“org.apache.commons.abcp.BasicDataSource” detroy-method=“close”> < /bean>BeanFactory高级特性
如果java bean实现了BeanFactoryAware接口,就能获取BeanFactory对象,有下面几个方法:
boolean containsBean(String) :判断指定名称的Bean是否存在
Object getBean(String)返回指定名称的Bean,如果没有该Bean,抛出异常
Object getBean(String,Class)返回指定名称的Bean,并转换为指定的类对象,如果没有该Bean,会抛出异常。
boolean isSingleton(String):判断指定名称的Bean是否被配置为singleton,如果没有该Bean,会抛出异常。
String 【】 getAliases(String) 返回指定名称的Bean的别名。
属性覆盖器
对于一些参数,更实用更简单的方法就是使用properties配置,而不是配置在Spring的配置文件中,Spring提供属性替代配置,允许把某些属性配置在properties文件中。
配置PropertyOverrideConfigure属性覆盖器
PropertyOverrideConfigure允许把XML配置里的某些参数配置到properties文件中,这在数据库配置中很常用,配置时需要配置一个PropertyOverrideConfigure对象,指定properties文件的位置,然后把替换的属性用形如${jdbc.url}的字符串替代,例如:
applicationContext.xml
< bean id=“dataSource”
class=“org.apache.commons.dbcp.BasicDataSource”
destroy-method=“close”>
< property name=“driverClassName” 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.PropertyPlaceholderConfigure”>
< property name=“location” value=“classpath:jdbc.properties”/>
< /bean>
提示:PropertyOverrideConfigure对象会到指定名称的properties文件,例如jdbc.properties中,寻找属性名为 ${}变量的配置, ${}中最好不要有空格。
properties配置
具体的数据库配置是写在jdbc.properties里面的,properties中的配置比applicationContext.xml中更便于阅读,修改和维护。代码如下:
jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/training?characterEncoding=UTF-8
jdbc.username=root
jdbc.password=admin
本章小结
Core模块是Spring最核心,最基本的模块,实现加载配置文件,管理,初始化Bean等,Spring配置文件中可以配置各种构造函数,不过最常见的还是使用不带参数的构造函数,Spring的一些配置也可以拿到properties中。