六指琴魔电影歌曲:Spring的集成
来源:百度文库 编辑:中财网 时间:2024/05/07 15:28:47
原文地址:
http://cometd.org/documentation/cometd-java/server/services/integration-spring
Spring的集成
由 sbordet 提交于星期二,2009/11/17-15:39。
Bayeux 服务与Spring集成
CometD 服务与Spring的集成尤其有趣,因为大多时候你的 Bayeux 服务将需要其他 bean 来执行他们的服务。
并不是所有的 Bayeux 服务都像EchoService这样简单,加入Spring的依赖注入 (和其他框架一样) 集成将大大简化开发过程。
下面您可以找到 3 种建议的方法集成Spring。
Late Spring初始化
这种方法是延迟Spring初始化,直到 CometD servlet 初始化完成。
这种方法在这些情况下适用:要求Spring beans可以被延迟初始化,因为没有其他服务或框架需要预先进行Spring的初始化。
这种方法要求Spring和 Bayeux 服务的一些代码粘合在一起。
要求一些代码粘合在一起的原因有两个:
Bayeux 对象不是由Spring创建(是 CometD servlet),所以任何用于Bayeux对象的bean必须在CometD servlet初始化后才初始化。
在 web.xml中的servlets 和 listeners的初始化顺序在现有的Servlet 规范中不能被指定 (只有在servlet 3.0 中能完全指定顺序)
所以,为了保证方便初始化,这段粘合的代码是必需的。
下面您可以找到配置文件和集成Spring所需的代码。
首先,web.xml 文件:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
请注意我们是使用listener初始化Spring的。此listener完全取代了Spirng的 org.springframework.web.context.ContextLoaderListener,但它是基于相同的类的,这个类是用来执行web 应用程序启动时上下文初始化的。
这意味着:
LateSpringBayeuxInitializer会装载位于 /WEB-INF/applicationContext.xml中的Spring bean,或装载在 servlet上下文的初始化参数contextConfigLocation,和每一个通常Spring需要的配置。
其次, 在Spring的 applicationContext.xml 文件中,定义我们先前写好的 EchoService:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
请注意这里我们引用的是"bayeux"bean,这在Spring xml文件中是没有定义的,他是在 LateSpringBayeuxInitializer 中定义的,见下文。
最后,在 web.xml的 LateSpringBayeuxInitializer中像下面这样编写代码以整合Spring:
public class LateSpringBayeuxInitializerimplements ServletContextListener, ServletContextAttributeListener
{
private volatile ContextLoader loader;
public void contextInitialized(ServletContextEvent event)
{
}
public void contextDestroyed(ServletContextEvent event)
{
ContextLoader loader = this.loader;
if (loader != null)
loader.closeWebApplicationContext(event.getServletContext());
}
public void attributeAdded(ServletContextAttributeEvent event)
{
if (Bayeux.ATTRIBUTE.equals(event.getName()))
{
Bayeux bayeux = (Bayeux) event.getValue();
StaticListableBeanFactory factory = new StaticListableBeanFactory();
factory.addBean("bayeux", bayeux);
GenericApplicationContext bayeuxApplicationContext = newGenericApplicationContext(new DefaultListableBeanFactory(factory));
bayeuxApplicationContext.refresh();
loader = new BayeuxContextLoader(bayeuxApplicationContext);
ApplicationContext applicationContext =loader.initWebApplicationContext(event.getServletContext());
customizeBayeux(bayeux, applicationContext);
}
}
public void attributeRemoved(ServletContextAttributeEvent event)
{
}
public void attributeReplaced(ServletContextAttributeEvent event)
{
}
protected void customizeBayeux(Bayeux bayeux, ApplicationContextapplicationContext)
{
}
private static class BayeuxContextLoader extends ContextLoader
{
private final ApplicationContext parentApplicationContext;
public BayeuxContextLoader(ApplicationContext parentApplicationContext)
{
this.parentApplicationContext = parentApplicationContext;
}
@Override
protected ApplicationContext loadParentContext(ServletContextservletContext) throws BeansException
{
return parentApplicationContext;
}
}
}
请注意这里可以重写 customizeBayeux() 方法和进一步自定义 Bayeux 对象,例如,从Spring的应用程序上下文中查找一个 org.cometd.SecurityPolicy 对象并把它设置在 Bayeux 对象上。或者,用相同的方式,向 Bayeux 对象添加您Spring配置的 Bayeux 扩展。
Lazy Spring 初始化
这种方法允许正常初始化Spirng,但需要 Bayeux 服务标记成Lazy(懒加载) (且所有其他的bean或服务都要依赖于 Bayeux 服务),当然,也同样需要 CometD servlet正确初始化。
这种方法在这些情况下适用:有其他框架 (例如,Struts2) 需要预先进行Spring初始化。
这种方法需要编写一些代码从Spring配置文件中访问 Bayeux 对象。
首先,web.xml 文件:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
请注意我们使用的是普通的spring侦听器(ContextLoaderListener)进行Spring的初始化,但我们还添加了另一个侦听器,LazySpringBayeuxInitializer。
LazySpringBayeuxInitializer是我们需要从Spring配置文件中访问 Bayeux 对象所编写的代码:
public classLazySpringBayeuxInitializer implements ServletContextAttributeListener
{
public voidattributeAdded(ServletContextAttributeEvent event)
{
if(Bayeux.ATTRIBUTE.equals(event.getName()))
{
Bayeux bayeux = (Bayeux)event.getValue();
BayeuxHolder.setBayeux(bayeux);
}
}
public voidattributeRemoved(ServletContextAttributeEvent event)
{
}
public voidattributeReplaced(ServletContextAttributeEvent event)
{
}
}
LazySpringBayeuxInitializer类用到的 BayeuxHolder 类, 其实是非常简单的:
public classBayeuxHolder
{
private static volatile Bayeux bayeux;
public static void setBayeux(Bayeux bayeux)
{
BayeuxHolder.bayeux = bayeux;
}
public static Bayeux getBayeux()
{
return bayeux;
}
}
到此,我们需要在Spring的配置文件 applicationContext.xml 中做如下配置:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
请注意Spring的配置文件中可以有正常的bean (如 nonLazyService),这些bean可以被注入这些lazy(懒加载的) bean中,如: EchoService。
另外,请注意这里使用的 BayeuxHolder,是lazy(懒加载)初始化的,以便检索在 CometD servlet 初始化完成后被LazySpringBayeuxInitializer存储的 Bayeux 对象。
请注意EchoService是非常重要的,它也是懒加载的,这样它才能被注入到其他懒加载初始化的bean,或非单例bean (如原型范围的bean) ; 如果被注入到单例且非懒加载的bean中,因为他还没初始化(CometD servlet还没初始化),所以你会得到一个错误。
Full Spring初始化
这种方法是在Spring配置文件中直接初始化 Bayeux 对象,并注入 servlet 上下文中,这上下文是 CometD servlet 创建的。
这种方法更多地有点依赖于 CometD 实现,且如果CometD 实现更改了,它也要跟着改。
它可能需要或可能不需要中间代码,取决于正在开发的应用程序的其他细节(参见下文)。
它也需要一点规范,因为现在的Bayeux 对象可以在这两个位置: Spring配置文件和 web.xml 文件,而您不想将Bayeux 的配置拆分在不同的地方。
Web.xml 文件,如下所示:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
Spring的配置文件 applicationContext.xml 如下所示:
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
注意这里的Bayeux 对象是在applicationContext.xml文件中引用的,并且,这个Bayeux对象是通过spring的ServletContextAttributeExporter访问的。
这里只是创建一个没有初始化的Bayeux对象,只有在CometD servlet初始化后Bayeux对象才能够使用;正因为如此,懒加载的echoService(任何的Bayeux服务,引用到的服务,其他的依赖服务)才很重要。
因为echoService是懒加载的,当应用程序第一次用到它,就必须要告诉spring去实例化和初始化它。
如果你使用的其他框架需要用到spring的依赖注入,那么这个步骤应该由这个框架来完成。例如:你用spring配合structs2,你不需要告诉spring实例化和初始化你的CometD服务,因为structs2能识别有需要注入的CometD服务(如:在structs2的action中),所以structs2要求spring提供。
因此,上述的配置就完全足够了。
不管怎样,如果你不需要其他框架,你就要手动告诉spring实例化和初始化你的CometD服务。
这样做有点类似于非spring服务集成的描述:用一个servlet或侦听器来配置你的懒加载CometD服务。
见下面的例子:
public classConfigurationServlet extends GenericServlet
{
public void init() throws ServletException
{
// Grab Spring's ApplicationContent
ApplicationContext context =WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
// Trigger CometD serviceinitialization
context.getBean("echoService");
}
public void service(ServletRequest request,ServletResponse response) throws ServletException, IOException
{
throw new ServletException();
}
}
在web.xml的这个servlet中必须给load-on-startup标签元素设置一个高的值。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">