私は GWT と Spring サーバーを使用しています。私は、他の Web アプリケーションやプロジェクトで動作する Spring アノテーション (@Repository、@Service、@Component など) を持つ多くのプロジェクトに使用しているプロジェクトを持っていますが、Spring を GWT と統合すると、依存性注入が失敗して、 Bean に一致するタイプがありません。
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.xxx.yy.api.phone.call.PhoneCallDAO] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.annotation.Resource(mappedName=, shareable=true, description=, name=, type=class java.lang.Object, lookup=, authenticationType=CONTAINER)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:924)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:793)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:438)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:416)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:549)
at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:150)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:303)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:385)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:284)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)
at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:543)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1220)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:513)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
at com.google.gwt.dev.shell.jetty.JettyLauncher$WebAppContextWithReload.doStart(JettyLauncher.java:468)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.handler.RequestLogHandler.doStart(RequestLogHandler.java:115)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:222)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:39)
at com.google.gwt.dev.shell.jetty.JettyLauncher.start(JettyLauncher.java:672)
at com.google.gwt.dev.DevMode.doStartUpServer(DevMode.java:509)
at com.google.gwt.dev.DevModeBase.startUp(DevModeBase.java:1068)
at com.google.gwt.dev.DevModeBase.run(DevModeBase.java:811)
at com.google.gwt.dev.DevMode.main(DevMode.java:311)
上で述べたように、この同じプロジェクトが別の Web アプリケーションで使用されているため、DAO とサービスには正しく注釈が付けられています。ここに私のアプリケーションコンテキストがあります:
<?xml version="1.0" encoding="UTF-8"?>
...
<!-- This line sets up the fact that we can use annotations throughout -->
<context:annotation-config />
<!-- This line tells the Spring boot-strapper where to scan for any objects
that are marked with annotations such as @Repository or @Service or @Component -->
<context:component-scan
base-package="com.xxx.yyy, com.xxx.yyy.api, com.xxx.zzz.api, com.xxx.www, com.gwtplatform.dispatch.server.spring" />
<!-- NOTE: Properties are LAST ONE WINS. Meaning that if there are duplicate
properties the one that is loaded LAST will be used. Because of this we should
make the JNDI name *LAST* This particular class (bean) can be found in the
maher-spring-extension project and it was coded so we can use JNDI to find
an environment specific configuration file. We use these for things such
as the database, log file directories or anything that is specific to that
particular environment. This enables us to be able to build ONE war file
and deploy it to any server and so long as that server environment is configured
with the appropriate configuration file. (example: we configure the STAGE
system to point to the STAGE database and put that properties file somewhere
on that machine and then configure it in the Tomcat JNDI system. Then this
application will find that file and load the properties overwriting any of
the previously set properties (LAST ONE WINS)) -->
<bean
class="org.springframework.beans.factory.config.JndiAwarePropertyPlaceholderConfigurer"
init-method="initialize">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:application.properties</value>
<value>classpath:local.properties</value>
<!-- these properties are environment specific and are bound in JNDI.
If there is no entry then it will gracefully ignore them since we set ignoreUnresolvablePlaceholders
to true -->
<value>file:${IVRProperties}</value>
</list>
</property>
</bean>
<!-- Here we are configuring our server module for the GWTP -->
<bean id="serverModule" class="com.xxx.yyy.gwt.server.spring.ServerModule" />
<!-- Here we configure the logger that will be used by the GWTP -->
<bean id="logger"
class="com.gwtplatform.dispatch.server.spring.LoggerFactoryBean">
<constructor-arg>
<bean class="java.util.logging.Logger" factory-method="getAnonymousLogger">
<property name="level">
<value>INFO</value>
</property>
</bean>
</constructor-arg>
</bean>
<!-- Here is our data source. This is the only place you will see anything
to do with a database connection -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver.class}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="${jdbc.maxActive}" />
</bean>
<!-- Used to stamp every entity that has a createdAt or updatedAt field
on insert and update
<bean id="entityInterceptor" class="com.maher.ivr.server.interceptor.EntityInterceptor"/> -->
<!-- Here we configure the Session Factory. -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="schemaUpdate" value="${hibernate.schema.update}" />
<!-- <property name="entityInterceptor" ref="entityInterceptor"/> -->
<property name="packagesToScan" value="com.xxx.yyy, com.xxx.zzz.api" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.query.substitutions">${hibernate.query.substitutions}</prop>
<prop key="hibernate.bytecode.use_reflection_optimizer">${hibernate.bytecode.use.optimizer}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.generateDdl">${hibernate.generateDdl}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.cache.provider_class">${hibernate.cache.provider}</prop>
</props>
</property>
</bean>
<!-- Here we configure the Transaction manager. -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Here we enable the transaction manager to be picked up by Aspects.
Because of this we can simply add a @Transactional annotation to our service
classes and all aspects of the transactions are handled for us, such as Rollback,
Commit etc... -->
<bean
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager" />
<property name="transactionAttributeSource">
<bean
class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource" />
</property>
</bean>
<bean
class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
<property name="transactionInterceptor" ref="transactionInterceptor" />
</bean>
<bean id="velocityEngine"
class="org.springframework.ui.velocity.VelocityEngineFactoryBean">
<property name="velocityProperties">
<value>
resource.loader=class
class.resource.loader.class=org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
</value>
</property>
</bean>
クラスがGWTプロジェクトに含まれている別のプロジェクトの一部であることが問題であるかどうかはわかりませんが、それがどのように問題になるかはわかりません。すべての Bean を applicationContext.xml で手動で定義できますが、これは面倒です。大量の注入されるすべての単一クラスに対してそれらを定義する必要があるため、定義する必要がたくさんあります。