`
jinnianshilongnian
  • 浏览: 21504297 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2418715
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:3008842
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5639514
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:259938
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1597350
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:250228
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5858977
Group-logo
跟我学Nginx+Lua开...
浏览量:702015
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:785233
社区版块
存档分类
最新评论

采用共享jar包部署struts2+spring集成项目会遇到的问题

阅读更多

比如tomcat下边有个lib,放着我们需要的struts2 + spring 集成jar包(一定要struts2和spring集成),即共享给所有webapp使用,如图:


此时tomcat启动时,会先加载a项目,再加载b项目(一定要是这个顺序才会出现问题,比如tomcat是通过list file顺序部署的)。(关于tomcat的classloader请参考:http://tomcat.apache.org/tomcat-6.0-doc/class-loader-howto.html

 

tomcat/lib下的jar包:

请参考附件 

 

a项目(WEB-INF/lib下没有jar包):

package cn.javass.a;
public class Project {
    private Integer id;
    //省略getter/setter
}

package cn.javass.a;
public class Deploment {
    private Project project;
    //省略getter/setter
}

 Deploment中包含了Project

 

struts2的action

package cn.javass.a;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

@Controller("myAction")
@Scope("prototype")
public class MyAction {

    private Deploment deploment;
    //省略getter/setter
   
    public String execute() {
        System.out.println("===a::::" + deploment.getProject().getClass());
        return "success";
    }
}

 

spring-config.xml只有一句,用来扫描注解bean:

    <context:component-scan base-package="cn.javass"/>    

 

struts.xml配置一个action(因为和spring集成了,所以会问spring要):

    <action name="myaction" class="myAction">
            <result>/WEB-INF/jsp/success.jsp</result>
    </action>

 

当我们请求url,如:localhost/a/myaction?deploment.project.id=1时,struts2会创建deploment,又因为project为null,所以默认也会创建project。

 

b项目(WEB-INF/lib下没有jar包):

和a项目类似,但是不同的是,Project同时也是一个bean才会出问题。

package cn.javass.b;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
 
@Component
@Scope("prototype")
public class Project {
    private Integer id;
    //省略getter/setter
}

 

即Project同时也是一个bean。其他的和a项目完全一样。

 

此时启动如tomcat服务器,一定注意要让tomcat先加载a项目,再加载b项目(目前测试默认就是),并开启如log4j日志,观察日志。

此时在地址栏输入:http://localhost/a/myaction?deploment.project.id=1  ,会得到

java.lang.NullPointerException
	cn.javass.a.MyAction.execute(MyAction.java:27)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method
…………

即deploment对象为null。然后看控制台输出日志,会看到

写道
org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'cn.javass.b.Project' to required type 'cn.javass.a.Project' for property 'project'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [cn.javass.b.Project] to required type [cn.javass.a.Project] for property 'project': no matching editors or conversion strategy found
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:463)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:494)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:488)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1433)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1392)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1128)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:376)
at com.opensymphony.xwork2.spring.SpringObjectFactory.autoWireBean(SpringObjectFactory.java:203)
at com.opensymphony.xwork2.spring.SpringObjectFactory.buildBean(SpringObjectFactory.java:183)
at com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler.createObject(InstantiatingNullHandler.java:161)
at com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler.nullPropertyValue(InstantiatingNullHandler.java:137)
at com.opensymphony.xwork2.ognl.OgnlNullHandlerWrapper.nullPropertyValue(OgnlNullHandlerWrapper.java:21)
at ognl.ASTProperty.getValueBody(ASTProperty.java:118)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.ASTChain.setValueBody(ASTChain.java:222)
at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:220)
at ognl.SimpleNode.setValue(SimpleNode.java:301)
at ognl.Ognl.setValue(Ognl.java:737)
at com.opensymphony.xwork2.ognl.OgnlUtil.setValue(OgnlUtil.java:234)
at com.opensymphony.xwork2.ognl.OgnlValueStack.trySetValue(OgnlValueStack.java:183)
at com.opensymphony.xwork2.ognl.OgnlValueStack.setValue(OgnlValueStack.java:170)
at com.opensymphony.xwork2.ognl.OgnlValueStack.setParameter(OgnlValueStack.java:148)  
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.setParameters(ParametersInterceptor.java:318)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:231)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)


…………………………

at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.IllegalStateException: Cannot convert value of type [cn.javass.b.Project] to required type [cn.javass.a.Project] for property 'project': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:264)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:448)
... 74 more
WARN-2013-11-28 22:58:03,656 - Error setting expression 'deploment.project.id' with value '[Ljava.lang.String;@8feeb'
ognl.OgnlException: source is null for getProperty(null, "project")
at ognl.OgnlRuntime.getProperty(OgnlRuntime.java:2310)
at ognl.ASTProperty.getValueBody(ASTProperty.java:114)
at ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at ognl.SimpleNode.getValue(SimpleNode.java:258)
at ognl.ASTChain.setValueBody(ASTChain.java:222)
at ognl.SimpleNode.evaluateSetValueBody(SimpleNode.java:220)
at ognl.SimpleNode.setValue(SimpleNode.java:301)
at ognl.Ognl.setValue(Ognl.java:737)
at com.opensymphony.xwork2.ognl.OgnlUtil.setValue(OgnlUtil.java:234)

……………………

ERROR-2013-11-28 22:58:03,656 - Exception occurred during processing request: null
java.lang.NullPointerException
at cn.javass.a.MyAction.execute(MyAction.java:27)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)
at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252)

 

1、struts2默认情况下发现project为null,会委托给相应的Null处理器处理,此处就是com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler,请看上边红色部分,此时会发现,它是这样处理的:

1.1、先委托给SpringObjectFactory,其又委托给spring容器去获取同名(project)的bean,但是此时会看到 获取了b项目中的Project,但是转型到a项目中的Project出错了。

1.2、如果从spring容器找不到同名的bean,会通过反射new一个(即如果不合spring容器集成也不会有问题,或者spring容器中没有名字为project的也没问题)。

 

怎么会找到b项目中的spring容器呢?接着分析。

 

分析:

1、InstantiatingNullHandler是由 ognl.ASTProperty.getValueBody(ASTProperty.java:118)处调用的,去跟踪下代码:

 

result = OgnlRuntime.getNullHandler(OgnlRuntime.getTargetClass(source)).nullPropertyValue(context, source, property);

 

 

2、此处先调用OgnlRuntime.getNullHandler(OgnlRuntime.getTargetClass(source))得到一个NullHandler;发现没有静态方法调用;

 

3、接着去看看OgnlRuntime,即根据传入的class类型,去到_nullHandlers中匹配合适的handler:

 public static NullHandler getNullHandler(Class cls)
            throws OgnlException
    {
        NullHandler answer = (NullHandler) getHandler(cls, _nullHandlers);
        if (answer != null)
            return answer;
        throw new OgnlException("No null handler for class " + cls);
    }

 

 

 4、_nullHandlers何时注册的呢?这个是问题的关键,通过查看源代码,会发现:

 public static void setNullHandler(Class cls, NullHandler handler)
    {
        synchronized (_nullHandlers) {
            _nullHandlers.put(cls, handler);
        }
    }

 

此处有一个setNullHandler方法,用于注册null handler的,而且一定注意是静态的。

 

5、谁调用这个注册的呢?debug跟踪代码会发现是struts2在启动时的那个Filter(StrutsPrepareAndExecuteFilter)调用的。

 

6、分析:

6.1、类变量(静态变量)是一个类装载器一份,此处因为我们把jar包放在tomcat/lib下,所以整个web应用(a项目和b项目都能拿到这个,且俩人拿到的都是同一个)只有一份

6.2、因为a项目启动时调用会调用setNullHandler注册null handler,而接着b项目也会启动注册,又因为6.1所以呢,只有最后一个项目注册的有效(后边的覆盖前面的)

6.3、启动时debug的图:

6.3.1、a项目启动时注册的handler,该handler有a项目的spring容器引用(里边没有project bean的):


 

6.3.2、b项目启动时注册的handler,该handler有b项目的spring容器引用(里边有project bean的):

 

6.3.4、所以呢最后一个项目的null handler有效。就造成了之前的问题。

 

所以解决办法就是不能共享这些jar包。或者保证spring容器中没有同名的bean。。

 

示例项目源码请在附件中下载。建议下载源码跟踪一下。

 

另一个类似的bug:

struts2+spring集成bug——使用AOP时可能遇到的问题分析

5
2
分享到:
评论
6 楼 戈登哥 2013-11-29  
jinnianshilongnian 写道
戈登哥 写道
分析的不错.能够深入研究很值得佩服.

谢谢 

哥们 有意向来我们这里不.
5 楼 jinnianshilongnian 2013-11-29  
戈登哥 写道
分析的不错.能够深入研究很值得佩服.

谢谢 
4 楼 戈登哥 2013-11-29  
分析的不错.能够深入研究很值得佩服.
3 楼 jinnianshilongnian 2013-11-29  
如果非要共享 可以实现自己的null handler
2 楼 jinnianshilongnian 2013-11-29  
lengyun3566 写道
分析得够细致 不错

昨天晚上一朋友遇到的问题,想了想差不多就是这个问题,晚上回去debug了下 果然是
1 楼 lengyun3566 2013-11-29  
分析得够细致 不错

相关推荐

    STRUTS2+SPRING+IBATIS搭建的Demo实例

    总结来说,这个"STRUTS2+SPRING+IBATIS搭建的Demo实例"是一个很好的学习资料,它帮助开发者理解并实践如何在Java Web开发中有效地集成这三个框架,实现MVC架构,以及如何利用自动装配功能简化配置和提高代码的可维护...

    图解SSH(struts2,spring,hibernate)框架配置步骤

    在项目中引入 `struts2-spring-plugin-2.1.6.jar`,这个插件允许 Struts2 与 Spring 无缝集成。 **步骤2:配置 web.xml** 在 `web.xml` 中添加 `ContextLoaderListener`,以便启动 Spring 的上下文加载器,代码如下...

    struts2.5.1.1 jar包

    为了部署和运行一个基于Struts2的Web应用,开发者需要将上述jar包放入项目的类路径中,例如WEB-INF/lib目录下,然后在web.xml中配置Struts2的前端控制器DispatcherServlet。同时,还需要创建相应的struts.xml或...

    web开发常用jar包

    2.2 框架依赖:许多Web开发框架,如Spring、Struts、Hibernate等,其核心功能都封装在`jar`包中。开发者通过引入这些`jar`包,可以快速构建Web应用。 2.3 第三方库:许多开源项目提供了`jar`包形式的API,如Apache ...

    aisx2用到的jar

    在本案例中,"aisx2用到的jar"指的是一个项目或应用"AIX2"所依赖的一系列`JAR`库。这些库可能包含了实现特定功能、服务或者API的类和资源,是构建和运行"AIX2"不可或缺的部分。下面我们将深入探讨`JAR`文件以及它们...

    最新ssh的jar整合项目

    在"common"目录下,通常会包含这些共享的库文件,例如第三方jar包或者自定义的工具类。"cfg"目录可能包含了项目的配置文件,如Spring的bean配置文件(applicationContext.xml)、Struts的配置文件(struts.xml)和...

    Maven简介_SSH整合教程

    1. **依赖管理**:Maven通过pom.xml文件自动下载并管理项目所需的所有依赖库,避免了手动添加jar包的麻烦。 2. **构建工具**:Maven支持多种生命周期阶段,如编译、测试、打包、验证、部署等,使得构建过程规范化。...

    JavaStruts.rar

    7. **插件和扩展性**:Struts2有一个强大的插件系统,可以方便地集成其他框架,如Hibernate、Spring等。 在这个"JavaStruts.rar"的压缩包中,你可能找到了以下组件: 1. **Action类**:包含实现特定业务逻辑的Java...

    Spring-Reference_zh_CN(Spring中文参考手册)

    Jar包 2.7.1.2. XML配置 2.7.1.3. Deprecated的类和方法 2.7.1.4. Apache OJB 2.7.1.5. iBatis 2.8. 更新的样例应用 2.9. 改进的文档 I. 核心技术 3. 控制反转容器 3.1. 简介 3.2. 容器和bean的基本原理 3.2.1. ...

    java开发jar汇总

    开发者可以根据实际需求,选择相应的JAR包引入到项目中,大大提高了开发效率。 总之,这个“java开发jar汇总”是Java开发者宝贵的资源库,涵盖了开发中常见的框架、数据库驱动和其他实用工具,是快速开发和调试的...

    ibatis jsp servlet 的网上书城项目

    4. `lib`: 项目依赖的JAR库文件,如SSH框架的JAR包和数据库驱动。 5. `resources`: 配置文件和其他资源,如SQL脚本、日志配置等。 6. `WEB-INF/classes`: 编译后的Java类文件。 这个项目可以作为学习Java Web开发...

    dwrTest.rar_dwr 3 jar_dwr jar_dwr2.0 jar

    4. **更好的集成性**:DWR 3.x 对各种Web框架(如Spring、Struts等)的集成更加友好,提供了更多的配置选项和插件支持。 5. **自动刷新**:DWR 3.x 改进了自动刷新功能,使得调试和开发过程中实时查看代码变更变得...

    ssh整合jbpm所需要的几个包

    2. **集成Struts**:在Struts的Action中,可以调用Spring管理的JBPM服务,启动、暂停、继续或结束流程实例,以及处理任务分配。 3. **利用Hibernate**:由于JBPM也涉及到数据库操作,可能需要与Hibernate一起工作,...

    ssh+jbpm整合.doc

    整合SSH和JBPM的过程中,可能会遇到以下关键问题: 1. **数据库Session不一致**:JBPM默认使用的Session与现有的Hibernate Session不一致,需要统一。 2. **大字段处理**:处理字符串类型的Max字段,避免数据溢出或...

    新建文件夹 (2).rar

    在OA系统中,Spring可以管理各种组件的生命周期,如数据库连接池、事务管理、以及与Struts和Hibernate的集成。 Struts是MVC(Model-View-Controller)架构的实现,负责处理HTTP请求并调度业务逻辑。在在线办公系统...

    lib.zip(有自定义的mvc,封装了sql语句)

    在实际应用中,开发者会将lib.zip解压,将其中的jar包添加到项目的类路径(Classpath)中,以便在编译和运行时能够正确地加载和执行这些自定义MVC框架的类。如果这些jar包包含了数据库操作相关的代码,那么可能还...

    基于JSP+MySQL的小型商城系统

    Spring则是一个全面的Java应用框架,提供依赖注入、事务管理等功能,可与其他框架如Struts2集成;Hibernate是Java持久层的一个ORM(对象关系映射)框架,使得开发者可以通过Java对象直接操作数据库,而无需编写SQL...

Global site tag (gtag.js) - Google Analytics