初期状況
私の Web アプリケーションは、Maven モジュールmyapp-persistence (.jar)、myapp-model (.jar)、myapp-service (.jar)、およびmyapp-web (.war) で構成され、従来の疎結合の多層構造を取得します。建築。すべてのモジュールは、すべてのサブモジュールの一般的な定義を持つ親POMのみを含む親 Maven モジュールによって結合されます。
特にmyapp-service (.jar) とmyapp-persistence (.jar) は、必要なオブジェクトを含む独自の構成可能な (!) アプリケーション コンテキスト パーツを保持します。両方の jar は、含まれている変数定義を使用してデプロイ可能である必要があります。つまり、jar に変数の具体的な値が含まれていてはなりません。
myapp-service-context.xmlは、サーバー URL の変数を使用してsolrServer Bean を宣言します。
<bean id="solrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
<constructor-arg value="${solr.serverUrl}" />
<property name="connectionTimeout" value="60000"/>
<property name="defaultMaxConnectionsPerHost" value="40"/>
<property name="maxTotalConnections" value="40"/>
</bean>
myapp-persistence-context.xmlは、接続変数を使用してdataSourceを定義します。
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
...
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
...
</bean>
myapp-web (.war) はmyapp-service (.jar) とmyapp-persistence (.jar) を参照します。myapp-servlet.xmlには、それらのアプリケーション コンテキスト パーツが含まれ、プロパティ ファイルによって宣言された Bean の構成用のプロパティ値が提供されます。context:property-placeholderにより、Spring はメモリ内にアプリケーション コンテキストを作成するときに、すべての変数を具体的な値で初期化します。
<context:property-placeholder location="classpath*:myapp-configuration.properties" />
<import resource="classpath*:myapp-persistence-context.xml"/>
<import resource="classpath*:myapp-service-context.xml"/>
開発プロファイルの場合、具体的なmyapp-configuration.propertiesは次のようになります。
solr.serverUrl=http://localhost:8983/solr
jdbc.dialect=org.hibernate.dialect.HSQLDialect
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:mem:myapp
jdbc.username=sa
jdbc.password=
この構成は簡単で、ビューなしで機能します。org.springframework.orm.hibernate3.support.OpenSessionInViewFilterが登場すると問題が発生します。
問題の説明
OpenSessionInViewFilterは、ビューがこれらのオブジェクトのコンテンツを表示しようとする場合に、コントローラの処理中に開いているトランザクション内にロードされないオブジェクト グラフのインスタンスを遅延ロードできるようにします ( [1]を参照)。よく説明されるように、このフィルターは、展開記述子web.xmlで宣言されます ( [2]を参照)。
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
上記のようにmyapp-persistence-context.xmlがmyapp-servlet.xmlに含まれてcontext:property-placeholderが機能する場合、OpenSessionInViewFilterは必要なsessionFactoryを見つけられません。その理由は、Spring が最初にweb.xmlを処理し、次にmyapp -persistence-context.xmlをインポートするmyapp -servlet.xmlを処理するためと思われます。残念ながら、この推測を参照によって証明することはできません。次の例外がスローされます。
GRAVE: サーブレット [myapp] の Servlet.service() がパス [/myapp] のコンテキストで例外をスローしました org.springframework.beans.factory.NoSuchBeanDefinitionException: 「sessionFactory」という名前の Bean が定義されていません org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:529) で org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1095) で org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:277) で org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) で org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1097) で org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.lookupSessionFactory(OpenSessionInViewFilter.java:242) で org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.lookupSessionFactory(OpenSessionInViewFilter.java:227) で org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:171) で org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) で org.apache.catalina.core.ApplicationFilterChain.internalDoFilter (ApplicationFilterChain.java:243) で org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) で org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)で org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76) で 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:310) で java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) で java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) で java.lang.Thread.run(Thread.java:662) で
通常、異なるアプリケーション コンテキスト パーツは、myapp-servlet.xmlではなくContextLoaderListenerを使用してデプロイメント記述子に含まれます。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:myapp-service-context.xml,
classpath*:myapp-persistence-context.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
残念ながら、この構成では、Spring のcontext:property-placeholderメカニズムが機能しなくなったようです。
目的と疑問
myapp-persistence (.jar) やmyapp-service (.jar) などのモジュールは、 myapp-web (.war)のアプリケーション コンテキストなど、参照コンテキストによってプロパティ ファイルを使用して実行時に構成可能である必要があります。
問題は、Spring アプリケーション コンテキストでOpenSessionInViewFilterを構成してcontext:property-placeholderを引き続き使用できるようにすることは可能ですか?
または、代わりに: アプリケーション コンテキスト パーツがデプロイメント記述子web.xmlに含まれている場合、実行時にアプリケーション コンテキストの変数を Spring によってどのように初期化できますか?
基本的に: 実際にOpenSessionInViewFilterを構成する必要があるのはなぜですか? Spring MVC がデフォルトでビューの遅延読み込みを透過的にサポートしていないのはなぜですか?
予想発言
コンパイル時のプロパティの置換は、ここでは重要ではありません。プロファイル依存プロパティ ファイルは、Maven フィルタリングで既に作成されています。
myapp - persistence ( .jar )とmyapp - service ( _ _ _ _ .jar) - 実際には依存性注入の精神です!