java中关于Struts和spring集成的一些原理剖析

来源:互联网 发布:ipad软件连不上网络 编辑:程序博客网 时间:2024/05/18 12:33

用过ssh的人都知道struts和spring的有很多种集成方式现在我就常用的一些spring类做简单的剖析,我们先看第一个类org.springframework.web.struts.DelegatingActionProxy,我们看一些它做了那些事。

//看到Action 就知道他也是一个Action
public class DelegatingActionProxy extends Action {

 public DelegatingActionProxy() {
 }

 public ActionForward execute(ActionMapping mapping, ActionForm form,
   HttpServletRequest request, HttpServletResponse response)
   throws Exception {
  Action delegateAction = getDelegateAction(mapping);//通过映射文件mapping找到spring创建的ActionBean,然后委托他,其实这种方式也是一种代理,只是显现的方式有些不同吧了。
  return delegateAction.execute(mapping, form, request, response);
 }

 protected Action getDelegateAction(ActionMapping mapping)
   throws BeansException {
  WebApplicationContext wac = getWebApplicationContext(getServlet(),
    mapping.getModuleConfig());//通过ServletContext找到WebApplicationContext ,当spring的ContextLoaderListener或ContextServlet创建好之后放在ServletContext中就是application中
  String beanName = determineActionBeanName(mapping);//通过mapping查找actionName
  return (Action) wac.getBean(beanName, org / apache / struts / action
    / Action);//从WebApplicationContext 查找ActionBean
 }

 protected WebApplicationContext getWebApplicationContext(
   ActionServlet actionServlet, ModuleConfig moduleConfig)
   throws IllegalStateException {
  return DelegatingActionUtils.findRequiredWebApplicationContext(
    actionServlet, moduleConfig);
 }

 protected String determineActionBeanName(ActionMapping mapping) {
  return DelegatingActionUtils.determineActionBeanName(mapping);
 }
}

 

通过DelegatingActionProxy 的源码我们知道struts在访问spring创建好的Action时是通过spring的代理Action在调用execute方法时委托给Action来现实的,那是不是只有这一种方式了,其实不然,我们在看另外的一种方式。

Struts1中还有一种通过processor来控制的,当用户的一个请求发出给了ActionServlet之后紧接着ActionServlet把请求交给了Processor处理下面就看一下spring是如何处理的。


public class DelegatingRequestProcessor extends RequestProcessor {

 public DelegatingRequestProcessor() {
 }

 public void init(ActionServlet actionServlet, ModuleConfig moduleConfig)
   throws ServletException {
  super.init(actionServlet, moduleConfig);
  if (actionServlet != null)
   webApplicationContext = initWebApplicationContext(actionServlet,
     moduleConfig);//初始化webApplicationContext
 }

//关键地方是在这里

 protected Action processActionCreate(HttpServletRequest request,
   HttpServletResponse response, ActionMapping mapping)
   throws IOException {

//当创建Action时spring做了处理,从webApplicationContext 中取出创建好的Action实例,然后把请求交给Action实例。
  Action action = getDelegateAction(mapping);
  if (action != null)
   return action;
  else
   return super.processActionCreate(request, response, mapping);
 }

 

 private WebApplicationContext webApplicationContext;
}
这个是上面的类似都是代理的方式实现的。这是spring和struts的集成问题,那spring和hibernate的集成有没有问题了,请看下面的代码。


public class OpenSessionInViewFilter extends OncePerRequestFilter {

 

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException
    {
        SessionFactory sessionFactory;
        boolean participate;
        sessionFactory = lookupSessionFactory(request);//查找SessionFactory
        participate = false;
        if(isSingleSession())//session是不是单例
        {
            if(TransactionSynchronizationManager.hasResource(sessionFactory))
            {
                participate = true;
            } else
            {
                logger.debug("Opening single Hibernate Session in OpenSessionInViewFilter");
                Session session = getSession(sessionFactory);//获取Session
                TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));//绑定Session到当前的线程中
            }
        } else
        if(SessionFactoryUtils.isDeferredCloseActive(sessionFactory))
            participate = true;
        else
            SessionFactoryUtils.initDeferredClose(sessionFactory);
        filterChain.doFilter(request, response);
        break MISSING_BLOCK_LABEL_154;
        Exception exception;
        exception;
        if(!participate)
            if(isSingleSession())
            {
                SessionHolder sessionHolder = (SessionHolder)TransactionSynchronizationManager.unbindResource(sessionFactory);//请求执行完毕之后又解除绑定
                logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
                closeSession(sessionHolder.getSession(), sessionFactory);
            } else
            {
                SessionFactoryUtils.processDeferredClose(sessionFactory);//处理延迟关闭的Session
            }
        throw exception;
        if(!participate)
            if(isSingleSession())
            {
                SessionHolder sessionHolder = (SessionHolder)TransactionSynchronizationManager.unbindResource(sessionFactory);
                logger.debug("Closing single Hibernate Session in OpenSessionInViewFilter");
                closeSession(sessionHolder.getSession(), sessionFactory);//关闭Session
            } else
            {
                SessionFactoryUtils.processDeferredClose(sessionFactory);//处理延迟关闭的session
            }
        return;
    }
