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

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

阅读更多

之前一朋友问我strut2和spring集成时使用aop后造成注入失败:关于struts2-spring整合的问题,我就分析一下struts2如果和spring集成的,并解决这个问题。

 

此问题已经提交到struts2的JIRA,2.3.16将修复;https://issues.apache.org/jira/browse/WW-4110

 

问题:

但是当我对action类加了spring-aop之后,写@resource不加getset方法的情况下又报错了,好像spring的注解又失效了,不知道这是为什么,请问您碰到过这种情况吗。

 

默认情况下,失败的情况只有两种:

当如<action name="myAction" class="cn.javass.MyAction">时,即没有交给spring管理:

1、 @Autowired   private Resource resource; 但无setter方法;

2、有setter方法,如setResource(),但无名字为resource的bean。

 

分析

首先介绍下struts2怎么去和spring集成的。

1、如果需要和spring集成,需要添加struts2-spring-plugin-***.jar,此处我们使用struts2-spring-plugin-2.3.1.1.jar;

 

2、接着struts2在启动时会按照如下顺序加载配置文件:

struts-default.xml 默认配置

struts-plugin.xml  插件配置(可以多个)

struts.xml 我们自己的

 

3、自动注册StrutsSpringObjectFactory为struts2的ObjectFactory,因此拿struts2的组件等都是问它要;

 

    <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" />

 

4、 StrutsSpringObjectFactory继承了com.opensymphony.xwork2.spring.SpringObjectFactory,主要做了几件事情:

4.1、获取ApplicationContext:servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

4.2、获取自动装配的机制,可以在struts.xml配置常量:struts.objectFactory.spring.autoWire,默认是name;这个可以参考http://jinnianshilongnian.iteye.com/blog/1415461,3.3.3 自动装配;

 

5、接下来如果要获取如action,需要:

 

    @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;
    }

5.1、首先查找spring容器有木有,如果有直接返回;

 

5.2、否则调用buildBean(beanClazz, extraContext);创建新的bean;即<action name="myAction" class="cn.javass.MyAction"> class配置的不是beanName时;

 

6、buildBean(beanClazz, extraContext);

 

    @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);
            }
        } catch (UnsatisfiedDependencyException e) {
            if (LOG.isErrorEnabled())
                LOG.error("Error building bean", e);
            // Fall back
            return autoWireBean(super.buildBean(clazz, extraContext), autoWiringFactory);
        }
    }

6.1、 如果是alwaysRespectAutowireStrategy,默认false,这个对于大家来说直接忽略,遗留策略,现在可以直接忽略。

6.2、正常情况会走到else中:

6.2.1、首先通过bean = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false)创建Bean;

6.2.2、执行Bean预处理:bean = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName()),此时可能发生@PostConstruct的初始化及一些Aware接口的注入;

6.2.2、执行Bean的后处理:bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName()),此时可能发生创建代理对象;

6.2.3、最后调用autoWireBean(bean, autoWiringFactory)装配对象,此时会调用org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory的populateBean完成,完成1、如果支持自动装配,会执行自动专配;2、如果有支持@Autowired注解,那么会调用InstantiationAwareBeanPostProcessor的postProcessPropertyValues;

 

如上的流程可以参考如下文章,有详细讲解:

Spring开闭原则的表现-BeanPostProcessor的扩展点-1

Spring开闭原则的表现-BeanPostProcessor扩展点-2 

 

 

 

但是getBean的流程是(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory):

 

1、InstantiationAwareBeanPostProcessor.applyBeanPostProcessorsBeforeInstantiation

2、InstantiationAwareBeanPostProcessor.applyBeanPostProcessorsAfterInitialization

如果此时有bean返回 直接返回;

3、doCreateBean

3.1、createBeanInstance

3.2、populateBean

3.2.1、InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation

3.2.2、autowire, for example AUTOWIRE_BY_NAME,AUTOWIRE_BY_TYPE

