Struts2中的dependency injection访问会话Scoped Bean

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

//@Repository //@Scope("session") public class Session { private Map map = new HashMap(); public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } } 

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

  

以及创建该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 myMap = new HashMap(); public Map getMyMap() { return myMap; } public void setMyMap(Map 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

  

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

 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配置

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

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

好吧,假设我想实现会话范围。 然后我需要知道我可以实现它的地方。 该框架具有扩展点,您可以在其中插入扩展,或者只是扩展default实现并提供您自己的自定义实现。 通过查看BeanSelectionProvider可以轻松完成此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 findInRequest(Class type, String name, Callable factory) throws Exception { return null; } @Override public  T findInSession(Class type, String name, Callable factory) throws Exception { ActionContext context = ActionContext.getContext(); SessionMap sessionMap = (SessionMap) context.getSession(); if (sessionMap == null) { sessionMap = new SessionMap(ServletActionContext.getRequest()); context.setSession((Map) sessionMap); } T obj = sessionMap.get(name); if (obj == null) { obj = factory.call(); sessionMap.put(name, obj); } return obj; } @Override public  T findInWizard(Class type, String name, Callable factory) throws Exception { return null; } } 

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

  

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

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

  @Inject("session") private Session session; 

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

有关更具体的信息,请查看Struts用户列表中的讨论: 内置DI上的Struts用户问题