【WEB】struts2整合spring原理以及源码剖析
2015-04-14 10:33
281 查看
一、原理概述
1. struts和spring整合,到底是谁整合谁?
是struts整合spring还是spring整合struts?这个问题重要吗?有必要讨论吗?说struts整合spring,是因为struts比spring晚出现,所以只能是struts整合spring,貌似有一定的道理,但是不绝对正确。一个框架的流行取决于市场的接受程度,在struts很流行的前提下如果spring没有那么流行,那么无论是谁先出现谁后出现,恐怕spring为了自身的发展也会要去整合struts。
事实上的确是struts整合spring,但原因不是两个框剪出现的时间,而是两个框架提供了什么样的jar包。struts和spring整合后的运行环境不再只是单纯的JVM,而是WEB服务器,spring提供接入web的jar包是spring-web-x.x.x.RELEASE.jar,这个jar包的作用是将spring容器整合到WEB容器(见上一篇博文:《【Spring】Spring&WEB整合原理及源码剖析》),而struts提供的jar包是struts2-spring-plugin-x.x.x.x.jar,这个jar包里面改写了struts默认的对象工厂ObjectFactory,重新提供了一个新的对象工厂SpringObjectFactory,在这个工厂类里面你会看到出现spring框架中的类和对象,也就是struts通过这个jar包,把spring整合到了自己的框架里面,从而享受spring带来的便利。
2. struts是表现层MVC框架,而spring是业务层框架,struts整合spring,整合的到底是什么东西?
spring的核心是IOC和AOP(加多spring MVC和spring JDBC/事务),通俗的讲spring是框架的框架,他自己本身就是一个框架,但是他主要服务于其他框架。所以整合的核心就落点于spring的”服务“,spring为其他框架提供了什么样的服务?换言之,struts需要把什么东西托管给spring,从而获得更好的服务?这一切谜题的答案就在struts框架提供整合spring的jar包之中:struts2-spring-plugin-x.x.x.x.jar。
这个jar包里面主要提供了SpringObjectFactory这个对象工厂,将原来struts对象工厂创建的实例交由spring IOC容器来创建和管理,从而首先享受了spring提供的IOC服务,因为从spring容器获得bean实例,从而又享受到了spring带来的其他诸如AOP、spring JDBC、spring事务管理等等服务。
所以,struts整合spring,是将spring的IOC整合到了自己的框架里面!
3. 整合步骤如概述
1. spring整合web,参看上一篇文章《【Spring】Spring&WEB整合原理及源码剖析》,主要由spring框架提供的jar包完成:spring-web-x.x.x.RELEASE.jar;2. struts接入spring,将原来struts自己ObjectFactory创建的对象交由SpringObjectFactory来创建并缓存,主要由struts提供的jar包完成:struts2-spring-plugin-2.3.15.3.jar;
3. 最后,不要忘记struts的Action托管给spring,并且设置scope="ptototype";
二、实现细节&源码code实现
一句话struts整合spring:配置好web.xml(spring接入web,struts配置过滤器,剩下的交由两个jar包处理即可,是不是太TM的简单了?一切就是那么简单!),导入spring-web-x.x.x.RELEASE.jar,导入struts2-spring-plugin-2.3.15.3.jar,完成!因为spring整合web上一次有过详细讨论,这一次主要讨论的是struts提供的jar包,也即struts对象工厂的替换。
1. 怎么实现工厂替换
struts默认的对象工厂是ObjectFactory,该工厂提供了在struts启动的时候实例化、装配bean的操作,主要是struts-default.xml中配好的bean/result/interceptor(缓存在ContainerImpl中),以及运行期的action及其参数注入。SpringObjectFactory是ObjectFactory的子类,要想替换ObjectFactory,利用面向对象三大特性“多态”即可完成。要想完成替换,需要告知struts你的意图,替换的开关在最先加载的框架起配置文件default.properties中,即struts.objectFactory = spring。要想打开这个开关,你可以在struts-default.xml、struts-plugin.xml、struts.xml、struts.properties、web.xml总共五处完成操作,当然struts-default.xml和struts-plugin.xml是不能修改的,除非系统已经提供。毋庸置疑,既然struts整合spring,那么struts提供的整合插件必然打开了这个开关,不需要你再手动配置。
struts.xml中对象工厂替换配置内容,默认开关是关闭的。
### if specified, the default object factory can be overridden here ### Note: short-hand notation is supported in some cases, such as "spring" ### Alternatively, you can provide a com.opensymphony.xwork2.ObjectFactory subclass name here # struts.objectFactory = spring(看我看我看我看我看我,我就是开关,默认是关闭的,已经在struts-spring-plugin-xxx.jar中打开了,引入了该jar包即可,剩下的什么也不用操作) ### specifies the autoWiring logic when using the SpringObjectFactory. ### valid values are: name, type, auto, and constructor (name is the default) struts.objectFactory.spring.autoWire = name ### indicates to the struts-spring integration if Class instances should be cached ### this should, until a future Spring release makes it possible, be left as true ### unless you know exactly what you are doing! ### valid values are: true, false (true is the default) struts.objectFactory.spring.useClassCache = true ### ensures the autowire strategy is always respected. ### valid values are: true, false (false is the default) struts.objectFactory.spring.autoWire.alwaysRespect = falsestruts-plugin.xml,struts提供的整合jar包配置文件内容,可以看到开关已经打开, <constant name="struts.objectFactory" value="spring" />。
<?xml version="1.0" encoding="UTF-8" ?> <!-- /* * $Id: struts-plugin.xml 1221225 2011-12-20 12:22:28Z jogep $ * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ --> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <bean type="com.opensymphony.xwork2.ObjectFactory" name="spring" class="org.apache.struts2.spring.StrutsSpringObjectFactory" /> <!-- Make the Spring object factory the automatic default --> <constant name="struts.objectFactory" value="spring" /> <constant name="struts.class.reloading.watchList" value="" /> <constant name="struts.class.reloading.acceptClasses" value="" /> <constant name="struts.class.reloading.reloadConfig" value="false" /> <package name="spring-default"> <interceptors> <interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/> </interceptors> </package> </struts>
2. 替换了哪些内容
struts的默认工厂ObjectFactory里面提供了一堆的buildXXX方法,但是所有的buildXXX方法最终都通过调用buildBean来实现。其中涉及类的关系统如下所示。更多细节,请参看源码注解。
package org.apache.struts2.spring; import com.opensymphony.xwork2.inject.Container; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.spring.SpringObjectFactory; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import org.apache.struts2.StrutsConstants; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.web.context.WebApplicationContext; import javax.servlet.ServletContext; /** * Struts object factory that integrates with Spring. * <p/> * Spring should be loaded using a web context listener * <code>org.springframework.web.context.ContextLoaderListener</code> defined in <code>web.xml</code>. * */ public class StrutsSpringObjectFactory extends SpringObjectFactory { private static final Logger LOG = LoggerFactory.getLogger(StrutsSpringObjectFactory.class); //@Inject //public StrutsSpringObjectFactory( // @Inject(value=StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_AUTOWIRE,required=false) String autoWire, // @Inject(value=StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_USE_CLASS_CACHE,required=false) String useClassCacheStr, // @Inject ServletContext servletContext) { // this(autoWire, "false", useClassCacheStr, servletContext); //} /** * Constructs the spring object factory * @param autoWire The type of autowiring to use * @param alwaysAutoWire Whether to always respect the autowiring or not * @param useClassCacheStr Whether to use the class cache or not * @param servletContext The servlet context * @since 2.1.3 */ @Inject public StrutsSpringObjectFactory( @Inject(value=StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_AUTOWIRE,required=false) String autoWire, @Inject(value=StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_AUTOWIRE_ALWAYS_RESPECT,required=false) String alwaysAutoWire, @Inject(value=StrutsConstants.STRUTS_OBJECTFACTORY_SPRING_USE_CLASS_CACHE,required=false) String useClassCacheStr, @Inject ServletContext servletContext, @Inject(StrutsConstants.STRUTS_DEVMODE) String devMode, @Inject Container container) { super(); boolean useClassCache = "true".equals(useClassCacheStr); if (LOG.isInfoEnabled()) { LOG.info("Initializing Struts-Spring integration..."); } /** * 从ServletContext中获取spring IOC容器 * 该容器在spring web的jar包中创建完成并放入ServletContext,具体代码在ContextLoader类中 */ Object rootWebApplicationContext = servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE); if(rootWebApplicationContext instanceof RuntimeException){ RuntimeException runtimeException = (RuntimeException)rootWebApplicationContext; LOG.fatal(runtimeException.getMessage()); return; } //强转成父类型 ApplicationContext appContext = (ApplicationContext) rootWebApplicationContext; if (appContext == null) { // uh oh! looks like the lifecycle listener wasn't installed. Let's inform the user String message = "********** FATAL ERROR STARTING UP STRUTS-SPRING INTEGRATION **********\n" + "Looks like the Spring listener was not configured for your web app! \n" + "Nothing will work until WebApplicationContextUtils returns a valid ApplicationContext.\n" + "You might need to add the following to web.xml: \n" + " <listener>\n" + " <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n" + " </listener>"; LOG.fatal(message); return; } //从struts容器中获取一些开发模式的实例 String watchList = container.getInstance(String.class, "struts.class.reloading.watchList"); String acceptClasses = container.getInstance(String.class, "struts.class.reloading.acceptClasses"); String reloadConfig = container.getInstance(String.class, "struts.class.reloading.reloadConfig"); //对于开发模式的处理 if ("true".equals(devMode) && StringUtils.isNotBlank(watchList) && appContext instanceof ClassReloadingXMLWebApplicationContext) { //prevent class caching useClassCache = false; ClassReloadingXMLWebApplicationContext reloadingContext = (ClassReloadingXMLWebApplicationContext) appContext; reloadingContext.setupReloading(watchList.split(","), acceptClasses, servletContext, "true".equals(reloadConfig)); if (LOG.isInfoEnabled()) { LOG.info("Class reloading is enabled. Make sure this is not used on a production environment!", watchList); } setClassLoader(reloadingContext.getReloadingClassLoader()); //we need to reload the context, so our isntance of the factory is picked up reloadingContext.refresh(); } /** * 为SpringObjectFactory设置容器(替代ContainerImpl) * 方法setApplicationContext来自父类SpringObjectFactory * SpringObjectFactory中方法重写了ApplicationContextAware(spring中的类) * 此时,struts开始和spring发生耦合,struts获得了spring的IOC容器 */ this.setApplicationContext(appContext); /** * 开启spring工厂开关后,struts配置文件default.properties中关于springObjectFactory开始生效 * 默认是按照name进行装配 struts.objectFactory.spring.autoWire = name * 提供的装配类型有: * name(名字装配)、type(类型装配)、constructor(按构造器装配)、auto(自动装配)、no(不自动装配) */ int type = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; // default if ("name".equals(autoWire)) { type = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; } else if ("type".equals(autoWire)) { type = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; } else if ("auto".equals(autoWire)) { type = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT; } else if ("constructor".equals(autoWire)) { type = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR; } else if ("no".equals(autoWire)) { type = AutowireCapableBeanFactory.AUTOWIRE_NO; } this.setAutowireStrategy(type); this.setUseClassCache(useClassCache); this.setAlwaysRespectAutowireStrategy("true".equalsIgnoreCase(alwaysAutoWire)); if (LOG.isInfoEnabled()) { LOG.info("... initialized Struts-Spring integration successfully"); } } }
package com.opensymphony.xwork2.spring; import com.opensymphony.xwork2.ObjectFactory; import com.opensymphony.xwork2.inject.Inject; import com.opensymphony.xwork2.util.logging.Logger; import com.opensymphony.xwork2.util.logging.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.UnsatisfiedDependencyException; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.util.HashMap; import java.util.Map; /** * Simple implementation of the ObjectFactory that makes use of Spring's application context if one has been configured, * before falling back on the default mechanism of instantiating a new class using the class name. <p/> In order to use * this class in your application, you will need to instantiate a copy of this class and set it as XWork's ObjectFactory * before the xwork.xml file is parsed. In a servlet environment, this could be done using a ServletContextListener. * * @author Simon Stewart (sms@lateral.net) */ public class SpringObjectFactory extends ObjectFactory implements ApplicationContextAware { private static final Logger LOG = LoggerFactory.getLogger(SpringObjectFactory.class); protected ApplicationContext appContext;//spring IOC容器 protected AutowireCapableBeanFactory autoWiringFactory;//spring中用于自动装配的类 protected int autowireStrategy = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;//默认按照name进行装配,配置项在default.properties中 private final Map<String, Object> classes = new HashMap<String, Object>(); private boolean useClassCache = true; private boolean alwaysRespectAutowireStrategy = false; @Inject(value="applicationContextPath",required=false) public void setApplicationContextPath(String ctx) { if (ctx != null) { setApplicationContext(new ClassPathXmlApplicationContext(ctx)); } } /** * Set the Spring ApplicationContext that should be used to look beans up with. * * @param appContext The Spring ApplicationContext that should be used to look beans up with. */ public void setApplicationContext(ApplicationContext appContext) throws BeansException { this.appContext = appContext; autoWiringFactory = findAutoWiringBeanFactory(this.appContext); } /** * Sets the autowiring strategy * 装配策略 * @param autowireStrategy */ public void setAutowireStrategy(int autowireStrategy) { switch (autowireStrategy) { case AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT: if (LOG.isInfoEnabled()) { LOG.info("Setting autowire strategy to autodetect"); } this.autowireStrategy = autowireStrategy; break; case AutowireCapableBeanFactory.AUTOWIRE_BY_NAME: if (LOG.isInfoEnabled()) { LOG.info("Setting autowire strategy to name"); } this.autowireStrategy = autowireStrategy; break; case AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE: if (LOG.isInfoEnabled()) { LOG.info("Setting autowire strategy to type"); } this.autowireStrategy = autowireStrategy; break; case AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR: if (LOG.isInfoEnabled()) { LOG.info("Setting autowire strategy to constructor"); } this.autowireStrategy = autowireStrategy; break; case AutowireCapableBeanFactory.AUTOWIRE_NO: if (LOG.isInfoEnabled()) { LOG.info("Setting autowire strategy to none"); } this.autowireStrategy = autowireStrategy; break; default: throw new IllegalStateException("Invalid autowire type set"); } } public int getAutowireStrategy() { return autowireStrategy; } /** * If the given context is assignable to AutowireCapbleBeanFactory or contains a parent or a factory that is, then * set the autoWiringFactory appropriately. * * @param context */ protected AutowireCapableBeanFactory findAutoWiringBeanFactory(ApplicationContext context) { if (context instanceof AutowireCapableBeanFactory) { // Check the context return (AutowireCapableBeanFactory) context; } else if (context instanceof ConfigurableApplicationContext) { // Try and grab the beanFactory return ((ConfigurableApplicationContext) context).getBeanFactory(); } else if (context.getParent() != null) { // And if all else fails, try again with the parent context return findAutoWiringBeanFactory(context.getParent()); } return null; } /** * Looks up beans using Spring's application context before falling back to the method defined in the {@link * ObjectFactory}. * * @param beanName The name of the bean to look up in the application context * @param extraContext * @return A bean from Spring or the result of calling the overridden * method. * @throws Exception */ @Override public Object buildBean(String beanName, Map<String, Object> extraContext, boolean injectInternal) throws Exception { Object o; if (appContext.containsBean(beanName)) { o = appContext.getBean(beanName); } else { Class beanClazz = getClassInstance(beanName); o = buildBean(beanClazz, extraContext); } if (injectInternal) { injectInternalBeans(o); } return o; } /** * @param clazz * @param extraContext * @throws Exception * 所有创建和装配对象的最终方法,也是最重要的方法 * 不再由struts创建并缓存 * 而是由spring的自动装配类autoWiringFactory来创建和装配,最后 */ @Override public Object buildBean(Class clazz, Map<String, Object> extraContext) throws Exception { Object bean; try { // Decide to follow autowire strategy or use the legacy approach which mixes injection strategies if (alwaysRespectAutowireStrategy) { // Leave the creation up to Spring bean = autoWiringFactory.createBean(clazz, autowireStrategy, false); injectApplicationContext(bean); return injectInternalBeans(bean);//放入容器 } else { bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false); bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName()); // We don't need to call the init-method since one won't be registered. bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName()); return autoWireBean(bean, autoWiringFactory);//自动装配bean,并放入容器 } } catch (UnsatisfiedDependencyException e) { if (LOG.isErrorEnabled()) LOG.error("Error building bean", e); // Fall back return autoWireBean(super.buildBean(clazz, extraContext), autoWiringFactory); } } public Object autoWireBean(Object bean) { return autoWireBean(bean, autoWiringFactory); } /** * @param bean * @param autoWiringFactory */ public Object autoWireBean(Object bean, AutowireCapableBeanFactory autoWiringFactory) { if (autoWiringFactory != null) { autoWiringFactory.autowireBeanProperties(bean, autowireStrategy, false); } injectApplicationContext(bean); injectInternalBeans(bean); return bean; } private void injectApplicationContext(Object bean) { if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(appContext); } } public Class getClassInstance(String className) throws ClassNotFoundException { Class clazz = null; if (useClassCache) { synchronized(classes) { // this cache of classes is needed because Spring sucks at dealing with situations where the // class instance changes clazz = (Class) classes.get(className); } } if (clazz == null) { if (appContext.containsBean(className)) { clazz = appContext.getBean(className).getClass(); } else { clazz = super.getClassInstance(className); } if (useClassCache) { synchronized(classes) { classes.put(className, clazz); } } } return clazz; } /** * This method sets the ObjectFactory used by XWork to this object. It's best used as the "init-method" of a Spring * bean definition in order to hook Spring and XWork together properly (as an alternative to the * org.apache.struts2.spring.lifecycle.SpringObjectFactoryListener) * @deprecated Since 2.1 as it isn't necessary */ @Deprecated public void initObjectFactory() { // not necessary anymore } /** * Allows for ObjectFactory implementations that support * Actions without no-arg constructors. * * @return false */ @Override public boolean isNoArgConstructorRequired() { return false; } /** * Enable / disable caching of classes loaded by Spring. * * @param useClassCache */ public void setUseClassCache(boolean useClassCache) { this.useClassCache = useClassCache; } /** * Determines if the autowire strategy is always followed when creating beans * * @param alwaysRespectAutowireStrategy True if the strategy is always used */ public void setAlwaysRespectAutowireStrategy(boolean alwaysRespectAutowireStrategy) { this.alwaysRespectAutowireStrategy = alwaysRespectAutowireStrategy; } }
3. 带来的效果
struts中的Action, Inteceptor, Result, Converter, Validator的创建和装配交由Spring,struts自己创建的对象允许spring装配。4. 启动顺序
web容器、spring、struts三者的启动顺序,web容器(ServletContext)会最先启动,接着是spring,最后才是struts。从启动类型来看。web容器的启动依赖于web.xml,而xml中的配置加载顺序是context-param>listener>filter>servlet,context-param加载后会以KV形式set到web容器ServletContext中,所以web容器最先启动;接着是listener,spring 2.4以后只提供了listener方式整合web,因此接着启动的是spring;最后是通过filter实现拦截HTTP的struts。
从依赖关系来看。struts启动依赖于对象工厂,而struts的对象工厂依赖于spring的WebApplicationContext,而spring的WebApplicationContext的创建则依赖于ServletContext,因此最先启动的是web容器,接着是spring和struts。
5. 伪类名
action要交由spring创建和注入,则需要在struts中配置的时候起class属性采用伪类名,即applicationContext.xml中bean的属性id,否则是由struts自己创建action,但是是spring来装配。三、整合实现范例
如上所述,一句话struts整合spring,配置文件的参考范例如下,亲测无误。1. web.xml
<span style="font-family:Microsoft YaHei;"><?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>ss01</display-name> <!-- 1. context-param中的param会以KV的方式存入ServletContext 2. 如果applicationContext.xml没有放在默认路径/WEB-INF/applicationContext.xml(定义在XmlWebApplicationContext中), 则需要配置contextConfigLocation(定义在ContextLoader中) 3. 其value是配置文件applicationContext.xml的存放路径,如果不是web根目录下,则需要加classpath修饰 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 配置上下文加载侦听器:spring容器随着web容器的启动而加载 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- struts的侦听器:主要由init和doFilter完成,具体细节此处不再详谈 struts初始化以及HTTP预处理主要对象:Dispatcher, PrepareOperations, ExecuteOperations struts执行主要对象:ActionProxy, ActionInvocation, Action, Intecepter, Result struts数据流主要对象:ValueStack和ActionContext --> <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> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app></span>
2. applicationContext.xml
<span style="font-family:Microsoft YaHei;"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="loginAction" class="cn.wxy.action.LoginAction" scope="prototype" /> </beans></span>
3. struts.xml
<span style="font-family:Microsoft YaHei;"><?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="user" namespace="/user" extends="struts-default"> <action name="login" class="loginAction"> <result>/WEB-INF/jsp/succ.jsp</result> </action> </package> </struts></span>
附注:
本文如有错漏,烦请不吝指正,谢谢!
相关文章推荐
- 【Spring】Spring&WEB整合原理及源码剖析
- 深入剖析Spring Web源码(十五) - 处理器映射,处理器适配器以及处理器的实现 - 处理器的实现架构 - HTTP请求处理器
- 深入剖析Spring Web源码(十五) - 处理器映射,处理器适配器以及处理器的实现 - 处理器的实现架构 - HTTP请求处理器
- Spring 学习之路(十三): Spring 整合web以及struts2
- 深入剖析Spring Web源码(十二) - 处理器映射,处理器适配器以及处理器的实现 - 处理器适配器的实现架构
- 深入剖析Spring Web源码(十一) - 处理器映射,处理器适配器以及处理器的实现 - 处理器映射的实现架构
- 深入剖析Spring Web源码(九) - 处理器映射,处理器适配器以及处理器的实现 - 基于注解控制器流程的实现
- 深入剖析Spring Web源码(十一) - 处理器映射,处理器适配器以及处理器的实现 - 处理器映射的实现架构
- 深入剖析Spring Web源码(八) - 处理器映射,处理器适配器以及处理器的实现 - 基于简单控制器流程的实现
- 【Spring】Spring&WEB整合原理及源码分析
- 深入剖析Spring Web源码(十三) - 处理器映射,处理器适配器以及处理器的实现 - 处理器的实现架构 - 简单控制器
- Spring整合web项目原理以及IOC与DI关系
- 深入剖析Spring Web源码(十) - 处理器映射,处理器适配器以及处理器的实现 - 基于HTTP请求处理器流程的实现
- 深入剖析Spring Web源码(十六) - 处理器映射,处理器适配器以及处理器的实现 - 拦截器的实现架构
- Spring&WEB整合原理及源码分析
- 深入剖析Spring Web源码(十六) - 处理器映射,处理器适配器以及处理器的实现 - 拦截器的实现架构
- 深入剖析Spring Web源码(十四) - 处理器映射,处理器适配器以及处理器的实现 - 处理器的实现架构 - 注解控制器
- struts2拦截器的实现原理及源码剖析
- Struts2总结---拦截器的实现原理及源码剖析 (6)
- spring整合dwr架构(ftl+ssm)以及dwr.xml配置,原理,优缺点讲解,面试题总结