欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring DM集成Strtus2(一)

程序员文章站 2022-05-23 11:42:41
...

要完成Spring DM与Struts2的集成,主要完成两件事

  • 将Struts2集成到OSGi环境中。
  • 将Spring DM与Struts2集成,使Struts2可以使用Spring DM中定义的Bean。

此文章采用的方法不是Spring DM Web Extender的方式,由Spring DM Web是将工程手动注册到Web容器中,暂时只支持tomcat与jetty。

 

Struts2集成到OSGi环境中

        这步的目的是让Struts2的bundle可以读到其实bundle下的Struts配置文件,由于Struts2本身只处理了classpath下面的三类配置文件,分别为struts-default.xml、struts-plugin.xml、struts.xml文件,所以首先我们要增加读取bundle下面配置文件的ConfigurationProvider,代码在org.apache.struts2.dispatcher.Dispatcher,将此类的源代码找出来,然后修改private void init_TraditionalXmlConfigurations()方法

 

 private void init_TraditionalXmlConfigurations() {
        String configPaths = initParams.get("config");
        if (configPaths == null) {
            configPaths = DEFAULT_CONFIGURATION_PATHS;
        }
        String[] files = configPaths.split("\\s*[,]\\s*");
        for (String file : files) {
            if (file.endsWith(".xml")) {
                if ("xwork.xml".equals(file)) {
                    configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false));
                } else {
                    configurationManager.addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext));
                }
            } else {
                throw new IllegalArgumentException("Invalid configuration file name");
            }
        }
        //FIXME 增加读取bundle中配置文件的类。
        configurationManager.addContainerProvider(new OSGiXmlConfigurationProvider("struts_osgi.xml",false,servletContext));
    }

 

 其中OSGiXmlConfigurationProvider的代码见附件, 主要的代码在loadConfigurationFiles方法中

