在struts2的struts-default.xml中定义了一个name为autowiring拦截器,实现类是com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor,它的作用是在struts2和spring整合时为action注入spring上下文ApplicationContext(Action需要实现org.springframework.context.ApplicationContextAware接口),并使用com.opensymphony.xwork2.inject.Container对象为action注入其他属性。
首先说明一下struts2与spring的整合。
要实现struts2与spring的整合,只需将struts2-spring-plugin-2.x.x.jar加入到项目中即可。在该jar包中存在文件struts-plugin.xml,在struts2启动时会被加载,文件内容如下:
<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>
这里它将struts2框架常量struts.objectFactory设置为"spring",这里其实是使用了缩写形式,全称是"org.apache.struts2.spring.StrutsSpringObjectFactory"。这个缩写的"spring"是和bean配置中的name属性相对应的。默认情况下struts2框架创建的对象都是由ObjectFactory实例化的,ObjectFactory提供了与其他IoC容器(如Spring等)集成的方法。覆盖这个ObjectFactory的类必须继承ObjectFactory类或者它的任何子类,并且带有一个无参构造方法或者构造方法中的参数全部使用struts2的@Inject注解。上述代码使用org.apache.struts2.spring.StrutsSpringObjectFactory代替了默认的ObjectFactory。该ObjectFactory使得struts2中的bean可以由spring来装配,默认情况下框架使用的自动装配策略是name,也就是说框架会根据spring中bean的name属性自动装配,可选的装配策略还有type、auto、constructor,我们可以根据常量struts.objectFactory.spring.autoWire来进行设置。
在struts2与spring进行整合的时候还需要在web.xml中添加如下信息来启动spring:
<listener> <listener-class >org.springframework.web.context.ContextLoaderListener</listener-class > </listener>
但如果没有配置这个会出现什么情况呢?如果未配置上述代码,启动web服务器会出现如下错误FATAL 2011-12-28 11:53:34:272 - ********** FATAL ERROR STARTING UP
STRUTS-SPRING INTEGRATION ********** Looks like the Spring listener was not configured for your web app! Nothing will work until WebApplicationContextUtils returns a valid ApplicationContext. You might need to add the following to web.xml: <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> ERROR 2011-12-28 11:53:34:288 - Dispatcher initialization failed java.lang.NullPointerException at com.opensymphony.xwork2.spring.SpringObjectFactory.getClassInstance(SpringObjectFactory.java:220) …………
错误中显示是出现了NullPointerException(SpringObjectFactory.java:220), 出现该异常的代码是:
if(appContext.containsBean(className))
此处的appContext是org.springframework.context.ApplicationContext,说明在SpringObjectFactory类(StrutsSpringObjectFactory的直接父类)中需要存在org.springframework.context.ApplicationContext对象的引用,此处的 ApplicationContext需要什么时候进行装配呢?在StrutsSpringObjectFactory类中只存在一个构造方法
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); LOG.info("Initializing Struts-Spring integration..."); 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; } 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)); 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(); } this.setApplicationContext(appContext); 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)); LOG.info("... initialized Struts-Spring integration successfully"); } }
在上述代码中从servletContext中取到一个名称为"org.springframework.web.context.WebApplicationContext.ROOT"的属性值,将其强制转换为ApplicationContext类型,之后调用SpringObjectFactory类setApplicationContext方法将spring上下文传递给了SpringObjectFactory。spring上下文是什么时候放置到servletContext中的呢?我们接下来看一下org.springframework.web.context.ContextLoaderListener类,这个监听器到底做了什么? 我们知道ContextLoaderListener是在服务器初始化的时候执行contextInitialized这个方法,该方法的代码如下:
public void contextInitialized(ServletContextEvent event) { this.contextLoader = createContextLoader(); this.contextLoader.initWebApplicationContext(event.getServletContext()); }
可以看出主要起作用的应该是initWebApplicationContext方法,初始化WebApplicationContext,我们进去看看:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) throws IllegalStateException, BeansException { if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) { throw new IllegalStateException( "Cannot initialize context because there is already a root application context present - " + "check whether you have multiple ContextLoader* definitions in your web.xml!"); } servletContext.log("Initializing Spring root WebApplicationContext"); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); } long startTime = System.currentTimeMillis(); try { // Determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. this.context = createWebApplicationContext(servletContext, parent); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context); if (logger.isDebugEnabled()) { logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]"); } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms"); } return this.context; } catch (RuntimeException ex) { logger.error("Context initialization failed", ex); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex); throw ex; } catch (Error err) { logger.error("Context initialization failed", err); servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err); throw err; } }
上面代码,将spring上下文放置到了servletContext中,因此只要通过org.springframework.web.context.ContextLoaderListener类启动了spring,那么在struts2中通过servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)或者ActionContext.getContext().getApplication().get(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)就能取到spring上下文对象
spring把ApplicationContext放在application里面,然后struts2在application中把这个对象取出来,放在SpringObjectFactory里面,然后struts2与spring就实现了集成,当我们没有在web.xml里面配置监听器,也就是没有把ApplicationContext的对象放在application里面,所以struts2去application里面去取的时候会是null,这就是为什么没有配置监听器那里会抛NullPointerException异常。
当struts2和spring集成之后,struts2将允许Spring创建Action、Interceptror和Result,并且由Struts创建的对象能够被Spring装配。这样就可以在配置action时不使用类名,而使用spring中bean的name值了。如果在spring中找不到与Action的class值相匹配的bean,struts2框架会根据class值初始化一个action对象,并对action对象进行装配。
其实SpringObjectFactory已经对Action对象注入了ApplicationContext和其他struts2对象,那么autowiring拦截器岂不是没用了?有一种情况,当项目中同时使用了Struts2和spring,但未将struts.objectFactory的值设置为"spring",即Struts2的objectFactory还是默认的ObjectFactory类,这样action中就不会被注入spring的上下文对象,就需要使用autowiring拦截器了。autowiring拦截器会从application中获取到spring上下文对象,初始化一个SpringObjectFactory对象,使用该对象对Action对象进行装配。
版权所有,转载请标明出处:http://blogwarning.iteye.com/blog/1332214
发表评论
-
struts2默认拦截器之chain
2012-05-08 22:32 988在struts2的struts-default.xml中定义了 ... -
struts2默认拦截器之prepare
2012-02-02 11:26 8274在struts2的struts-default.xml中定义 ... -
struts2默认拦截器之i18n
2012-01-17 17:02 5271在struts2的struts-default.xml中定义 ... -
struts2默认拦截器之servletConfig
2012-01-06 11:46 2473在struts2的struts-default.xml中定义 ... -
struts2默认拦截器之exception
2012-01-04 11:26 5976在struts2的struts-default.xml ... -
struts2默认拦截器之alias
2011-12-31 16:17 3347在struts2的struts- ...
相关推荐
默认情况下,Struts2提供了一系列内置的拦截器,这些拦截器已经配置在`struts-default.xml`文件中,以便开发者可以直接使用或进行自定义组合。 首先,让我们逐一了解这些默认拦截器的功能: 1. **alias**:别名...
Struts2默认提供了一系列内置拦截器,每种拦截器都有其特定的功能: 1. **alias**:别名拦截器,主要用于简化不同Action间参数的共享,特别是当需要在不同Action间传递同名但不同作用域的参数时,可以通过`aliases`...
Struts 2 框架中的拦截器是其核心组件之一,主要负责在Action执行前后进行额外的操作,如参数绑定、验证、权限控制等。在`struts-default`配置中,许多默认的拦截器组合成预设的拦截器栈,为开发者提供了便捷的功能...
在上面的示例中,可以看到`<package>`节点定义了默认的结果类型(如dispatcher、redirect等)以及基本的拦截器栈(如`basicStack`)。这些定义为整个应用程序提供了一套基础的行为模式。 #### 五、参考文档 对于更...
Struts框架的拦截器是其核心特性之一,用于处理Action执行前后的各种逻辑,如权限检查、日志记录等。拦截器可以单独定义,也可以组合成拦截器栈来按顺序执行多个拦截器。 1. **定义拦截器**:通过`<interceptor>`...
- Struts2 支持拦截器模型,这使得开发者可以更容易地扩展框架功能。 - Struts2 还支持多种不同的视图技术,包括但不限于JSP、FreeMarker等。 #### 四、Struts2 的整合原理 **整合原理** 指的是将Struts2与其他框架...
这可能意味着我们正在使用Spring的自动装配(Autowiring)特性,让Spring处理Bean之间的依赖关系,而不是通过Struts2的配置。Spring的自动装配可以通过`@Autowired`注解实现,例如: ```java @Service(...
网上的东西好大多都不能直接用,自己结合网上资料做了一个Struts2+Spring3+MyBatis3的测试工程,JUnit测试用例和WEB服务。 内涵完整jar包,解压直接可用,包括一个表文件。 Eclipse3.2+Tomcat/5.5+jdk1.5.0_17 - ...
Struts2.3作为一款流行的MVC框架,提供了丰富的标签库和拦截器机制,而Spring3.2则以其强大的依赖注入和面向切面编程能力著称。两者的结合,可以实现业务逻辑和控制层的分离,同时利用Spring的AOP和DI特性增强代码的...
autowiring, 一种 C 控制框架 命令行目自动装配是一个用于C 11的inversion-of-control 框架。 它提供了一种通过依赖注入插件来管理资源的声明性方法。 而不是显式地实例化依赖关系,仅仅声明需要的内容,自动装配将...
2. **配置**:然后,定义你的服务(即包含依赖的对象)和它们的依赖。这些可以通过类或函数的形式表示,类的构造函数或函数的参数会表明它们需要哪些依赖。 3. **注册**:将你的服务和依赖注册到"autowiring"容器中...
"16spring4_struts2_mybatis"和"17ssm_annotation"是关于Spring、Struts2和MyBatis三者集成的项目。Struts2是一个流行的MVC框架,它与Spring和MyBatis结合可以构建出强大的企业级应用。这两个例子将演示如何配置...
2. 在偏好设置中,依次选择“Editor” -> “Inspections” -> “Spring” -> “Spring Core” -> “Code” -> “Autowiring for bean class”。 3. 将“Error”级别修改为“Warning”级别,这样IDEA将会把@Autowired...
欢迎使用Symfony标准版-一个功能齐全的Symfony2应用程序,您可以将其用作新应用程序的框架。 有关如何下载和开始使用Symfony的详细信息,请参见Symfony文档的“一章。 里面有什么? Symfony Standard Edition配置...
在Spring Boot应用中,自动装配(Autowiring)是一种便捷的依赖注入机制,它允许Spring框架自动为bean提供所需的依赖。然而,当涉及到有限泛型的服务时,可能会遇到一些问题,这正是“autowiring-bug-boot”所指出的...
13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. AcceptHeaderLocaleResolver 13.6.2....
- **拦截器**: EJB 3.0 支持在方法调用前后执行拦截器,用于处理日志记录、性能监控等通用任务。 **6. 集成与测试** - **工具支持**: Eclipse、MyEclipse 和 NetBeans 等 IDE 提供了对 EJB 3.0 的良好支持,使得...