3.2.3、InstantiationAwareBeanPostProcessor.postProcessPropertyValues

3.2.4、applyPropertyValues

 

4、initializeBean

4.1、invokeAwareMethods

4.2、BeanPostProcessor.postProcessBeforeInitialization

4.3、invokeInitMethods

4.4、BeanPostProcessor.postProcessAfterInitialization

 

所以综上,SpringObjectFactory的实现是存在问题的,我给了一个正确的方式:

//1、instantiation
bean = autoWiringFactory.createBean(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);

//2、autowire
bean = autoWireBean(bean, autoWiringFactory);

//3、initialization
bean = autoWiringFactory.initializeBean(bean, bean.getClass().getName());

这才是正确的步骤。

 

如果按照struts2默认的实现,

bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());会执行创建代理,那么bean此时是代理对象;

 

那么接下来autoWireBean(bean, autoWiringFactory);会造成@Autowired   private Resource resource; 但无setter方法;注入失败。

 

到此分析完毕,已经提交struts2 jira:

https://issues.apache.org/jira/browse/WW-4110 

 

正确的SpringObjectFactory在附件中,请下载测试

3
3
分享到:
评论
8 楼 LinApex 2013-07-21  
jinnianshilongnian 写道
LinApex 写道
    <bean id="aspect" class="com.temp.common.advice.DaoMethodTimeAdvice"/>
    <aop:config>
        <aop:aspect ref="aspect">
            <aop:before method="before" pointcut="execution(* com.temp.web.action.*(..))"/>
        </aop:aspect>
    </aop:config>


1、详细的错误
2、配置文件
3、相关代码


没有错误,只是到 拦截  invocation.proceed(); 就出卡死,然后前台就跳转到一个空白页面... 这个比较神奇,我已经取消了 Action 层拦截了。。。下次再研究吧
7 楼 jinnianshilongnian 2013-07-21  
LinApex 写道
    <bean id="aspect" class="com.temp.common.advice.DaoMethodTimeAdvice"/>
    <aop:config>
        <aop:aspect ref="aspect">
            <aop:before method="before" pointcut="execution(* com.temp.web.action.*(..))"/>
        </aop:aspect>
    </aop:config>


1、详细的错误
2、配置文件
3、相关代码

6 楼 LinApex 2013-07-20  
    <bean id="aspect" class="com.temp.common.advice.DaoMethodTimeAdvice"/>
    <aop:config>
        <aop:aspect ref="aspect">
            <aop:before method="before" pointcut="execution(* com.temp.web.action.*(..))"/>
        </aop:aspect>
    </aop:config>
5 楼 LinApex 2013-07-20  
jinnianshilongnian 写道
LinApex 写道
Spring3.1.1 集成 Struts2 2.3.14.3 .
Spring 配置了以一个 拦截 struts2 Action 的 aop类,这个aop的拦截类的主要功能就是检查这个action的时间... 但是在请求 action 的时候,在aop这里就卡死了.. 然后报错。。不知道啥原因。

aop代码贴下 我先看看


aop 拦截器的代码:

package com.temp.common.advice;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

@Component(value = "ActionMethodTimeAdvice")
public final class ActionMethodTimeAdvice implements MethodInterceptor
{

private Logger logger = Logger.getLogger(this.getClass());

@Override
public Object invoke(MethodInvocation invocation) throws Throwable
{
StopWatch clock = new StopWatch();
clock.start();

Object result = invocation.proceed();

clock.stop();

// 方法参数类型,转换成简单类型
Class[] params = invocation.getMethod().getParameterTypes();
String[] simpleParams = new String[params.length];
for (int i = 0; i < params.length; i++)
{
simpleParams[i] = params[i].getSimpleName();
}
Object[] args = invocation.getArguments();

logger.info("Action execute Time:" + clock.getTime() + " ms [" + invocation.getThis().getClass().getName() + "." + invocation.getMethod().getName() + "(" + StringUtils.join(simpleParams, ",") + ")(" + StringUtils.join(args, ",") + ")] ");
return result;
}

}


