spring vaadin
我越深入Vaadin ,就越喜欢它:与肮脏的管道隔离,丰富的组件,与portlet的集成,Vaadin拥有了一切。
无论如何,您对技术的探索越多,跌倒众所周知的兔子洞的机会就越大。 我是昨天才找到的,并提出了解决方案。 问题如下:在Vaadin中,应用程序对象绑定到会话。 由于我是Spring的忠实拥护者,因此使用Spring连接我的所有依赖关系确实很有意义。 这样,我将所有与应用程序相关的bean(应用程序,窗口,按钮,资源等)的作用域限定为如下会话:
<?xml version="1.0" encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:annotation-config/>
<beanid="application"scope="session">
<aop:scoped-proxy/>
...
</beans>
效果很好,直到您碰巧使用DI进行进一步布线为止。 进一步说,我的意思是将窗口连接到应用程序,将按钮连接到窗口,然后将资源(图标)连接到按钮。 这是导致循环依赖的最后一步。 图标资源在com.vaadin.terminal.ClassResource
中由com.vaadin.terminal.ClassResource
。 该类有两个构造函数,都需要一个应用程序实例。
因此,依赖关系周期为:应用程序→窗口→按钮→资源→应用程序。 Spring不喜欢它,并抛出一个标记为的异常来对此进行强烈抗议,因此Requested bean is currently in creation: Is there an unresolvable circular reference?
我认为在这种情况下, ClassResource
的设计不适合。 这就是为什么我设计了一个与Spring延迟实例化对齐的类:由于应用程序是基于会话的,因此Spring使用了一个代理,该代理将实例化从应用程序启动(Spring正常行为)推迟到会话使用。 关键是实现ApplicationResource
接口,该接口需要一个接口,但仅在需要时设置应用程序:
publicclassDeferredClassResourceimplementsApplicationResource{
privatestaticfinallongserialVersionUID=1L;
privateintbufferSize=0;
privatelongcacheTime=DEFAULT_CACHETIME;
privateClass<?>associatedClass;
privatefinalStringresourceName;
privateApplicationapplication;
publicDeferredClassResource(StringresourceName){
if(resourceName==null){
thrownewIllegalArgumentException("Resource name cannot be null");
}
this.resourceName=resourceName;
}
publicDeferredClassResource(Class<?>associatedClass,StringresourceName){
this(resourceName);
if(associatedClass==null){
thrownewIllegalArgumentException("Associated class cannot be null");
}
this.associatedClass=associatedClass;
}
...// standard getters
@Override
publicStringgetFilename(){
intindex=0;
intnext=0;
while((next=resourceName.indexOf('/',index))>0
&&next+1<resourceName.length()){
index=next+1;
}
returnresourceName.substring(index);
}
@Override
publicDownloadStreamgetStream(){
finalDownloadStreamds=newDownloadStream(associatedClass
.getResourceAsStream(resourceName),getMIMEType(),
getFilename());
ds.setBufferSize(getBufferSize());
ds.setCacheTime(cacheTime);
returnds;
}
@Override
publicStringgetMIMEType(){
returnFileTypeResolver.getMIMEType(resourceName);
}
publicvoidsetApplication(Applicationapplication){
if(this.application==application){
return;
}
if(this.application!=null){
thrownewIllegalStateException("Application is already set for this resource");
}
this.application=application;
associatedClass=application.getClass();
application.addResource(this);
}
}
DeferredClassResource
只是ClassResource
一个副本,但具有一些适应性,这些适应性使以后可以设置应用程序,而不仅仅是在构造函数中。 我的问题解决了,我只需要让应用程序知道我的资源,即可在@PostConstruct
注释方法中调用setApplication(this)
。
翻译自: https://blog.frankel.ch/chicken-and-egg-problem-with-spring-and-vaadin/
spring vaadin