Spring2.5とClickで開発
今のプロジェクトはこの組み合わせで進めてる。
せっかくSpringの2.5を使うんだから新機能を使いたいよねーってわけで、今採用してる方法を書いてみる。
まず、applicationContext.xml はこんな感じでやってる。
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- ========== RESOURCE DEFINITIONS ========== --> <context:annotation-config/> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- DataSource --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" p:defaultAutoCommit="false" p:maxActive="3" p:maxIdle="1" p:initialSize="1" p:maxWait="60000" /> <!-- Transaction manager --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref local="dataSource" /> </property> </bean> <tx:annotation-driven transaction-manager="transactionManager" /> <!-- ========== BUSINESS OBJECT DEFINITIONS ========== --> <context:component-scan base-package="sample.service" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" /> </context:component-scan> <!-- ========== Data Access OBJECT DEFINITIONS ========== --> <context:component-scan base-package="sample.dao" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" /> </context:component-scan> <!-- ========== PAGE OBJECT DEFINITIONS ========== --> <context:component-scan base-package="sample.page" use-default-filters="false" name-generator="sample.PageNameGenerator" scope-resolver="sample.PageScopeMetadataResolver"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" /> </context:component-scan> </beans>
パッケージとしてはPageとDaoとServiceにわけた。
PageパッケージのPageクラスにはComponentアノテーションを、Daoパッケージの実装クラスにはRepositoryアノテーションを、Serviceパッケージの実装クラスにはServiceアノテーションを付けたものだけSpringに自動登録されるようにした。こいつらはSpringの標準アノテーション。
問題はPageなんだけど、通常Springで自動登録したら、たとえばsample.HogePageだとsample.HogePage#0って名前になっちゃう。Clickは完全クラス名でApplicationContextに登録されている事が前提だから、独自のBeanNameGeneratorを作ってやった。
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; public class PageNameGenerator implements BeanNameGenerator { public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) { return definition.getBeanClassName(); } }
こいつらは通常だとSingletonなので、scope-resolverで一括でprototypeにしてやる。これはScopeMetadataResolverを独自実装したものを使ったけど、この程度のクラス、デフォルトで用意されてないのかなぁ。あんまり注意して探してないけど。
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.ScopeMetadata; import org.springframework.context.annotation.ScopeMetadataResolver; import org.springframework.context.annotation.ScopedProxyMode; public class PageScopeMetadataResolver implements ScopeMetadataResolver { public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) { ScopeMetadata scopeMetadata = new ScopeMetadata(); scopeMetadata.setScopedProxyMode(ScopedProxyMode.NO); scopeMetadata.setScopeName(BeanDefinition.SCOPE_PROTOTYPE); return scopeMetadata; } }
もちろん各Pageクラスで@Scopeを指定してやってもいいけど、忘れちゃやだからねー。
ClickとSpring2.5って、すごく相性がいいと思うけど、あんまり情報ないなー。ってゆーかClick自体の情報がないじゃーん。
追記
あ、ClassPathBeanDefinitionScanner見たら、@Service、@Repository、@Component、@Controllerの4つはもともと自動で登録されるんだ。いちいちuse-default-filtersをfalseにせんでもよかった。