通过以上的代码的分析我们知道在处理一次请求可以使用一个Session或多个Session而且Session不是调用完了就立即关闭而是等到一次请求完毕之后再统一关闭。为什么要这样做了?我们都知道hibernate有延迟加载的功能但是通常session使用完了就关闭了所以当遇到延迟加载的对象就出现Session已经关闭的异常消息,那为什么配置了SessionInViewFilter就可以避免了,是因为session在Filter过滤请求之前打开,在Filter过滤请求之后才关闭满足了延迟加载。那为什么Filer可以再请求之前了,我们都知道用户请求的一般执行过程,现实Filter过滤然后再是Servlet或者Action,那这又和页面访问对象的属性有什么关系了,Servlet和Action执行完了之后还是要关闭Session啊,这是因为页面也是Servlet,这样Filter就在页面请求的所有资源就可以再Filter中过滤了,Session是在页面动态构建好之后显示在用户之前关闭的。其实jsp页面对解析成Servlet了然后在Service方法中动态的构建好html然后输出的。不信可以看一下Tomcat中的work目录中我们的项目,全部是Jsp页面对应的Servlet类。

下面看一下DispatchAction如何实现动态调用Action中的方法。


public abstract class DispatchAction extends Action {

 public DispatchAction() {
  clazz = getClass();
  methods = new HashMap();
  types = (new Class[] { org.apache.struts.action.ActionMapping.class,
    org.apache.struts.action.ActionForm.class,
    javax.servlet.http.HttpServletRequest.class,
    javax.servlet.http.HttpServletResponse.class });
 }

 public ActionForward execute(ActionMapping mapping, ActionForm form,
   HttpServletRequest request, HttpServletResponse response)
   throws Exception {
  if (isCancelled(request)) {
   ActionForward af = cancelled(mapping, form, request, response);
   if (af != null)
    return af;
  }
  String parameter = getParameter(mapping, form, request, response);//获取页面提交过来的参数(mapping对应parameter 具体的方法参数)
  String name = getMethodName(mapping, form, request, response, parameter);//获取方法名称parameter对应的参数值
  if ("execute".equals(name) || "perform".equals(name)) {
   String message = messages.getMessage("dispatch.recursive", mapping
     .getPath());
   log.error(message);
   throw new ServletException(message);
  } else {
   return dispatchMethod(mapping, form, request, response, name);//调用Action的中的方法
  }
 }


 protected ActionForward dispatchMethod(ActionMapping mapping,
   ActionForm form, HttpServletRequest request,
   HttpServletResponse response, String name) throws Exception {
  if (name == null)
   return unspecified(mapping, form, request, response);
  Method method = null;
  try {
   method = getMethod(name);//从反射机制获取对应的方法
  } catch (NoSuchMethodException e) {
   String message = messages.getMessage("dispatch.method", mapping
     .getPath(), name);
   log.error(message, e);
   String userMsg = messages.getMessage("dispatch.method.user",
     mapping.getPath());
   throw new NoSuchMethodException(userMsg);
  }
  ActionForward forward = null;
  try {
   Object args[] = { mapping, form, request, response };//Action中的方法参数列表
   forward = (ActionForward) method.invoke(this, args);//使用反射动态的调用Action中的方法
  } catch (ClassCastException e) {
   String message = messages.getMessage("dispatch.return", mapping
     .getPath(), name);
   log.error(message, e);
   throw e;
  } catch (IllegalAccessException e) {
   String message = messages.getMessage("dispatch.error", mapping
     .getPath(), name);
   log.error(message, e);
   throw e;
  } catch (InvocationTargetException e) {
   Throwable t = e.getTargetException();
   if (t instanceof Exception) {
    throw (Exception) t;
   } else {
    String message = messages.getMessage("dispatch.error", mapping
      .getPath(), name);
    log.error(message, e);
    throw new ServletException(t);
   }
  }
  return forward;
 }

}

通过以上代码分析知道DsiptcherAction是通过反射技术实现动态的调用Action中的方法。

接下来看一下spring与struts2是怎样集成的:


public class SpringObjectFactory extends ObjectFactory implements
  ApplicationContextAware {

//覆盖ObjectFactory 中的方法,不使用Class直接new对象而是使用spring创建对象好的对象
public Object buildBean(String beanName, Map extraContext,
   boolean injectInternal) throws Exception {
  Object o = null;
  try {
   o = appContext.getBean(beanName);//beanName在WebApplicationContext中取出创建好的Action对象
  } catch (NoSuchBeanDefinitionException e) {
   Class beanClazz = getClassInstance(beanName);
   o = buildBean(beanClazz, extraContext);
  }
  if (injectInternal)
   injectInternalBeans(o);
  return o;
 }

}

 

原创粉丝点击