Spring配置文件中的代码,与Dao层配置事务一样.对所有方法进行拦截.

4 楼 jinnianshilongnian 2013-06-22  
LinApex 写道
Spring3.1.1 集成 Struts2 2.3.14.3 .
Spring 配置了以一个 拦截 struts2 Action 的 aop类,这个aop的拦截类的主要功能就是检查这个action的时间... 但是在请求 action 的时候,在aop这里就卡死了.. 然后报错。。不知道啥原因。

aop代码贴下 我先看看
3 楼 LinApex 2013-06-22  
Spring3.1.1 集成 Struts2 2.3.14.3 .
Spring 配置了以一个 拦截 struts2 Action 的 aop类,这个aop的拦截类的主要功能就是检查这个action的时间... 但是在请求 action 的时候,在aop这里就卡死了.. 然后报错。。不知道啥原因。
2 楼 jinnianshilongnian 2013-06-20  
loveExtJs 写道
精彩!学习了,下来后再细读。

1 楼 loveExtJs 2013-06-20  
精彩!学习了,下来后再细读。

相关推荐

    struts2+hibernate+spring

    Struts2+Hibernate+Spring(SSH2)是Java开发领域中经典的三大开源框架组合,用于构建企业级的Web应用程序。这个组合提供了模型-视图-控制器(MVC)架构模式,持久层管理以及依赖注入等功能,极大地提高了开发效率和...

    struts2.3.8+spring3.2.1+hibernate4.2.0整合jar包

    Spring3.2.1在此基础上可能增强了对Java EE6的支持,改进了数据访问接口,如JDBC和Hibernate的集成,并且优化了配置方式,比如使用Java配置代替XML配置。Spring框架能够管理应用中的组件,提供事务控制、安全管理等...

    struts2+hibernate4+spring3+maven+easyui

    Struts2、Hibernate4、Spring3、Maven和EasyUI是Java Web开发中常见的开源框架和技术,它们在构建高效、可维护的Web应用程序时发挥着关键作用。下面将详细阐述这些技术及其整合应用。 1. **Struts2**: Struts2 是一...

    基于最新的SSH(Struts2.3.12+Spring3.2.2+Hibernate4.20)+ jquery EasyUI1.3.2的担保公司OA系统

    SSH是Struts2、Spring和Hibernate三个开源框架的缩写,它们在Java Web开发中被广泛使用。Struts2提供了MVC(Model-View-Controller)架构,Spring则作为应用容器处理依赖注入和事务管理,而Hibernate则是ORM(对象...

    ssh_jar包(struts2+spring3+hibernate3)

    SSH是三个流行开源框架的缩写,分别是Spring、Struts2和Hibernate,它们在Java Web开发中被广泛使用。这个“ssh_jar包”显然包含了这三个框架的核心库,供开发者在构建基于SSH的项目时使用。 **Spring框架**是Java...

    struts2.3.16 + hibernare4.3.4 + spring4.0.2整合jar包

    Struts2、Hibernate4和Spring4是Java Web开发中三个重要的框架,它们分别负责MVC模式中的Action层、持久化层和依赖注入。这个整合的jar包提供了这三大框架的协同工作环境,使得开发者能够更高效地构建企业级应用。 ...

    struts 2.3.7+spring3.2.0+MyBatis3.1

    Struts 2.3.7、Spring 3.2.0 和 MyBatis 3.1 是三个在Java企业级开发中广泛使用的开源框架,它们分别负责不同的职责,共同构建了一个强大的后端服务架构。 **Struts 2.3.7** 是一个基于MVC(Model-View-Controller...

    Eclipse搭建SSH(Struts2.5.10+Spring4.3.7+Hibernate5.2.9)Demo

    这个"Eclipse搭建SSH(Struts2.5.10+Spring4.3.7+Hibernate5.2.9)Demo"是一个实践教程,帮助开发者了解如何在Eclipse集成开发环境中配置和使用这三个框架的最新版本。下面将详细讲解SSH框架的组成部分以及它们之间的...

    开发Struts+Spring应用

    Struts和Spring是Java开发中两个非常重要的框架,它们在构建企业级Web应用程序时起着核心作用。Struts是MVC(模型-视图-控制器)架构的一个实现,主要用于处理前端请求和业务逻辑,而Spring则是一个全面的后端框架,...

    ssh Struts2.3.16.1+Hibernate4.3.4+Spring4.0.2 框架整合jar包

    SSH框架是Java开发中常用的三大开源框架Struts2、Hibernate和Spring的组合,它们各自负责应用程序的不同层面,共同构建了一个高效、灵活的企业级应用开发环境。这个SSH整合jar包是针对Struts2.3.16.1、Hibernate...

    struts2-spring-plugin-2.2.3.1.jar

    Struts2-Spring-Plugin-2.2.3.1.jar是Apache Struts框架与Spring框架集成的一个插件,主要用于帮助开发者在基于Struts2的应用程序中无缝地使用Spring进行依赖注入(Dependency Injection,DI)和控制反转(Inversion...

    博客系统(struts+hibernate+spring)130225.zip

    这个博客系统项目提供了一个学习和实践Java Web开发的平台,特别是对于理解Struts、Hibernate和Spring的集成使用具有很高的价值。通过这个项目,开发者可以深入掌握Java企业级应用的开发技巧,并为今后的复杂项目...

    网上订餐系统(struts+spring+hibernate).zip

    3. **编码实现**:使用Struts处理请求,Spring管理依赖,Hibernate操作数据库。 4. **测试**:单元测试、集成测试,确保各模块功能正常,无明显bug。 5. **部署**:将应用部署到服务器,进行线上环境的调试和优化。 ...

    Struts2 hibernate spring

    3. **AOP集成**:Spring的AOP功能可以用于日志记录、性能监控、安全控制等,例如,可以在Struts2的拦截器中利用AOP进行权限控制。 4. **数据源和SessionFactory管理**:Spring可以管理Hibernate的数据源和...

    Spring+Struts2 整合测试

    - 结合Struts2拦截器:使用Spring的AOP功能,可以创建自定义拦截器,增强Struts2的处理流程。 - 测试:编写测试用例,验证整合后的系统是否能正常工作,确保Action、Service和DAO层的交互无误。 4. **常见问题**...

    Struts2SpringUnitDemo单元测试

    Struts2SpringUnitDemo是一个示例项目,展示了如何在Java应用程序中将Struts2和Spring框架进行集成,并进行单元测试。这两个框架都是Java Web开发中的关键组件,Struts2负责控制层逻辑,Spring则提供了全面的依赖...

    hibernate-release-5.4.1.Final+struts-2.5.20+spring-framework-5.1.5.RELEASE

    综上所述,这个压缩包提供了一套完整的Java Web开发环境,集成了Hibernate、Struts 2和Spring Framework三个主流的开源框架。开发者可以利用这些工具来快速搭建应用,实现数据库操作、业务逻辑控制以及视图渲染等...

    Strus2+Spring 4 +Hibernate 所需全部jar包

    这些jar包可能包括Struts2的核心库、插件、Spring的上下文、AOP、Web模块以及Hibernate的主库、JPA支持、数据库驱动等。同时,你需要配置相关的XML文件,例如Struts2的struts.xml、Spring的applicationContext.xml和...

    Spring框架以及与Struts、Mybatis的整合

    Spring与Struts2、Mybatis整合后形成的SSM框架,是目前Java开发中广泛使用的一种架构模式。 **Spring框架基础** Spring框架主要由以下几个核心概念构成: 1. **控制反转(Inversion of Control,IoC)**:是一种...

Global site tag (gtag.js) - Google Analytics