??xml version="1.0" encoding="utf-8" standalone="yes"?>
代码Q?/span>
ApplicationContext
ac = new FileSystemXmlApplicationContex("applicationContext.xml");
ac.getBean("beanId");
说明Q?/span>
q种方式适用于采?/span>Spring框架的独立应用程序,需要程序通过配置文g手工初始?/span>Spring的情c(din)?/span>
Ҏ(gu)二:(x)通过Spring提供的工L(fng)获取ApplicationContext对象
代码Q?/span>
import
org.springframework.web.context.support.WebApplicationContextUtils;
ApplicationContext
ac1 =
WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext
sc)
ApplicationContext ac2 =
WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)
ac1.getBean("beanId");
ac2.getBean("beanId");
说明Q?/span>
q种方式适合于采?/span>Spring框架?/span>B/SpȝQ通过ServletContext对象获取ApplicationContext对象Q然后在通过它获取需要的cd例。上面两个工h式的区别
是,前者在获取p|时抛出异常,后者返?/span>null?/span>
?
?/span>
servletContext sc ?
以具?/span> 换成
servlet.getServletContext()或?/span> this.getServletContext() 或?/span>
request.getSession().getServletContext();
另外Q由?/span>spring是注入的对象攑֜ServletContext中的Q所以可以直接在ServletContext取出WebApplicationContext
对象Q?/span>
WebApplicationContext webApplicationContext =
(WebApplicationContext)
servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
Ҏ(gu)三:(x)l承自抽象类ApplicationObjectSupport
说明Q?/span>
抽象c?/span>ApplicationObjectSupport提供getApplicationContext()Ҏ(gu)Q可以方便的获取?/span>ApplicationContext?/span>Spring初始化时Q会(x)通过该抽象类?/span>setApplicationContext(ApplicationContext
context)Ҏ(gu)?/span>ApplicationContext
对象注入?/span>
Ҏ(gu)四:(x)l承自抽象类WebApplicationObjectSupport
说明Q?/span>
cM上面Ҏ(gu)Q调?/span>getWebApplicationContext()获取WebApplicationContext
Ҏ(gu)五:(x)实现接口ApplicationContextAware
说明Q?/span>
实现该接口的setApplicationContext(ApplicationContext
context)Ҏ(gu)Qƈ保存ApplicationContext
对象?/span>Spring初始化时Q会(x)通过该方法将ApplicationContext
对象注入?/span>
以上Ҏ(gu)适合不同的情况,h据具体情况选用相应的方法?/span>
q里值得提一点的是,pȝ中用Cq方法的cd际上׃Spring框架紧密耦合在一起了(jin)Q因些类是知道它们是q行?/span>Spring框架上的Q因此,pȝ中,应该量的减这cd用,使系l尽可能
的独立于当前q行环境Q尽量通过DI的方式获取需要的服务提供者?/span>
?
后在Action?
~写如下代码得到ContextQ(我是覆盖?/span>Struts Action?/span>setServletҎ(gu)Q也许还有更好的Ҏ(gu)Q?/span>
public void setServlet(ActionServlet servlet){
super.setServlet(servlet);
ServletContext servletContext =
servlet.getServletContext();
WebApplicationContext
wac =
WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
// get yours beans
}
我需要在spring?/span>bean中直接获取,q下可和我们常规的操作有些不同,因ؓ(f)spring?/span>bean都是pojo的。根本见不着servletconfig?/span>servletcontext的媄(jing)子?/span>
q里?
需要指?/span>springl?
我们提供?jin)两个接口?x)org.springframework.web.context.ServletContextAware?/span>
org.springframework.web.context.ServletConfigAware。我们可以让我们?/span>bean实现上边的Q何一个接口就能获取到servletContext?/span> .
代码如下Q?/span>
如图 1 所C?/p>
?1. Spring 框架?7 个模?/strong>
l成 Spring 框架的每个模块(或组Ӟ(j)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下Q?
BeanFactory
Q它是工厂模式的实现?code>BeanFactory 使用控制反{ QIOCQ?模式应用程序的配置和依赖性规范与实际的应用程序代码分开?
Spring 框架的功能可以用在Q?J2EE 服务器中Q大多数功能也适用于不受管理的环境。Spring 的核?j)要?gu)Q支持不l定到特?J2EE 服务的可重用业务和数据访问对象。毫无疑问,q样的对象可以在不同 J2EE 环境 QWeb ?EJBQ、独立应用程序、测试环境之间重用?
![]() ![]() |
控制反{模式Q也UC依赖性介入)(j)的基本概忉|Q不创徏对象Q但是描q创建它们的方式。在代码中不直接与对象和服务q接Q但在配|文件中描述哪一个组仉要哪一Ҏ(gu)务。容?Q在 Spring 框架中是 IOC 容器Q?负责这些联pd一赗?/p>
在典型的 IOC 场景中,容器创徏?jin)所有对象,q设|必要的属性将它们q接在一P军_什么时间调用方法。下表列Z(jin) IOC 的一个实现模式?/p>
cd 1 | 服务需要实C门的接口Q通过接口Q由对象提供q些服务Q可以从对象查询依赖性(例如Q需要的附加服务Q?/td> |
cd 2 | 通过 JavaBean 的属性(例如 setter Ҏ(gu)Q分配依赖?/td> |
cd 3 | 依赖性以构造函数的形式提供Q不?JavaBean 属性的形式公开 |
Spring 框架?IOC 容器采用cd 2 和类? 实现?/p>
面向斚w的编E?/em>Q即 AOPQ是一U编E技术,它允许程序员Ҏ(gu)切关注点或横切典型的职责分界U的行ؓ(f)Q例如日志和事务理Q进行模块化。AOP 的核?j)构造是斚wQ它?yu)那些?jing)响多个类的行为封装到可重用的模块中?/p>
AOP ?IOC 是补充性的技术,它们都运用模块化方式解决企业应用E序开发中的复杂问题。在典型的面向对象开发方式中Q可能要日志记录语句放在所有方法和 Java cM才能实现日志功能。在 AOP 方式中,可以反过来将日志服务模块?/em>Qƈ以声明的方式它们应用到需要日志的lg上。当?dng)优势?Java cM需要知道日志服务的存在Q也不需要考虑相关的代码。所以,?Spring AOP ~写的应用程序代码是松散耦合的?/p>
AOP 的功能完全集成到?Spring 事务理、日志和其他各种Ҏ(gu)的上下文中?/p>
Spring 设计的核?j)? bean 工厂的概忉| Spring 作ؓ(f) IOC 容器的基。IOC 处理事情的责Q从应用程序代码{Ud框架。正如我在下一个示例中演示的那PSpring 框架使用 JavaBean 属性和配置数据来指出必设|的依赖关系?/p>
因ؓ(f) ?XML 文g中定义的 Bean 是被消极加蝲的,q意呛_需?bean 之前Qbean 本n不会(x)被初始化。要? 每个 bean 的定义都可以?POJO Q用cd?JavaBean 初始化属性定义)(j) ? 理解控制反{最单的方式是看它的实际应用。在对由三部分组成的 Spring pd 的第 1 部分q行ȝӞ我用了(jin)一个示例,演示?jin)如何通过 Spring IOC 容器注入应用E序的依赖关p(而不是将它们构徏q来Q?/p>
我用开启在U信用帐L(fng)用例作ؓ(f)L(fng)。对于该实现Q开启信用帐戯求用户与以下服务q行交互Q?
对于q个CZQ我假设服务已经存在Q理想的情况是用松散耦合的方式把它们集成在一赗以下清单显CZ(jin)三个服务的应用程序接口?/p>
清单 3 所C的信用U别评定接口提供?jin)信用历史信息。它需要一个包含客户信息的 信用链接接口信用历史信息与银行信息Q如果需要的话)(j)q接在一Pq插入用L(fng)信用卡信息。信用链接接口是一个远E服务,它的查询是通过 q些接口׃之后Q接下来要考虑的就是如何用松散耦合方式它们集成在一赗在 清单 6 中可以看C用卡帐户用例的实现?/p>
注意Q所有的 setter Ҏ(gu)都是?Spring 的配|?bean 实现的。所有的依赖关系 Q也是三个接口Q都可以?Spring 框架用这?bean 注入?code>createCreditCardAccount() Ҏ(gu)?x)用服务L行其余实现。在 清单 7 中可以看?Spring 的配|文件。我用箭头突Z(jin)q些定义? 要运行示例应用程序,首先必须 下蝲 Spring 框架 ?qing)其所有依赖文件。接下来Q将框架释放刎ͼ比如_(d)(j)盘 c:\Q这?x)创?C:\spring-framework-1.2-rc2 Q适用于当前发行版本)(j) q样的文件夹。在l箋后面的操作之前,q必M载和释放 Apache Ant?/p>
接下来,源代码释放到文件夹Q例?c:\ 盘,然后创徏 SpringProject。将 Spring 库(?C:\spring-framework-1.2-rc2\dist 下的 spring.jar ?C:\spring-framework-1.2-rc2\lib\jakarta-commons 下的 commons-logging.jarQ复制到 SpringProject\lib 文g夹中。完成这些工作之后,有?jin)必需的构Z赖关p集?/p>
打开命o(h)提示W,当前目录切换到 SpringProjectQ在命o(h)提示W中输入以下命o(h)Q?code>build? q会(x)构徏q运? 在这由三部分组成的 Spring pd 的第一文章中Q我介绍?Spring 框架的基。我从讨论组?Spring 分层架构?7 个模块开始,然后深入介绍?jin)其中两个模块?x)Spring AOP ?IOC 容器?/p>
׃学习(fn)的最x法是实践Q所以我用一个工作示例介l了(jin) IOC 模式 Q像 Spring ?IOC 容器实现的那P(j)如何用松散耦合的方式将分散的系l集成在一赗在q个CZ中可以看刎ͼ依赖关pL服务注入工作中的信用卡帐户应用程序,要比从头开始构建它们容易得多?/p>
L(fng)l关注这一pd的下一文章,我将在这里学?fn)的知识基础上,介绍 Spring AOP 模块如何在企业应用程序中提供持久支持Qƈ让?zhn)开始了(jin)?Spring MVC 模块和相x件?
org.springframework.beans
包,它的设计目标是与 JavaBean lg一起用。这个包通常不是qL(fng)接用,而是由服务器其用作其他多数功能的底层中介。下一个最高抽象?BeanFactory
接口Q它是工厂设计模式的实现Q允?dng)R过名称创徏和检索对象?code>BeanFactory 也可以管理对象之间的关系?/p>
BeanFactory
支持两个对象模型?/p>
org.springframework.beans.factory.BeanFactory
是一个简单接口,所以可以针对各U底层存储方法实现。最常用?BeanFactory
定义?XmlBeanFactory
Q它Ҏ(gu) XML 文g中的定义装入 beanQ如清单 1 所C?/p>
清单 1. XmlBeanFactory
BeanFactory factory = new XMLBeanFactory(new FileInputSteam("mybean.xml"));
BeanFactory
(g)?beanQ只需调用 getBean()
Ҏ(gu)Q传入将要检索的 bean 的名U即可,如清?2 所C?/p>
清单 2. getBean()
MyBean mybean = (MyBean) factory.getBean("mybean");
FactoryBean
?code>FactoryBean 接口Z?Spring 框架构徏的应用程序添加了(jin)一个间接的U别?/p>
清单 3. CreditRatingInterface
public interface CreditRatingInterface {
public boolean getUserCreditHistoryInformation(ICustomer iCustomer);
}
Customer
对象。该接口的实现是?CreditRating
cL供的?/p>
清单 4. CreditLinkingInterface
public interface CreditLinkingInterface {
public String getUrl();
public void setUrl(String url);
public void linkCreditBankAccount() throws Exception ;
}
getUrl()
Ҏ(gu)q行的。URL ?Spring 框架?bean 配置机制讄Q我E后?x)讨论它。该接口的实现是?CreditLinking
cL供的?/p>
清单 5. EmailInterface
public interface EmailInterface {
public void sendEmail(ICustomer iCustomer);
public String getFromEmail();
public void setFromEmail(String fromEmail) ;
public String getPassword();
public void setPassword(String password) ;
public String getSmtpHost() ;
public void setSmtpHost(String smtpHost);
public String getUserId() ;
public void setUserId(String userId);
}
EmailInterface
负责向客户发送关于客户信用卡状态的?sh)子邮g。邮仉|参敎ͼ例如 SMPT L、用户名、口令)(j)由前面提到的 bean 配置机制讄?code>Email cL供了(jin)该接口的实现?/p>
CreateCreditAccountClient
c,cȝq行创?Customer
cd象ƈ填充它,q会(x)调用 CreateCreditCardAccount
cd建ƈ链接信用卡帐戗?code>CreateCreditAccountClient q会(x)通过 ClassPathXmlApplicationContext
装入 Spring 配置文g。装?bean 之后Q就可以通过 getBean()
Ҏ(gu)讉K它们?jin),如清?8 所C?/p>
清单 8. 装入 Spring 配置文g
ClassPathXmlApplicationContext appContext =
new ClassPathXmlApplicationContext(new String[] {
"springexample-creditaccount.xml"
});
CreateCreditCardAccountInterface creditCardAccount =
(CreateCreditCardAccountInterface)
appContext.getBean("createCreditCard");
轉載(j)地址:http://www.ibm.com/developerworks/cn/java/wa-spring1/
]]>
本文中的 web.xml ?org.springframework.web.servlet.DispatcherServlet 所处理?url-pattern ?*.htmlQ?br /> 如何搭徏 Spring MVC 目不细加说明,可参考我前面同系列的文章?/p>
例如Q下面的 UserControllerQ有两个{一L(fng) updateUser() ?deleteUser() Ҏ(gu)
public class UserController extends MultiActionController {
public ModelAndView updateUser(HttpServletRequest request,
HttpServletResponse response) {
System.out.println("updateUser");//方便于跟t执行了(jin)哪个Ҏ(gu)
return new ModelAndView("userList","from","updateUser");
}
public ModelAndView deleteUser(HttpServletRequest request,
HttpServletResponse response) {
System.out.println("deleteUser");//方便于跟t执行了(jin)哪个Ҏ(gu)
return new ModelAndView("userList","from","deleteUser");
}
}
用过 Struts ?DispatchAction 的都知道Q是通过 http://.../userAction.do?method=updateUser 的方式来指定执行哪个Ҏ(gu)?br /> ?Spring MVC中是如何定位到所需Ҏ(gu)上呢Q?/p>
Spring MVC 除了(jin)有一个叫?HandlerMapping(?URL 解析?Controller) 的东西,q要把操作进一步解析到Ҏ(gu)名上Q?br /> 卌扑ֈ?Controller 上的哪个Ҏ(gu)q执行之。缺省的Ҏ(gu)名解析器?InternalPathMethodNameResolverQ它Ҏ(gu) URL 样式解析Ҏ(gu)名?/p>
在缺省的 BeanNameUrlHandlerMapping 和缺省的 InternalPathMethodNameResolver 协调之下QBean 上下文可以这样配|:(x)
<bean name="/updateUser.html" class="com.unmi.UserController"/>
<bean name="/deleteUser.html" class="com.unmi.UserController"/>
q样分别通过下面?URL p执行到正的Ҏ(gu)上去?jin)?x)
http://.../updateUser.html -- 被 UserController.updateUser() 处理
http://.../deleteUser.html -- 被 UserController.deleteUser() 处理
但是Q你应该注意C(jin)Q上面的 com.unmi.UserController 配置?jin)两ơ,一来碍眹{二来原来只?Singleton ?UserController 实例不再是那么回事了(jin)?br /> 所以要引入 SimpleUrlHandlerMapping ?Bean 配置q一步紧凑一下:(x)
<bean id="userController" class="com.unmi.UserController"/>
<bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/updateUser.html">userController</prop>
<prop key="/deleteUser.html">userController</prop>
</props>
</property>
</bean>
说是紧凑Q倒不如说 Bean 配置复杂?jin),反正不用配置两个相同?UserController 实例?jin)。还是通过上面那两?URL 来访问执行到相应的方法?/p>
除了(jin)~省的方法名解析?InternalPathMethodNameResolver(注意?jin),Spring 中缺省的 XXX 很多?InternalXXX 的命?Q还有两U其他类型的Ҏ(gu)名解析器Q?/p>
·ParameterMethodNameResolver -- Ҏ(gu)h中的参数解析执行Ҏ(gu)名,相当?Struts ?DispathAction
·PropertiesMethodNameResolver -- Ҏ(gu)查询一?key/value 列表解析执行Ҏ(gu)名,相当?Struts ?MappingDispatchAction(用得很少)
下面逐一介绍使用上面两种Ҏ(gu)名解析器时的 Bean 配置?qing)相应访问?URL?/p>
使用 ParameterMethodNameResolver 时的 Bean 配置(为简单v见,又用回了(jin)~省?HandlerMapping)Q?/p>
<bean name="/user.html" class="com.unmi.UserController">
<property name="methodNameResolver">
<ref bean="methodNameResolver"/>
</property>
</bean>
<bean name="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName">
<value>method</value>
</property>
</bean>
q时候分别用下面?URL p讉K到相应的Ҏ(gu)
http://.../user.html?method=updateUser -- 被 UserController.updateUser() 处理
http://.../user.html?method=deleteUser -- 被 UserController.deleteUser() 处理
通过参数的方式?HTML 表单表现用户选择成ؓ(f)可能Q例如把 method 参数可放在一个下拉框或隐藏域中?/p>
使用 PropertiesMethodNameResolver 时的 Bean 配置
<bean id="userController" class="com.unmi.UserController" />
<bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/updateUser.html">userController</prop>
<prop key="/deleteUser.html">userController</prop>
</props>
</property>
</bean>
<bean id="methodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
<property name="mappings">
<props>
<prop key="/updateUser.html">updateUser</prop>
<prop key="/deleteUser.html">deleteUser</prop>
</props>
</property>
</bean>
q种配置有点复杂QPropertiesMethodNameResolver 不仅?SimpleUrlHandlerMapping 总又有重叠Q而且必须?SimpleUrlHandlerMapping 拉进来,
无法使用默认?HandlerMapping。从上面的配|我们可以明昄看出 HandlerMapping ?MethodNameResolver 不同职责?jin),一个是定位 ControllerQ?br />
一个是定位 Method?/p>
q时候分别用下面?URL 来访问到相应 Controller 的方?/p>
http://.../updateUser.html -- 被 UserController.updateUser() 处理
http://.../deleteUser.html -- 被 UserController.deleteUser() 处理
q里?URL 恰y和?InternalPathMethodNameResolver 时是一L(fng)Q但一定要理解其实他们的机制是一L(fng)?/p>
PropertiesMethodNameResolver 把事性搞q么复杂Q被誉ؓ(f)最复杂的方法名解析器。可我还真看不出它还有什么独C处,或值得一用的理由Q?br />
同时也不隄?Struts ?MappingDispatchAction 鲜ؓ(f)人知的缘׃(jin)?/p>