Struts2中的依赖注入访问会话范围的Bean

时间:2013-06-21 20:45:42

标签: java struts2 dependency-injection session-scope scope-strategy

最近我需要在Struts2中使用DI。我知道它使用它自己的DI实现,如Guice但不使用Guice,因为我找不到一些适合设置注入bean范围的注释。简而言之,我创建了一个bean

//@Repository
//@Scope("session")
public class Session {

    private Map<String, Object> map = new HashMap<>();

    public Map<String, Object> getMap() {
        return map;
    }

    public void setMap(Map<String, Object> map) {
        this.map = map;
    }
}

我评论过使用Spring bean的注释。我通过spring DI成功创建了相同的bean,并设置了我的对象注入的范围。现在,我想对Struts2和DI做同样的事情。为此,我在struts.xml

中创建了bean定义
<bean name="session" class="jspbean.struts.Session" scope="session"/>

以及创建该bean并将其注入我的操作的简单操作

public class DefaultAction extends ActionSupport {

    private Session session;

    //  @Autowired
    @Inject("session")
    public void setSession(Session session) {
        this.session = session;
    }

    public Session getSession() {
        return session;
    }

    private Map<String, String> myMap = new HashMap<String, String>();

    public Map<String, String> getMyMap() {
        return myMap;
    }

    public void setMyMap(Map<String, String> myMap) {
        this.myMap = myMap;
    }

    @Override
    public String execute() throws Exception {
        //populate my bean with sample data
        myMap.put("q1", "Question1");
        myMap.put("q2", "Question2");
        session.getMap().put("myMap", myMap);
        return SUCCESS;
    }
}
在JSP中我使用简单的迭代器而不是会话bean

<s:iterator value="session.map['myMap']">
  <s:textfield name="myMap['%{key}']" value="%{value}" theme="simple" size="10" /><br>
</s:iterator>

现在,当我运行这个简单的应用程序时,我得到了异常

Stacktraces
Unable to instantiate Action, jspbean.struts.DefaultAction, defined for '' in namespace '/'java.lang.IllegalStateException: Scope strategy not set. Please call Container.setScopeStrategy().

    com.opensymphony.xwork2.DefaultActionInvocation.createAction(DefaultActionInvocation.java:316)
    com.opensymphony.xwork2.DefaultActionInvocation.init(DefaultActionInvocation.java:397)
    com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:194)
    org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:63)
    org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39)
    com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:58)
    org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:536)
    org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
    org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)


java.lang.RuntimeException: java.lang.IllegalStateException: Scope strategy not set. Please call Container.setScopeStrategy().

    com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:301)
    com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:492)
    com.opensymphony.xwork2.inject.ContainerImpl$6.call(ContainerImpl.java:530)
    com.opensymphony.xwork2.inject.ContainerImpl$6.call(ContainerImpl.java:528)
    com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:584)
    com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:528)
    com.opensymphony.xwork2.ObjectFactory.injectInternalBeans(ObjectFactory.java:139)
    com.opensymphony.xwork2.spring.SpringObjectFactory.autoWireBean(SpringObjectFactory.java:208)
    com.opensymphony.xwork2.spring.SpringObjectFactory.buildBean(SpringObjectFactory.java:183)
    com.opensymphony.xwork2.spring.SpringObjectFactory.buildBean(SpringObjectFactory.java:154)
    com.opensymphony.xwork2.ObjectFactory.buildBean(ObjectFactory.java:151)
    com.opensymphony.xwork2.ObjectFactory.buildAction(ObjectFactory.java:121)
    com.opensymphony.xwork2.DefaultActionInvocation.createAction(DefaultActionInvocation.java:297)
    com.opensymphony.xwork2.DefaultActionInvocation.init(DefaultActionInvocation.java:397)
    com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:194)
    org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:63)
    org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39)
    com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:58)
    org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:536)
    org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
    org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)


