设为首页 收藏本站
查看: 1624|回复: 0

[经验分享] 在应用程序中使用Spring启动嵌入式Jetty并让Web程序共享同一个Application Context(一)

[复制链接]

尚未签到

发表于 2017-2-27 10:51:40 | 显示全部楼层 |阅读模式
  Jetty 的简单灵活特性使之很适合用于嵌入到应用程序当中。
  比如开发一个多媒体资料管理库应用程序,你想用Web完成所有的用户界面,这时就可以让Jetty嵌入到你的应用程序作为Web容器。
  在应用程序里启动 Jetty 的方法很简单,使用如下代码即可:

Server server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(8080);
server.addConnector(connector);
WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setDescriptor("web/WEB-INF/web.xml");
context.setResourceBase("web");
context.setConfigurationDiscovered(true);
server.setHandler(context);
server.start();
  这里有更详细的示例:http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty
  通常我们的 Web 程序还会使用 Spring、 Struts、 Hibernate,为了让 Web 程序能使用 Spring ,我们只需在 web.xml 配置文件里加入如下代码即可:

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
  这样就可以让 Spring 管理 Service、 Reposity、事务等。另外在 web.xml 加上如下代码即可启用 Struts2 的支持

<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
  (注:你还需要 struts2-spring-plugin.jar 包才能让 Struts2 和 Spring 整合起来)
  这样一个简单的嵌入式 Web 环境即搭建完成。
  假如你在启动 Jetty 之前就已经创建和使用 Spring 的 Application Context 了,比如我在 Web 之外还要提供另外一个网络接口作为应用程序API的,而这个网络接口同时也依赖于 Spring 的 Application Context,这样你就会遇到一个问题:应用程序启动后会创建一个 context,当Jetty启动后又会创建一个 context,而刚好这两个 context 的内容其实是一样的。那么能不能让 Jetty 不创建新的 application context,而直接共享使用之前应用程序所创建的那个呢?
  经过实践,得出其中的一个方法如下:
  首先你要创建自己的 ContextLoaderListener 以替换掉 Spring 自带的那个,并把 web.xml 配置文件更改如下:

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</context-param>
<listener>
<listener-class>com.test.ShareContextLoaderListener</listener-class>
</listener>
  需要注意的是 “contextConfigLocation” 这个配置不能省略,否则启动 Jetty 时会出现异常。 其中 com.test.ShareContextLoaderListener.java 就是自己写的,代码如下:

package com.test;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.ContextLoaderListener;
public class ShareContextLoaderListener extends ContextLoaderListener {
@Override
protected ContextLoader createContextLoader() {
return new ShareContextLoader();
}
}

  实际上我只是继承Spring原有的 ContextLoaderListener 并将其中的 createContextLoader() 方法重写。上面代码中的 ShareContextLoader.java 的代码如下:

package com.test;
import javax.servlet.ServletContext;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoader;
public class ShareContextLoader extends ContextLoader {
@Override
protected ApplicationContext loadParentContext(ServletContext servletContext)
throws BeansException {
return (ApplicationContext) servletContext
.getAttribute("applicationContext");
}
}

  从上面的代码可见,其实应用程序所创建的 application context 是通过 servletContext 的 attribute 集合传递过来的。所以我们还要适当更改启动 Jetty 的代码:

package com.test;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.webapp.WebAppContext;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
public class JettyDaemon implements ApplicationContextAware{
private Server server;
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void start() throws Exception{
server = new Server();
SelectChannelConnector connector = new SelectChannelConnector();
connector.setPort(8080);
server.addConnector(connector);
WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setDescriptor("web/WEB-INF/web.xml");
context.setResourceBase("web");
context.setConfigurationDiscovered(true);
// 以下两行是关键所在 //
context.setClassLoader(applicationContext.getClassLoader());
context.setAttribute("applicationContext", applicationContext);
server.setHandler(context);
server.start();
}
}
  上面的这两行代码很关键:
  context.setClassLoader(applicationContext.getClassLoader());
context.setAttribute("applicationContext", applicationContext);
  第一行是为了让 web app 使用跟 application context 同一个 class loader。
  第二行是为了将 application context 通过 servletContext 的 attribute 集合传递给 ShareContextLoader,这里的 applicationContext 对象是由于当前类继承了 ApplicationContextAware 接口而得来的。
  这样我们就可以顺便在 Spring 的 applicationContext.xml 配置启动 Jetty 了,applicationContext.xml 文件的片段如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" … … … … … …>
<!-- daemons -->
<bean id="webDaemon" class="com.test.JettyDaemon" init-method="start" />
… … … … … …

  现在应用程序的 main() 方法里面只需加载 Spring context 即可,其他的所有工作就让 Spring 来完成吧。

public static void main(String[] args){
applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
applicationContext.registerShutdownHook();
}
  注:这篇文章的各个组件的版本如下:
  Jetty:7.0.2
  Spring:2.5.6
  Struts 2.1.8
  Hibernate 3.5.0
  下一篇将会介绍另一种比较简单的方法:
  《在应用程序中使用Spring启动嵌入式Jetty并让Web程序共享同一个Application Context(二)

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-347871-1-1.html 上篇帖子: i-jetty android服务器 程序开发示例--图片验证码 下篇帖子: 百度地图API入门——(4)用Jetty搭建一个简单的多终端可访问的地图应用站点
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表