spring是在Java中应用最广泛的IOC框架。spring的兴起源于控制反转的思想(或DI,依赖注入),传统的软件开发就像造房子,一层一层的累加上去;而控制反转的思想就像造汽车,先制造部件,然后组装起来,让各个部件一起工作。因此使用IOC的方法进行软件开发可以获得更大的灵活性,可以在任何时候把部件拆开并重新组装。当然IOC并非全都是优点,制造并组装很自然的会增加组装的开销,当部件粒度太小,组装非常繁琐的时候,IOC还是会让人头疼,部件粒度还是把握好为宜。
IOC中的部件,在Java中就是bean,bean就是class,spring实际上是创造并组装object的对象工厂,那么这个对象工厂是怎么实现控制反转的呢?这其间还有一个很重要的角色——接口。在没有IOC的情况下,如果classA依赖于classB(或是classB的接口)中的方法,那么程序自然会要求ClassA在调用ClassB中的方法之前对ClassB进行实例化,在classA中用classB的构造方法实例化classB的对象,就导致了classA在代码上依赖于classB,这是常见的类型依赖。在使用IOC的情况下,ClassA依赖于classB的接口,而接口的实例化工作并不是由classA来完成,而是由对象工厂来进行classB的实例化,这样classA与classB都依赖于对象工厂,而classA与classB之间就不存在依赖关系,然后把classA、classB与对象工厂之间的依赖关系可配置化,这样就实现了分解依赖的目的。
下面就开始对spring的基本配置做简单说明。首先当然是下载最新版本的spring框架,官网地址http://www.springsource.org/,本配置说明基于spring2.0版本。从该版本开始spring框架被分解为一个核心包spring.jar和众多的插件扩展包,可以根据需要引用所需要的jar包。
示例程序包含接口MyBean、UseBean和实现类MyBeanImpl和UseBeanImpl,此外还有一个测试类型UseBeanTest,其中UseBeanImpl依赖于接口MyBean,主要代码如下:
MyBean:
1: package com.test.bean;
2:
3: public interface MyBean {
4: public String sayHello();
5: }
MyBeanImpl:----------
1: package com.test.bean.impl;
2:
3: import com.test.bean.MyBean;
4: public class MyBeanImpl implements MyBean {
5: /**
6: * 实现sayHello方法
7: * @return
8: */
9: public String sayHello(){
10: return "hello world";
11: }
12: }
UseBean---------
1: package com.test.bean;
2:
3: public interface UseBean {
4: public void speak();
5: }
UseBeanImpl---------
1: package com.test.bean.impl;
2:
3: import com.test.bean.MyBean;
4: import com.test.bean.UseBean;
5: public class UseBeanImpl implements UseBean {
6: //依赖接口
7: private MyBean beanTest;
8: /**
9: * 注入属性
10: * @param beanTest
11: */
12: public void setMyBean(MyBean beanTest) {
13: this.beanTest = beanTest;
14: }
15: public void speak(){
16: System.out.print(beanTest.sayHello());
17: }
18: }
接下来就要配置spring的配置文件了,只需要配置bean即可,配置文件可以任意命名,存放在classes目录,方便加载。
1: <?xml version="1.0" encoding="GBK"?>
2: <!-- 指定Spring配置文件的DTD信息 -->
3: <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
4: "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
5: <!-- Spring配置文件的根元素 -->
6: <beans default-autowire="byName">
7: <bean id="myBean" class="com.test.bean.impl.MyBeanImpl"></bean>
8: <bean id="useBean" class="com.test.bean.impl.UseBeanImpl">
9: <property name="myBean" ref="myBean"/>
10: </bean>
11: </beans>
这里配置了两个bean,property用来声明注入属性,由于声明了default-autowire="byName"按名称自动注入属性策略,property也可以省略(需要符合属性名称查找策略)。
然后可以创建一个Junit来测试bean配置与应用:
1: package com.test.unit;
2:
3: import org.junit.Before;
4: import org.junit.Test;
5: import org.springframework.context.ApplicationContext;
6: import org.springframework.context.support.ClassPathXmlApplicationContext;
7: import com.test.bean.UseBean;
8:
9: public class UseBeanTest {
10:
11: ApplicationContext ctx;
12: UseBean useBean;
13:
14: @Before
15: public void setUp() throws Exception {
16: ctx=new ClassPathXmlApplicationContext(new String[]{"beanContext-useBean.xml"});
17: useBean = (UseBean) ctx.getBean("useBean");
18: }
19:
20: @Test
21: public void testUserBean(){
22: useBean.speak();
23: }
24: }
测试代码中是用xml文件初始化ApplicationContext对象,如果是在web中,只需要在web.xml中配置一个spring的侦听器(Listener)即可:
1: <!-- 这里集成Spring框架 -->
2: <context-param>
3: <param-name>contextConfigLocation</param-name>
4: <param-value>/WEB-INF/applicationContext.xml,classpath*:beanContext-*.xml,classpath*:springContext-*.xml</param-value>
5: </context-param>
6: <listener>
7: <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
8: </listener>
9: <!-- 这里的Listener让spring支持scope='session' -->
10: <listener>
11: <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
12: </listener>