`
499490717
  • 浏览: 40196 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

struts2默认拦截器之autowiring

阅读更多

   在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默认拦截器解析.pdf

    默认情况下,Struts2提供了一系列内置的拦截器,这些拦截器已经配置在`struts-default.xml`文件中,以便开发者可以直接使用或进行自定义组合。 首先,让我们逐一了解这些默认拦截器的功能: 1. **alias**:别名...

    Struts2的拦截器

    Struts2默认提供了一系列内置拦截器,每种拦截器都有其特定的功能: 1. **alias**:别名拦截器,主要用于简化不同Action间参数的共享,特别是当需要在不同Action间传递同名但不同作用域的参数时,可以通过`aliases`...

    struts-default中拦截器介绍.pdf

    Struts 2 框架中的拦截器是其核心组件之一,主要负责在Action执行前后进行额外的操作,如参数绑定、验证、权限控制等。在`struts-default`配置中,许多默认的拦截器组合成预设的拦截器栈,为开发者提供了便捷的功能...

    Struts2配置详解

    在上面的示例中,可以看到`&lt;package&gt;`节点定义了默认的结果类型(如dispatcher、redirect等)以及基本的拦截器栈(如`basicStack`)。这些定义为整个应用程序提供了一套基础的行为模式。 #### 五、参考文档 对于更...

    struts学习笔记

    Struts框架的拦截器是其核心特性之一,用于处理Action执行前后的各种逻辑,如权限检查、日志记录等。拦截器可以单独定义,也可以组合成拦截器栈来按顺序执行多个拦截器。 1. **定义拦截器**:通过`&lt;interceptor&gt;`...

    旺旺教师————Struts2

    - Struts2 支持拦截器模型,这使得开发者可以更容易地扩展框架功能。 - Struts2 还支持多种不同的视图技术,包括但不限于JSP、FreeMarker等。 #### 四、Struts2 的整合原理 **整合原理** 指的是将Struts2与其他框架...

    Spring注解配置中间层供Struts2使用

    这可能意味着我们正在使用Spring的自动装配(Autowiring)特性,让Spring处理Bean之间的依赖关系,而不是通过Struts2的配置。Spring的自动装配可以通过`@Autowired`注解实现,例如: ```java @Service(...

    Struts2+Spring3+MyBatis3完整实例

    网上的东西好大多都不能直接用,自己结合网上资料做了一个Struts2+Spring3+MyBatis3的测试工程,JUnit测试用例和WEB服务。 内涵完整jar包,解压直接可用,包括一个表文件。 Eclipse3.2+Tomcat/5.5+jdk1.5.0_17 - ...

    Struts2.3+Spring3.2的整合

    Struts2.3作为一款流行的MVC框架,提供了丰富的标签库和拦截器机制,而Spring3.2则以其强大的依赖注入和面向切面编程能力著称。两者的结合,可以实现业务逻辑和控制层的分离,同时利用Spring的AOP和DI特性增强代码的...

    autowiring, 一种 C 控制框架.zip

    autowiring, 一种 C 控制框架 命令行目自动装配是一个用于C 11的inversion-of-control 框架。 它提供了一种通过依赖注入插件来管理资源的声明性方法。 而不是显式地实例化依赖关系,仅仅声明需要的内容,自动装配将...

    autowiring:依赖注入和自动装配

    2. **配置**:然后,定义你的服务(即包含依赖的对象)和它们的依赖。这些可以通过类或函数的形式表示,类的构造函数或函数的参数会表明它们需要哪些依赖。 3. **注册**:将你的服务和依赖注册到"autowiring"容器中...

    spring相关的demo,包含spring的ioc注入,aop的使用,mybatis的整合(1).zip

    "16spring4_struts2_mybatis"和"17ssm_annotation"是关于Spring、Struts2和MyBatis三者集成的项目。Struts2是一个流行的MVC框架,它与Spring和MyBatis结合可以构建出强大的企业级应用。这两个例子将演示如何配置...

    demo-autowiring:Symfony自动接线演示

    欢迎使用Symfony标准版-一个功能齐全的Symfony2应用程序,您可以将其用作新应用程序的框架。 有关如何下载和开始使用Symfony的详细信息,请参见Symfony文档的“一章。 里面有什么? Symfony Standard Edition配置...

    autowiring-bug-boot:带有有限泛型的服务的Spring Boot自动装配问题

    在Spring Boot应用中,自动装配(Autowiring)是一种便捷的依赖注入机制,它允许Spring框架自动为bean提供所需的依赖。然而,当涉及到有限泛型的服务时,可能会遇到一些问题,这正是“autowiring-bug-boot”所指出的...

    spring chm文档

    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....

    EJB3.0学习心得

    - **拦截器**: EJB 3.0 支持在方法调用前后执行拦截器,用于处理日志记录、性能监控等通用任务。 **6. 集成与测试** - **工具支持**: Eclipse、MyEclipse 和 NetBeans 等 IDE 提供了对 EJB 3.0 的良好支持,使得...

    autowiring-benchmark:SPR-13086 的基准应用程序

    模式 2 @Inject + @Named (byName) 模式 3 @Autowired (byType) 模式 4 @Autowired + @Qualifier (byName) 模式 5 @Resource (byName) 如何测量 运行脚本。 $ sh run.sh N 这个基准测试应用程序有 N 个...

Global site tag (gtag.js) - Google Analytics