Bundle[] bundles=Activator.getContext().getBundles();
			ByteArrayOutputStream bos=new ByteArrayOutputStream();
			for(Bundle bundle:bundles){
				try {
					//不加载本bundle的struts.xml文件
					if(bundle.getSymbolicName().equals(Activator.getContext().getBundle().getSymbolicName())) continue;
					url=bundle.getEntry(DEFAULT_CONFIG_NAME);
					if(url==null) continue;
					is=url.openStream();
					IOUtils.copy(is, bos);
					is=new ByteArrayInputStream(bos.toByteArray());
					InputSource in = new InputSource(is);
					
					in.setSystemId(is.toString());
					Document doc=DomHelper.parse(in,dtdMappings);
					try{
						//增加默认名称空间
						addDefaultNamespace(doc,bundle.getHeaders().get(WEB_CONTEXT),HashFile.getHash(bos.toByteArray()),bundle.getBundleId());
					}catch(Exception e){
						LOG.error("增加包名到缓存失败", e, new String[]{});
					}
					docs.add(doc);
				} catch (IOException e) {
					LOG.error("加载ID为"+bundle.getBundleId()+" 的bundle中的配置文件失败!", e, new String[]{});
				}finally{
					if(is!=null){
						try {
							is.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
					if(bos!=null){
						try {
							bos.close();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
			}

 接下来就是注册Struts2的servlet,由于采用的是Equinox的http实现,所以要用HttpService来注册

package com.yinhai.osgi.web.struts2;

import javax.servlet.Servlet;
import javax.servlet.ServletException;

import org.apache.log4j.Logger;
import org.apache.struts2.dispatcher.ng.servlet.StrutsServlet;
import org.eclipse.equinox.http.helper.BundleEntryHttpContext;
import org.eclipse.equinox.http.helper.ContextPathServletAdaptor;
import org.eclipse.equinox.jsp.jasper.JspServlet;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.SynchronousBundleListener;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.service.http.NamespaceException;
import org.osgi.util.tracker.ServiceTracker;

/**
 * 用于注册struts2的servlet和web bundle的上下文。
 * @author Dream.Lee
 * @version 2013-6-5
 */
public class StrutsController implements BundleListener {
	
	private static Logger logger=Logger.getLogger(StrutsController.class);
	public static final String WEB_CONTEXT="Web-Context";
	
	public static final String STATIC_SUBFIX="_res";

	private HttpService httpService;
	
	public static final String WEB_CONTENT_PATH = "/WebContent";

	public void activate(ComponentContext context) {
		registerController("/*.do");
		//对已有的bundle进行web上下文注册
		Bundle[] bundles=Activator.getContext().getBundles();
		for(Bundle bundle:bundles){
			if(bundle.getHeaders().get(WEB_CONTEXT)!=null&&bundle.getState()==Bundle.ACTIVE){
				try {
					ServiceTracker<HttpService, HttpService> sTracker=new ServiceTracker<HttpService, HttpService>(bundle.getBundleContext(), HttpService.class.getName(), null);
					sTracker.open();
					HttpService httpService=sTracker.getService();
					if(httpService!=null){
						httpService.registerResources(bundle.getHeaders().get(WEB_CONTEXT)+STATIC_SUBFIX,WEB_CONTENT_PATH,
								 null);
						// 注册JSP文件
						HttpContext commonContext = new BundleEntryHttpContext(
								bundle, WEB_CONTENT_PATH);
						Servlet adaptedJspServlet = new ContextPathServletAdaptor(
								new JspServlet(bundle,
										WEB_CONTENT_PATH), bundle.getHeaders().get(
										WEB_CONTEXT));
						httpService.registerServlet(
								bundle.getHeaders().get(WEB_CONTEXT) + "/*.jsp",
								adaptedJspServlet, null, commonContext);
					}
//					sTracker.close();
				} catch (NamespaceException e) {
					e.printStackTrace();
				} catch (ServletException e) {
					e.printStackTrace();
				}
			}
		}
		Activator.getContext().addBundleListener(this);
		Activator.getContext().addBundleListener(new SynchronousBundleListener() {
			
			@SuppressWarnings({ "rawtypes", "unchecked" })
			@Override
			public void bundleChanged(BundleEvent event) {
				Bundle bundle=event.getBundle();
				if (bundle.getHeaders().get(WEB_CONTEXT) != null) {
					switch(event.getType()){
						case BundleEvent.STOPPING:
							ServiceReference sf=bundle.getBundleContext().getServiceReference(HttpService.class.getName());
							HttpService httpService = (HttpService) bundle
									.getBundleContext().getService(sf);
							try{
								httpService.unregister(bundle.getHeaders().get(WEB_CONTEXT)+STATIC_SUBFIX);
								logger.info("卸载"+bundle.getHeaders().get(WEB_CONTEXT));
							}catch(Exception e){
								logger.info("卸载失败:"+bundle.getHeaders().get(WEB_CONTEXT), e);
							}finally{
								bundle.getBundleContext().ungetService(sf);
							}
							break;
					}
				}
			}
		});
	}

	public void setHttpService(HttpService httpService) {
		this.httpService = httpService;
	}


	private void registerController(String webcontext) {
		try {
			StrutsServlet controller = new StrutsServlet();
			httpService.registerServlet(webcontext, controller, null, null);
			controller.init();
			logger.info("已注册:" + webcontext);
		} catch (Exception e) {
			logger.error("注册扩展的:" + webcontext + "失败", e);
		}
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public void bundleChanged(BundleEvent event) {
		Bundle bundle = event.getBundle();
		if (bundle.getHeaders().get(WEB_CONTEXT) != null) {
			if (event.getType() == BundleEvent.STARTED) {
				logger.info("注册 "
						+ bundle.getHeaders().get(WEB_CONTEXT)+STATIC_SUBFIX + ","
						+ bundle.getHeaders().get(WEB_CONTEXT)
						+ "/*.jsp");
				BundleContext context = bundle.getBundleContext();
				ServiceReference sf=context.getServiceReference(HttpService.class.getName());
				HttpService httpService = (HttpService) bundle
						.getBundleContext().getService(sf);
				try {
					// 注册静态文件
					httpService.registerResources(bundle.getHeaders().get(WEB_CONTEXT)+STATIC_SUBFIX,
					 WEB_CONTENT_PATH, null);

					// 注册JSP文件
					Servlet adaptedJspServlet = new ContextPathServletAdaptor(
							new JspServlet(bundle,
									WEB_CONTENT_PATH), bundle
									.getHeaders().get(WEB_CONTEXT));
					httpService.registerServlet(bundle.getHeaders()
							.get(WEB_CONTEXT) + "/*.jsp",
							adaptedJspServlet, null, null);
				} catch (NamespaceException e) {
					e.printStackTrace();
				} catch (ServletException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

 此类采用声明式的方式发布,配置文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<component name="strutscontroller">
	<implementation class="com.yinhai.osgi.web.struts2.StrutsController"/>
	<reference name="HttpService" interface="org.osgi.service.http.HttpService" bind="setHttpService" unbind="unsetHttpService" policy="dynamic"/>
</component>