1. Spring的依赖注入
Spring的核心是个IoC容器,可以用Setter或建构方法的方式来实现应用程序对象,至于对象与对象之间的关系建立,则可以透过配置文件设定(一个XML文件或是一个.properties文件),让Spring在执行时期根据配置文件的设定,建立对象之间的依赖关系。这样开发人员不必特地编写一些程序来建立这些对象之间的依赖关系,不仅减少了大量的程序编写,也降低了对象之间的耦合程度。
1.1. Bean基本管理
1.1.1.BeanWapper
我们知道,如果动态设置一个对象属性,可以借助Java的Reflection机制完成:
Class cls = Class.forName("com.raykey.beans.User");
Method mtd = cls.getMethod("setName",new Class[]{String.class});
Object obj = (Object)cls.newInstance();
mtd.invoke(obj,new Object[]{"Erica"});
return obj;
|
上面我们通过动态加载了User类,并通过Reflection调用了User.setName方法设置其name属性。对于这里的例子而言,出于简洁,我们将类名和方法名都以常量的方式硬编码。假设这些常量都是通过配置文件读入,那我们就实现了一个最简单的BeanWrapper。这个BeanWrapper的功能很简单,提供一个设置JavaBean属性的通用方法(Apache BeanUtils 类库中提供了大量针对Bean的辅助工具,如果有兴趣可以下载一份源码加以研读)。
Spring BeanWrapper基于同样的原理,提供了一个更加完善的实现。看看如何通过Spring BeanWrapper操作一个JavaBean:
Object obj = Class.forName("com.raykey.beans.User").newInstance();
BeanWrapper bw = new BeanWrapperImpl(obj);
bw.setPropertyValue("name", "Erica");
System.out.println("User name=>"+bw.getPropertyValue("name"));
|
对比之前的代码,很容易知道BeanWrapper的实现原理。
通过这样的方式设定Java Bean属性虽然繁琐,但它却提供了一个通用的属性设定机制,而这样的机制,也正是Spring依赖注入机制所依赖的基础。通过BeanWrapper,我们可以无需在编码时就指定JavaBean的实现类和属性值,通过在配置文件加以设定,就可以在运行期动态创建对象并设定其属性(依赖关系)。
1.1.2.BeanFactory
Bean Factory,顾名思义,负责创建并维护Bean实例。BeanFactory负责读取Bean定义文件,管理对象的加载、生成,维护Bean对象与Bean对象之间的依赖关系。负责Bean的生命周期,对于简单的应用程序来说,BeanFactory已经足够管理Bean,在对象的管理上就可以获得许多的便利性。
Bean Factory负责根据配置文件创建Bean实例,可以配置的项目有:
1. Bean属性值及依赖关系(对其他Bean的引用)
2. Bean创建模式(是否Singleton模式,即是否只针对指定类维持全局唯一的实例)
3. Bean初始化和销毁方法
4. Bean的依赖关系
下面是一个较为完整的Bean配置示例:
<beans>
<description>Spring Bean Configuration Sample</description>
<bean id="TheAction" ⑴
class="com.raykey.spring.qs.UpperAction" ⑵
singleton="true" ⑶
init-method="init" ⑷
destroy-method="cleanup" ⑸
depends-on="ActionManager" ⑹
>
<property name="message">
<value>HeLLo</value> ⑺
</property>
<property name="desc">
<null/>
</property>
<property name="dataSource">
<ref local="dataSource"/> ⑻
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/sample</value>
</property>
</bean>
</beans>
|
⑴ id
Java Bean在BeanFactory中的唯一标识,代码中通过BeanFactory获取JavaBean实例时需以此作为索引名称。
⑵ class
Java Bean 类名
⑶ singleton
指定此Java Bean是否采用单例(Singleton)模式,如果设为“true”,则在BeanFactory作用范围内,只维护此Java Bean的一个实例,代码通过BeanFactory获得此Java Bean实例的引用。反之,如果设为“false”,则通过BeanFactory获取此Java Bean实例时,BeanFactory每次都将创建一个新的实例返回。
⑷ init-method
初始化方法,此方法将在BeanFactory创建JavaBean实例之后,在向应用层返回引用之前执行。一般用于一些资源的初始化工作。
⑸ destroy-method
销毁方法。此方法将在BeanFactory销毁的时候执行,一般用于资源释放。
⑹ depends-on
Bean依赖关系。一般情况下无需设定。Spring会根据情况组织各个依赖关系的构建工作(这里示例中的depends-on属性非必须)。只有某些特殊情况下,如JavaBean中的某些静态变量需要进行初始化(这是一种BadSmell,应该在设计上应该避免)。通过depends-on指定其依赖关系可保证在此Bean加载之前,首先对depends-on所指定的资源进行加载。
⑺ <value>
通过<value/>节点可指定属性值。BeanFactory将自动根据Java Bean对应的属性类型加以匹配。下面的”desc”属性提供了一个null值的设定示例。注意<value></value>代表一个空字符串,如果需要将属性值设定为null,必须使用<null/>节点。
⑻ <ref>
指定了属性对BeanFactory中其他Bean的引用关系。示例中,TheAction的dataSource属性引用了id为dataSource的Bean。BeanFactory将在运行期创建dataSource bean实例,并将其引用传入TheAction Bean的dataSource属性。
下面的代码演示了如何通过BeanFactory获取Bean实例:
InputStream is = new FileInputStream("bean.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
Action action = (Action) factory.getBean("TheAction");
|
此时我们获得的Action实例,由BeanFactory进行加载,并根据配置文件进行了初始化和属性设定。联合上面关于BeanWrapper的内容,我们可以看到,BeanWrapper实现了针对单个Bean的属性设定操作。而BeanFactory则是针对多个Bean的管理容器,根据给定的配置文件,BeanFactory从中读取类名、属性名/值,然后通过Reflection机制进行Bean加载和属性设定。
1.1.3.ApplicationContext
BeanFactory提供了针对Java Bean的管理功能,而ApplicationContext提供了一个更为框架化的实现(从上面的示例中可以看出,BeanFactory的使用方式更加类似一个API,而非Framework style)。ApplicationContext覆盖了BeanFactory的所有功能,并提供了更多的特性。此外,ApplicationContext为与现有应用框架相整合,提供了更为开放式的实现(如对于Web应用,我们可以在web.xml中对ApplicationContext进行配置)。
相对BeanFactory而言,ApplicationContext提供了以下扩展功能:
1. 资源访问
提供取得资源文件更方便的方法,支持对文件和URL的访问。
2. 消息解析
提供文字消息解析的方法。
3. 国际化支持
我们可以在Beans.xml文件中,对程序中的语言信息(如提示信息)进行定义,将程序中的提示信息抽取到配置文件中加以定义,为我们进行应用的各语言版本转换提供了极大的灵活性。
4. 事件的监听与传播
事件传播特性为系统中状态改变时的检测提供了良好支持。ApplicationContext可以发布事件,对事件感兴趣的Bean可以接收到这些事件。
5. 多实例加载
可以在同一个应用中加载多个Context实例。
|
针对以上的扩展功能,将在2.3,2.4,2.5节介绍。
Spring的创始者Rod Johnson建议用ApplicationContext来取代BeanFactory,在实现ApplicationContext的类中,最常使用的大概是以下三个:
org.springframework.context.support.FileSystemXmlApplicationContext可指定XML定义文件的相对路径或绝对路径来读取定义文件。
org.springframework.context.support.ClassPathXmlApplicationContext从Xlasspath设定路径中来读取XML定义文件。
org.springframework.context.support.XmlWebApplicationContext在Web应用程序的文件架构中,指定相对位置来读取定义文件。
在我们最开始的spring的程序示例中我们用的就是ApplicationContext,并用XML定义文件的相对路径读取了定义文件。
public void testQuickStart() {
ApplicationContext ctx=new FileSystemXmlApplicationContext("bean.xml");
Action action = (Action) ctx.getBean("TheAction");
System.out.println(action.execute("Rod Johnson"));
}
|
1.1.4.构造子注入
在上面的spring示例程序中,用的都是Bean的Setter方法完成依赖注入,Spring鼓励的也是Setter Injection,但它也允许Constructor injection,使用哪种注入方法视需求而定,以下示例如何在Spring中使用构造子注入。
参考Type3Demo项目,在定义HelloBean类时,为了要能让Spring可以有使用无参数构造方法来生成对象的弹性,建议可以定义一个无参数的构造方法,即使目前没有编写任何的实现内容。
在Beans-config.xml定义文件中使用构造子注入时,在设定上必须指定构造方法上参数的顺序。使用<constructor-arg>标签来表示将要使用构造子注入。
运行主程序将得到和设值注入同样的效果。
使用设值注入和构造子注入各有好处,在前面已经比较过了,但如果想要让一些数据成员或资源变为只读或是私有,使用构造子注入会是个简单的选择。
1.1.5.自动绑定
除了在Bean定义文件中直接使用指定字符串值、使用<ref>直接指定参考至其它的Bean实例、或是使用<bean>标签并指定class属性来指定依赖对象之外,Spring也支持隐式的自动绑定,可以透过类型(byType)或名称(byName)将某个Bean实例绑定至其它Bean对象的属性。
HelloBean
publicclass HelloBean {
private String helloWord;
private Date date;
publicvoid setHelloWord(String helloWord) {
this.helloWord = helloWord;
}
public String getHelloWord() {
returnhelloWord;
}
publicvoid setDate(Date date) {
this.date = date;
}
public Date getDate() {
returndate;
}
}
|
Beans-config.xml
<beans>
<bean id="dateBean" class="java.util.Date"/>
<bean id="helloBean"
class="onlyfun.caterpillar.HelloBean"
autowire="byType">
<property name="helloWord">
<value>Hello!</value>
</property>
</bean>
</beans>
|
在上边的定义文件中,并没有指定helloBean的Date属性,而是通过byType自动绑定,根据helloBean的setDate()方法所接受的类型,来判断在Bean定义文件中是否定义有类似的类型对象,并将之设定给helloBean的setDate(),使用自动绑定时,如果无法完成绑定,则抛出org.springframework.beans.factory.unstatisfied-DependencyException异常。
如果通过byName绑定,我们的beans-config.xml文件应该如下所示:
<beans>
<bean id="date"class="java.util.Date"/>
<bean id="helloBean"
class="onlyfun.caterpillar.HelloBean"
autowire="byName">
<property name="helloWord">
<value>Hello!</value>
</property>
</bean>
</beans>
|
第一个Bean的id必须为”date”名称,如果byName无法完成自动绑定,则对应的Setter仅维持未绑定状态。
另外autowire也可以采取”constructor”或”autodetect”,它们的含义请自行查阅资料。
1.1.6.集合对象注入
对于像数组、java.util.List、java.util.Set、java.util.Map等集合对象,在注入前若必须填充入一些对象至集合中,然后再将集合对象注入至所需的Bean时,也可以交由Spring的IoC容器来自动维护或生成集合对象,并完成依赖注入。
参考CollectionDemo项目,在SomeBean类中只是简单的定义一些数组、List与Map属性,稍后这些属性所需的依赖对象将由Spring来注入,在SomeBean类中还使用到Some类。
SomeBean:
publicclass SomeBean {
private String[] someStrArray;
private Some[] someObjArray;
private List someList;
private Map someMap;
//getter and setter
}
|
Some:
publicclass Some {
private String name;
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
public String toString() {
returnname;
}
}
|
对于数组或List类型的依赖关系注入,在编写定义文件时是使用<list>标签,并使用<value>标签指定字符串,或是使用<ref>来参考至其它的Bean实例;对于Map类型的依赖关系注入则是使用<map>标签,map必须指定key-value,所以要用<entry>标签指定key,然后使用<value>标签来指定字符串,或是使用<ref>来参考至其它的Bean实例。
Beans-config.xml:
xml 代码
- <beans>
- ......
- <bean id="someBean" class="onlyfun.caterpillar.SomeBean">
- <property name="someStrArray">
- <list>
- <value>Hello</value>
- <value>Welcome</value>
- </list>
- </property>
- ......
- <property name="someMap">
- <map>
- <entry key="MapTest">
- <value>Hello!Justin!</value>
- </entry>
- <entry key="someKey1">
- <ref bean="some1"/>
- </entry>
- </map>
- </property>
- </bean>
- ......
- </beans>
运行测试程序可以验证文件编写是否正确。
如果使用java.util.Set类型的话,可以使用<set>标签:
xml 代码
- <property name="someMap">
- <set>
- <value>ListTest</value>
- <ref bean="some1"/>
- <ref bean="some2"/>
- </set>
- </proper
分享到:
- 2006-11-23 16:10
- 浏览 4715
- 评论(1)
- 论坛回复 / 浏览 (1 / 3976)
- 查看更多
相关推荐
Spring框架是Java开发中不可或缺的一部分,它以其强大的依赖注入(IOC)和面向切面编程(AOP)功能闻名。在本示例中,我们将深入理解这两个核心概念。 **依赖注入(IOC)** 依赖注入(Inversion of Control)是...
4. **Spring框架的应用**:Spring作为实现IoC和AOP的常用工具,会详细讲解如何配置和使用Spring容器。 5. **重构过程**:分享重构从旧版CurrencyExchange到使用IoC和AOP的新版CurrencyExchange2的具体步骤和考虑因素...
Spring框架是Java开发中最常用的轻量级框架之一,它的核心特性包括依赖注入(Dependency Injection,简称DI)和面向切面编程(Aspect-Oriented Programming,简称AOP)。这两个概念是Spring框架的基石,极大地简化了...
Spring核心IoC和AOP的理解 本文主要介绍了Spring核心IoC和AOP的相关知识,涵盖了IoC和AOP的概念、特点、优点和应用场景等方面的内容。...Spring框架的 IoC和AOP机制使得程序更加灵活、更加易于维护和扩展。
Spring框架是Java开发中不可或缺的一部分,它以其强大的依赖注入(IOC)和面向切面编程(AOP)功能而闻名。本项目"spring ioc和aop讲解项目demo"旨在通过实际操作来帮助开发者深入理解这两个核心概念。 首先,让...
在“spring-1”、“spring-2”和“spring-3”这三个文件中,很可能是包含了一系列关于Spring框架使用、IOC和AOP实践的示例代码。这些代码可能涵盖了如何定义bean、如何进行依赖注入、如何声明切面以及如何在实际项目...
Spring框架是Java开发中不可或缺的一部分,它以依赖注入(DI)和控制反转(IOC)为核心,简化了企业级应用的开发。AOP(面向切面编程)和MVC(模型-视图-控制器)模式是Spring框架的重要组成部分,用于处理业务逻辑...
Spring框架是Java开发中不可或缺的一部分,它以IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)为核心,极大地简化了企业级应用的开发工作。本篇将深入探讨Spring的这两...
Spring 是一种轻量级、非侵入式的java / java EE应用框架 Spring是分层的Java SE/EE应用一站式的轻量级开源框架 以IOC和AOP为核心 提供了表示层的MVC解决方案 提供了持久层JDBC的封装
Spring.NET是一个开源的.NET框架,它为.NET开发者提供了与Java Spring框架类似的功能,包括依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)。在这个"spring net IOC+AOP ...
本压缩包"helloAop.zip"包含了Spring框架的两个关键特性:IOC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)的示例。下面将详细介绍这两个概念及其在实际开发中的应用。 *...
在IT领域,Spring框架是Java开发中的核心工具,它提供了许多功能来简化应用程序的构建,如依赖注入(IOC)、面向切面编程(AOP)以及服务整合。本资源包聚焦于Spring的这些关键特性,同时也涉及到CXF服务、任务调度...
Spring框架是Java开发中不可或缺的一部分,它通过提供Inversion of Control (IOC)和Aspect-Oriented Programming (AOP)两大核心特性,极大地简化了企业级应用的开发工作。本资源包含Spring IOC和AOP的实现代码,使得...
该源码是课程 Java Spring案例精讲 ---- Spring框架 的源码,包含Java Spring的最简单的Hello World、IOC、AOP及Log的源码 Spring整体框架中的核心功能,例如:IOC、AOP、Bean生命周期、上下文、作用域、资源处理等...
在Spring框架中,IOC(Inversion of Control,控制反转)是其核心概念之一,它改变了传统应用程序中的对象创建和管理方式。本学习资料主要聚焦于Spring的IOC容器,特别是从最基本的BeanFactory开始,逐步深入理解...
Spring框架是Java开发中的核心组件,它为应用程序提供了一个轻量级的容器,负责管理和装配对象,以及提供各种服务。本教程围绕“Spring教程:IOC(控制反转)和AOP(面向切面编程)”展开,同时涵盖了与Hibernate的...
Spring框架是Java开发中不可或缺的一部分,它通过IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)两大核心特性,极大地简化了应用程序的构建和维护。在这个名为"spring ...
自学自用的Spring框架学习路径,从IOC、AOP、SSM整合到事务管理,内容丰富。注:整合SpringMVC需要配合上传的SpringMVC思维导图一起学习