`
499490717
  • 浏览: 39799 次
  • 性别: 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+Spring3+MyBatis3完整实例

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

    autowiring, 一种 C 控制框架.zip

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

    autowiring:依赖注入和自动装配

    自动装配一个简单的自动装配工具,用于在 node.js 上进行依赖注入。

    demo-autowiring:Symfony自动接线演示

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

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

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

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

    Spring中文帮助文档

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器(ViewResolver) 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. ...

    Spring API

    13.4.3. 拦截器(HandlerInterceptor) 13.5. 视图与视图解析 13.5.1. 视图解析器(ViewResolver) 13.5.2. 视图解析链 13.5.3. 重定向(Rediret)到另一个视图 13.6. 本地化解析器 13.6.1. ...

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

    自动接线错误引导 带有有限泛型的服务的Spring Boot自动装配问题

    spring自动装配例子

    (2)byName:根据属性 名 自动装配,设值注入 &lt;bean id="xxx" class="xxx" &gt;&lt;/bean&gt; (3)byType:根据属性 类型 自动装配,相同类型多个会抛出异常,设值注入 &lt;bean class="xxx" &gt;&lt;/bean&gt; (4)constructor:与 ...

    autowiring:将电路 CAD 上的自动布线构建导出到 svg(可缩放矢量图形)

    自动布线 将电路 CAD 上的自动布线构建导出到 svg(可缩放矢量图形) ##例子## ##参考##

    ControllerAutowire:[不推荐使用]从Symfony 3.3开始默认使用控制器自动装配

    2.为他们启用构造函数自动装配 还在想为什么将控制器用作服务? 检查和文章。 安装 composer require symplify/controller-autowire 将捆绑包添加到AppKernel.php : class AppKernel extends Kernel { public ...

    Spring常用的7大注解详解代码分析.docx

    1、核心注解 @Required 此注解用于bean的setter方法上。...根据type来autowiring。 当在field上使用此注解,并且使用属性来传递值时,Spring会自动把值赋给此field。也可以将此注解用于私有属性(不推荐),如下。

    EWALectureNotes:幻灯片和讲座笔记Hacettepe大学的企业Web体系结构讲座的笔记

    spring-annotation-based-autowiring:基于Spring注释的自动装配bean spring-autowiring-constructor:构造函数注入自动装配 spring-bean-definition-override:使用多个Spring配置覆盖bean定义 spring-bean-...

    Just.Spring.Jul.2011

    Dive into containers and other advanced concepts, such as event handling and autowiring beans Discover how Spring makes the Java Messaging Service API easier to use Learn how Spring has ...

    JdonFramework开源框架 v6.6.zip

     JF诞生于2004年底,作为中国第一个开源框架,创新地运用了当时刚刚出现的新的技术思想Ioc/DI(依赖注射Dependency Injection),JF是一个支持autowiring的DI框架;同时遵循约定优于配置(Convention Over ...

    基于框架的Web开发-装配Bean自动装配.doc

    自动装配(autowiring):Spring自动满足bean之间的依赖。 1 使用@Component定义bean 在类声明的前面使用@Component对类进行标注,这个类可以被spring容器识别,spring容器将类转换为容器管理的bean。 项目分层之后...

    lti-launch:Java框架,用于验证来自Canvas LMS的LTI启动请求

    它提供了对LTI启动请求的OAuth签名进行身份验证的功能,并在需要与Canvas API通信时处理OAuth 2用户令牌交换。 在验证启动请求之后,将用户转发到由实现的应用程序指定的初始视图。 使用的技术 Java 8 Maven(与...

    JdonFramework开源框架 v6.6

    JF诞生于2004年底,作为中国第一个开源框架,创新地运用了当时刚刚出现的新的技术思想Ioc/DI(依赖注射Dependency Injection),JF是一个支持autowiring的DI框架;同时遵循约定优于配置(Convention Over ...

    SpJBuilder2006新功能赏析

    适当地利用其中的选项可以使XML配置清晰,但是,有些选项,例如autowiring(自动绑定),往往会降低易读性和易维护性。文章中所列举的实例,可以帮助你创建出清晰易读的XML配置文件。 近两年来JavaIDE的市场异常...

Global site tag (gtag.js) - Google Analytics