[英]Spring MVC, Scoped Controller using Class-Based Proxy: 'There is already scopedTarget bean method.'
I'm creating a visual editor Web app using Spring MVC. 我正在使用Spring MVC创建一个可视化编辑器Web应用程序。
The visualizaton has some properties: visualizaton有一些属性:
public class VisualizationProperties {
double strokeWidth = 1;
Rectangle selectedArea;
}
Every browser session should have one, so I define it as a session-scoped bean: 每个浏览器会话应该有一个,所以我将其定义为会话范围的bean:
@Component
@Scope("session")
public class VisualizationProperties {
...
Since I want to access it from the service... 因为我想从服务中访问它...
@Service
public class VisualizationService {
@Resource
private VisualizationProperties properties;
public void createVisualization () {
//create visualization using properties
...
}
}
...I define access through a proxy: ...我通过代理定义访问:
@Component
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class VisualizationProperties {
...
make the members private and add getters + setters to it. 使成员私有,并添加getters + setter。
Perfect so far. 到目前为止完美。
Now I want the client to be able to read and update the properties. 现在我希望客户端能够读取和更新属性。
So I change the bean to become a controller and add methods to access itself: 所以我将bean更改为控制器并添加访问自身的方法:
@Controller
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class VisualizationProperties {
private double strokeWidth = 1;
private Rectangle selectedArea;
... //getters + setters
@RequestMapping(value="/properties", method=RequestMethod.GET)
public @ResponseBody VisualizationProperties getProperties () {
return this;
}
@RequestMapping(value="/properties", method=RequestMethod.POST)
public @ResponseBody void setProperties (@RequestBody VisualizationProperties newProperties) {
this.strokeWidth = newProperties.strokeWidth;
this.selectedArea = newProperties.selectedArea;
}
}
Causes the following exception on start-up: 在启动时导致以下异常:
IllegalStateException: Ambiguous mapping found.
Cannot map 'visualizationProperties' bean method getProperties() to {[/properties],methods=[GET],...}:
There is already 'scopedTarget.visualizationProperties' bean method.
Why is that? 这是为什么?
The issue here is two-fold. 这里的问题是双重的。 First you're annotating a class that is already annotated with @Controller
. 首先,您要注释一个已经使用@Controller
注释的类。
@Controller
@Scope(value="session", proxyMode=ScopedProxyMode.TARGET_CLASS)
public class VisualizationProperties {
Second, you are using scoped proxies. 其次,您正在使用范围代理。 In this case, Spring will register two bean definitions. 在这种情况下,Spring将注册两个bean定义。 One with the name visualizationProperties
for the actual bean and one with the name scopedTarget.visualizationProperties
which will act as a FactoryBean
for creating proxies. 一个名为visualizationProperties
用于实际bean,另一个名为scopedTarget.visualizationProperties
,用作创建代理的FactoryBean
。
The handler method registration process (for @Controller
beans and @RequestMapping
methods) works by finding all bean names in the context, finding their type, scanning the methods of that type and registering those methods if they are annotated with @RequestMapping
. 处理程序方法注册过程(对于@Controller
bean和@RequestMapping
方法)通过查找上下文中的所有bean 名称 ,查找其类型,扫描该类型的方法以及注册这些方法(如果使用@RequestMapping
注释)来工作。
Since Spring resolves both visualizationProperties
and scopedTarget.visualizationProperties
bean names as beans of type VisualizationProperties
which has @RequestMapping
annotated methods, it will try to register both, failing on the second because of mapping clashes (you can't have two handler mapped to the same request). 由于Spring解决了这两个visualizationProperties
和scopedTarget.visualizationProperties
bean名字类型的豆VisualizationProperties
已@RequestMapping
注解的方法,它会尝试注册这两个,没有按规定因为映射冲突的第二个(你不能有两个处理程序映射到相同请求)。
My suggested solution is to refactor and create a dedicated @Controller
class (that isn't proxied) that delegates to a session scoped VisualizationProperties
bean. 我建议的解决方案是重构并创建一个委托给会话范围的VisualizationProperties
bean的专用@Controller
类(不代理)。
Alternatives that work: 有效的替代方案:
proxyMode=ScopedProxyMode.INTERFACES
, move the cute little properties POJO to a VisualizationProperties
Impl
and introduce an interface for it .. overhead duh! 使用proxyMode=ScopedProxyMode.INTERFACES
,将可爱的小属性POJO移动到VisualizationProperties
Impl
并为它引入一个接口.. proxyMode=ScopedProxyMode.INTERFACES
! other ideas? 其他想法?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.