最近我需要在 Struts2 中使用 DI.我知道它使用自己的 DI 实现,如 Guice 但不是 Guice,因为我找不到一些适合设置注入 bean 范围的注释.简而言之,我创建了一个 bean
Recently I needed to use DI in Struts2. I know it uses it's own DI implementation like Guice but not Guice, as far as I couldn't find some annotations suitable to set the scope for injected beans. To be short, I created a 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
I have commented the annotations used with Spring beans. I was successfully created the same bean via spring DI and set the scope in which my objects were injected. Now, I want to do the same with Struts2 and DI. For this purpose I created the bean definition in struts.xml
<bean name="session" class="jspbean.struts.Session" scope="session"/>
创建该 bean 并将其注入到我的操作中的简单操作
and simple action to get that bean created and injected into my action
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 上使用简单的迭代器
in the JSP I use simple iterator over session bean
<s:iterator value="session.map['myMap']">
<s:textfield name="myMap['%{key}']" value="%{value}" theme="simple" size="10" /><br>
</s:iterator>
现在,当我运行这个简单的应用程序时,我遇到了异常
Now, when I'm running this smple application I've got the exception
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
,这个注解在我的情况下如何应用?
The exception says that I need to set the scope strategy. So, my question is what is this scope strategy and how it could be implemented in my simple application. Also, there is annotation @Scoped
, how this annotations to apply in my case?
我的示例参考:
让我们从查看文档开始了解什么是 Scope.Strategy
.它说
Let's start from looking what is a Scope.Strategy
by looking at the docs. It says
可插入的范围策略.使用户能够提供自定义请求、会话和向导范围的实现.实施和传递给Container.setScopeStrategy(com.opensymphony.xwork2.inject.Scope.Strategy)
Pluggable scoping strategy. Enables users to provide custom implementations of request, session, and wizard scopes. Implement and pass to
Container.setScopeStrategy(com.opensymphony.xwork2.inject.Scope.Strategy)
好的,假设我想实现会话范围.然后我需要知道我可以实现它的地方.该框架有它的扩展点,您可以在其中插入扩展或简单地扩展 default
实现并提供您自己的自定义实现.这很容易通过查看 BeanSelectionProvider
.然后分析堆栈跟踪,我认为最好的方法是扩展 DefaultActionProxyFactory
.扩展它还需要扩展 DefaultActionProxy
.
Ok, assume I want to implement session scope. Then I need to know the place where I could implement it. The framework has it's extension points where where you could plug your extensions or simply extend the default
implementation and provide your own custom implementations. This is easy done via looking at the BeanSelectionProvider
. Then analyzing the stacktraces I decided the best point would be to extend the DefaultActionProxyFactory
. Extending it requires to extend the DefaultActionProxy
also.
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,则不会使用它.但是,如果您以任何其他方式为 bean 提供 ContainerBuilder
,它就能够在其上找到注释并设置相应的范围.
That's all you need to inject a bean Session
with the session scope. Similar implementations could be done for other scopes. Notice, that other scopes like singlton (used by default), thread, and default seems don't require such pluggable extension. And the last word is about @Scoped
annotation. It's not used if you provide the beans via xml configuration. But if you supply the ContainerBuilder
with the bean in any other way it's able to find annotation on it and set the corresponding scope.
这篇关于Struts2 中的依赖注入访问 Session Scoped Bean的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!