Spring的核心是个lightweitht 的container,他是实现IOC容器、非侵入性(No Intrusive)的框架,并提供AOP概念的实现方式,提供Persistence、transaction的支持,提供MVC Web框架的实现,并对一些常用的企业服务API提供一致的模型封装,是一个全方位的Application Framework。
一、Spring部分术语介绍
No Intrusive:应用程序几乎感觉不到框架的存在,减低应用程序在框架移植时的负担,进一步增加应用程序组件的Reusability。
控制反转(IoC):依赖关系的转移。程序不应依赖实现,而是依赖于接口。
即如果A依赖B,则B拥有控制权。依赖关系的反转即是控制关系的反转,将控制权由实现的一方转移至抽象的一方,藉由让抽象方拥有控制权,可以获得组件的壳重用性。
在例子中,整个控制权从实际的FloppyWriter转移到抽象的IDeviceWriter接口上m而让Business依赖于IDeviceWriter接口,而FloppyWriter和UsbDiskWriter也依赖于IDeviceWriter接口。
依赖注入(Dependency Injection):IoC模式是一个高层的模式概念,实现IoC有两种方式:Dependency Injection和Service Locator,Spring采用的是DI。
保留抽象接口,让组件依赖于抽象接口,当组件要与其他实际的对象发生依赖关系时,通过抽象接口来注入依赖的实际对象。
依赖注入的三种实现方式:Interface Injection、Setter Injection、Constructor Injection。
二、第一个Spring程序。
载入配置文件:
1Resource rs = new ClassPathResource("SpringDemo\\applicationContext.xml");
2BeanFactory factory = new XmlBeanFactory(rs);
ClassPathResource:从系统的类路径中加载,在上述的代码中,目录的层次结构如下图所示:
FileSystemResource:从文件系统加载,比如说自己指定配置文件的全路径
InputStreamResource:从输入流中加载
ServletContextResource:从Servlet 上下文环境中加载
UrlResource:从指定的Url加载
一、Bean、消息、事件
1. BeanFactory、ApplicationContext
BeanFactory负责读取Bean定义文件,管理对象的加载、生成,维护Bean对象与Bean对象之间的依赖关系,负责Bean的生命周期。
ApplicationContext具备如BeanFactory基本的容器管理功能之外,还提供一个应用程序所需的更完整的框架功能,如取得资源文件的更方便的方法,提供文字消息解析的方法,支持国际化消息,事件的发布、处理与传播等。
建议用ApplicationContext替代BeanFactory。在实现ApplicationContext的类中,最常用的是以下三个:
org.springframework.context.support.FileSystemXmlApplicationContext:可指定XML定义文件的相对路径或者绝对路径来读取定义文件。
org.springframework.context.support.ClassPathXmlApplicationContext:从Classpath设定路径中来读取XML定义文件。
2. 使用Constructor Injection
即使使用Constructor Injection,也建议定义一个无参构造方法,以让Spring可以有使用无参构造方法来生成对象的弹性。
在Bean定义文件中,必须指定构造方法上参数的顺序,如下
<bean id="hello" class="SpringDemo.HelloBean">
<constructor-arg index="0" value="codingliyi" />
<constructor-arg index="1" value="Hello" />
</bean>
建议使用Setter构造方法。有时需要隐藏某属性的Setter方法时(如使该属性变为只读或私有),可使用Constructor Injection。
3. 属性绑定
如某个Bean实例只被某个属性参考一次,之那么可以在属性定义时使用Bean标签,并仅需指定其class属性即可。如
1<property name="date">
2 <bean class="java.util.Date"/>
3</property>
Spring也支持隐式的自动绑定。
1<bean id="helloBean" class="SpringDemo.HelloBean" autowire="byType|byName|constructor|autodetect" dependency-check="simple|objects|all|none"/>
若使用byType无法完成绑定,则抛出异常;
若使用byName无法完成绑定,则对应得Setter仅维持未绑定状态;
若使用constructor,Spring容器会试图比较对应容器中的Bean实例类型,及相关构造方法上的参数类型;
若使用autodetect,Spring首先尝试constructor,不行的话再尝试byType。
dependency-check指定依赖检查的方式,默认为none。如进行依赖检查时发现有未完成的伊拉关系,则执行时会跑出异常。
4. 集合类属性的注入。
<property name="list|set">
<list|set>
<value>hello</value>
<ref bean="helloBean"/>
</list|set>
</property>
<property name="map">
<map>
<entry key="name" value="codingliyi" />
<entry key="person">
<ref bean="codingliyi"/>
</entry>
</map>
</property>
<property name="properties">
<props>
<prop key="name">codingliyi</prop>
</props>
</property>
5. Bean的生命周期
使用BeanFactory来生成及管理Bean实例时:
Bean的建立:读取Bean定义文件,生成Bean的实例。
属性注入:执行相关Bean属性的依赖注入。
BeanNameAware的setBeanName():
如Bean实现了BeanNameAware接口,则执行。
BeanFactoryAware的setBeanFactory():
如Bean实现了BeanFactoryAware接口,则执行。
BeanPostProcessors的processBeforeInitialization():
如任何BeanPostProcessors实例与Bean实例关联,则执行。
InitializingBean的afterPropertiesSet()
如Bean实现了InitializingBean接口,则执行。
Bean定义文件中定义的init-method
如定义了init-method,则执行设定的方法名称。
BeanPostProcessors的processAfterInitialization():
如任何BeanPostProcessors实例与Bean实例关联,则执行。
DisposableBean的destory()
如Bean实现了DisposableBean接口,则执行。
Bean定义文件中定义的destory-method
如定义了destory-method,则执行设定的方法名称。
若使用ApplicationContext,在执行setBeanFactory()后,若bean有实现ApplicationContextAware接口,则执行setApplicationContext(),接着再继续执行之后的流程。
6. Bean高级管理
Aware接口
有时为了善用Spring所提供的一些功能,必须让Bean知道Spring容器管理的一些细节,或者让它知道BeanFactory,ApplicationContext的存在。
Spring中提供了一些Aware接口。如BeanNameAware,BeanFactoryAware,ApplicationContextAware。
当Bean实现了上述接口后,在依赖关系设定完成之后,初始化方法之前,Spring容器会注入对应的实例。
(在暑期实习中做的那个Flex项目,需要在Action层使用ApplicationContext得到服务层组件。当时使用的是直接在代码中用new创建。其实现在看来可以实现ApplicationContextAware接口)
BeanPostProcessor接口
1public interface BeanPostProcessor {
2 public Object postProcessAfterInitialization(Object bean, String name)throws BeansException;
3
4 public Object postProcessBeforeInitialization(Object bean, String name)throws BeansException;
5 }
6}
例如将注入的String改为大写,代码如下:
1public Object postProcessBeforeInitialization(Object bean, String name)
2 throws BeansException {
3 Field[] fields = bean.getClass().getDeclaredFields();
4 for(Field field : fields){
5 if(field.getType().equals(String.class)){
6 try {
7 String original = (String)field.get(bean);
8 field.set(bean, original.toUpperCase());
9 } catch (IllegalArgumentException e) {
10 e.printStackTrace();
11 } catch (IllegalAccessException e) {
12 e.printStackTrace();
13 }
14 }
15 }
16 return bean;
17}
7. 资源、消息、事件
ApplicationContext除了具备如BeanFactory基本的容器管理功能之外,并支持更多应用框架的特性,像是资源的取得、消息解析、事件的处理与传播。
资源的取得:ApplicationContext继承了ResourceLoader接口,可使用getResource()方法并指定资源文件的URL来取得一个实现Resource接口的实例。
Resource resource = context.getResource("classpath:admin.properties");
也可以指定其他标准的URL,如file:或http:等。
在Spring应用程序执行期间,ApplicationContext本身就会发布一连串的事件,而所有发布的时间都是抽象类ApplicationEvent的子类。
ApplicationContext会在ApplicationEvent发布时通知实现了ApplicationListener的Bean类实例。
如果打算发布事件通知ApplicationListener的实例,则可使用ApplicationContext的publishEvent()方法。