java.lang.IllegalStateException: Scope strategy not set. Please call Container.setScopeStrategy().

    com.opensymphony.xwork2.inject.InternalContext.getScopeStrategy(InternalContext.java:53)
    com.opensymphony.xwork2.inject.Scope$5$1.create(Scope.java:130)
    com.opensymphony.xwork2.inject.ContainerImpl$ParameterInjector.inject(ContainerImpl.java:469)
    com.opensymphony.xwork2.inject.ContainerImpl.getParameters(ContainerImpl.java:484)
    com.opensymphony.xwork2.inject.ContainerImpl.access$000(ContainerImpl.java:34)
    com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:299)
    com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:492)
    com.opensymphony.xwork2.inject.ContainerImpl$6.call(ContainerImpl.java:530)
    com.opensymphony.xwork2.inject.ContainerImpl$6.call(ContainerImpl.java:528)
    com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:584)
    com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:528)
    com.opensymphony.xwork2.ObjectFactory.injectInternalBeans(ObjectFactory.java:139)
    com.opensymphony.xwork2.spring.SpringObjectFactory.autoWireBean(SpringObjectFactory.java:208)
    com.opensymphony.xwork2.spring.SpringObjectFactory.buildBean(SpringObjectFactory.java:183)
    com.opensymphony.xwork2.spring.SpringObjectFactory.buildBean(SpringObjectFactory.java:154)
    com.opensymphony.xwork2.ObjectFactory.buildBean(ObjectFactory.java:151)
    com.opensymphony.xwork2.ObjectFactory.buildAction(ObjectFactory.java:121)
    com.opensymphony.xwork2.DefaultActionInvocation.createAction(DefaultActionInvocation.java:297)
    com.opensymphony.xwork2.DefaultActionInvocation.init(DefaultActionInvocation.java:397)
    com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:194)
    org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:63)
    org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39)
    com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:58)
    org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:536)
    org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
    org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
    org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
    org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
    org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
    org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    java.lang.Thread.run(Unknown Source)

例外情况说我需要设置范围策略。所以,我的问题是这个范围策略是什么以及如何在我的简单应用程序中实现它。另外,还有注释@Scoped,这个注释在我的情况下如何应用?

我的示例参考:

  1. bean configuration

2 个答案:

答案 0 :(得分:3)

让我们从查看文档开始查看Scope.Strategy是什么。它说

  

可插拔范围策略。使用户能够提供自定义   请求,会话和向导范围的实现。实施和   传递给   Container.setScopeStrategy(com.opensymphony.xwork2.inject.Scope.Strategy)

好的,假设我想实现会话范围。然后我需要知道我可以实现它的地方。该框架具有扩展点,您可以在其中插入扩展,或者只是扩展default实现并提供您自己的自定义实现。通过查看BeanSelectionProvider可以轻松完成此操作。然后分析堆栈跟踪我决定最好的方法是扩展DefaultActionProxyFactory。扩展它还需要扩展DefaultActionProxy

public class MyActionProxyFactory extends DefaultActionProxyFactory {

    public MyActionProxyFactory() {
        super();
    }

    @Override
    public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {

        MyActionProxy proxy = new MyActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
        container.inject(proxy);
        container.setScopeStrategy(new MyScopeStrategy());
        proxy.prepare();
        return proxy;
    }
}

public class MyActionProxy extends DefaultActionProxy {

    protected MyActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {
        super(inv, namespace, actionName, methodName, executeResult, cleanupContext);
    }

    @Override
    protected void prepare() {
        super.prepare();
    }
}

public class MyScopeStrategy implements Scope.Strategy {

    @Override
    public <T> T findInRequest(Class<T> type, String name, Callable<? extends T> factory) throws Exception {
        return null;
    }

    @Override
    public <T> T findInSession(Class<T> type, String name, Callable<? extends T> factory) throws Exception {

        ActionContext context = ActionContext.getContext();
        SessionMap<String, T> sessionMap = (SessionMap<String, T>) context.getSession();

        if (sessionMap == null) {
            sessionMap = new SessionMap<String, T>(ServletActionContext.getRequest());
            context.setSession((Map<String, Object>) sessionMap);
        }

        T obj = sessionMap.get(name);

        if (obj == null) {
            obj = factory.call();
            sessionMap.put(name, obj);
        }
        return obj;
    }

    @Override
    public <T> T findInWizard(Class<T> type, String name, Callable<? extends T> factory) throws Exception {
        return null;
    }
}

在配置文件struts.xml中,您应该设置属性

<constant name="struts.actionProxyFactory" value="jspbean.struts.factory.MyActionProxyFactory"/>

这就是为会话范围注入bean Session所需的一切。可以对其他范围进行类似的实现。请注意,其他范围如singlton(默认使用),线程和默认值似乎不需要这样的可插拔扩展。最后一个词是@Scoped注释。如果您通过xml配置提供bean,则不会使用它。但是如果你以任何其他方式向ContainerBuilder提供bean,它就可以在其上找到注释并设置相应的范围。

答案 1 :(得分:2)

我相信Luiggi的评论是正确的。 “@Inject”需要在字段值本身上,而不是在setter上。

 @Inject("session")
 private Session session;

只要你在struts.xml中定义了“session”bean或者在Struts容器中注册它,它应该能够找到并注入它。根据您的解释,似乎就是这种情况。

有关更具体的信息,请查看Struts用户列表中的讨论:Struts user question on built-in DI