Grails spring boot在使用GORM的多模块渐变构建中不支持@EntityScan

Grails spring boot在使用GORM的多模块渐变构建中不支持@EntityScan,grails,gradle,gorm,spring-boot,grails-2.0,Grails,Gradle,Gorm,Spring Boot,Grails 2.0,我有一个多模块gradle构建,使用spring boot和独立GORM 域实体位于单独的子模块中,因此这些域对象和gorm可以跨多个spring boot(和非spring boot)应用程序使用 结构 build.gradle - module1-with-springboot-jersey (depending on module 3) -- src/main/groovy/geit/api/Application.groovy - module2-with-springboot-gr

我有一个多模块gradle构建,使用spring boot和独立GORM

域实体位于单独的子模块中,因此这些域对象和gorm可以跨多个spring boot(和非spring boot)应用程序使用

结构

build.gradle
- module1-with-springboot-jersey  (depending on module 3)
-- src/main/groovy/geit/api/Application.groovy

- module2-with-springboot-groovytemplate (depending on module 3)

- module3-standalone-gorm-with-entities
-- src/main/groovy/geit/domain/../Animal.groovy

- module4-apache-camel-app  (depending on module 3)
在jersey应用程序module1中运行gradle bootRun时,它会启动应用程序,但在尝试访问返回动物的rest资源时,它会失败,并出现stacktrace:

2014-11-03 13:16:03.679 ERROR 44316 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/api].[jerseyServlet]     : Servlet.service() for servlet [jerseyServlet] in context with path [/api] threw exception [java.lang.IllegalStateException: Method on class [geit.domain.entity.experimental.reku.Animal] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.] with root cause

java.lang.IllegalStateException: Method on class [geit.domain.entity.experimental.reku.Animal] was used outside of a Grails application. If running in the context of a test using the mocking API or bootstrap Grails correctly.
    at geit.domain.entity.experimental.reku.Animal.currentGormStaticApi(Animal.groovy)
    at geit.domain.entity.experimental.reku.Animal.$static_methodMissing(Animal.groovy)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1270)
    at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
    at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1493)
    at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1481)
    at groovy.lang.ExpandoMetaClass.invokeStaticMethod(ExpandoMetaClass.java:1123)
    at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:50)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
    at geit.api.experimental.reku.AnimalsResource.greet(AnimalsResource.groovy:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     un.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springsource.loaded.ri.ReflectiveInterceptor.jlrMethodInvoke(ReflectiveInterceptor.java:1270)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:195)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:406)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:350)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:106)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:259)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:320)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1028)
    at org.glassfish.jersey.servlet.WebComponent.servComponent.java:373)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:219)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:110)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:280)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:98)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
      g.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:90)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1736)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1695)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:744)
所以我仔细阅读了文档,发现了这个 嗯@EntityScan看起来前景看好

所以我注释了我的应用程序类,如下所示

@ComponentScan
@EnableAutoConfiguration(exclude = GroovyTemplateAutoConfiguration.class)
@EntityScan(basePackageClasses=Animal)
class ApiApplication {
    static void main(String[] args) {
        SpringApplication.run ApiApplication, args
    }

}
但现在,gradle引导在启动时失败

2014-11-03 13:20:43.790  INFO 44376 --- [           main] utoConfigurationReportLoggingInitializer : 

Error starting ApplicationContext. To display the auto-configuration report enabled debug logging (start with --debug)


2014-11-03 13:20:43.797 ERROR 44376 --- [           main] o.s.boot.SpringApplication               : Application startup failed

java.lang.IllegalStateException: Unable to configure LocalContainerEntityManagerFactoryBean from @EntityScan, ensure an appropriate bean is registered.
    at org.springframework.util.Assert.state(Assert.java:385)
    at org.springframework.boot.orm.jpa.EntityScanRegistrar$EntityScanBeanPostProcessor.onApplicationEvent(EntityScanRegistrar.java:124)
    at org.springframework.boot.orm.jpa.EntityScanRegistrar$EntityScanBeanPostProcessor.onApplicationEvent(EntityScanRegistrar.java:94)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:331)
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:773)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:131)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:483)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:692)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:322)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:962)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:951)
    at org.springframework.boot.SpringApplication$run.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
      g.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
    at geit.api.ApiApplication.main(ApiApplication.groovy:31)

2014-11-03 13:20:43.798  INFO 44376 --- [           main] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@4c85ba73: startup date [Mon Nov 03 13:20:35 CET 2014]; root of context hierarchy
2014-11-03 13:20:43.801  INFO 44376 --- [           main] o.s.c.support.DefaultLifecycleProcessor  : Stopping beans in phase 0
2014-11-03 13:20:43.806  INFO 44376 --- [           main] o.s.b.a.e.jmx.EndpointMBeanExporter      : Unregistering JMX-exposed beans on shutdown
2014-11-03 13:20:43.806  INFO 44376 --- [           main] o.s.b.a.e.jmx.EndpointMBeanExporter      : Unregistering JMX-exposed beans
2014-11-03 13:20:43.807  INFO 44376 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown
Exception in thread "main" java.lang.IllegalStateException: Unable to configure LocalContainerEntityManagerFactoryBean from @EntityScan, ensure an appropriate bean is registered.
    at org.springframework.util.Assert.state(Assert.java:385)
    at org.springframework.boot.orm.jpa.EntityScanRegistrar$EntityScanBeanPostProcessor.onApplicationEvent(EntityScanRegistrar.java:124)
    at org.springframework.boot.orm.jpa.EntityScanRegistrar$EntityScanBeanPostProcessor.onApplicationEvent(EntityScanRegistrar.java:94)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:151)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:128)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:331)
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:773)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:131)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:483)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:692)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:322)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:962)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:951)
    at org.springframework.boot.SpringApplication$run.call(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
    at geit.api.ApiApplication.main(ApiApplication.groovy:31)
:api:bootRun FAILED

FAILURE: Build failed with an exception.
我也试过了 @EntityScan(basePackages=“geit.domain”)从层次结构中较高的包触发扫描,但这会产生相同的错误

但是,如果我将域/实体类移动到(jersey)应用程序模块中,那么它就可以工作了。但是,这会阻止我在多个应用程序中使用gorm。 这是我们需要实现的,以便上面的模块1、2和4可以使用独立的gorm模块

这是缺少的功能还是错误? :)

附言。 当将应用程序类移动到顶级包时,它工作正常! 也就是说,从包/geit/api/Application.groovy/geit/Application.groovy 所有子模块都有相同的顶级包名,所以这可能就是它工作的原因?
这仍然困扰着我,尽管这个问题没有得到回答。我们的解决方案是将GORM转换为spring data/jpa

我找到了一种破解方法

即使我们在做独立的GORM+Spring引导,GORM仍然会得到一个
GrailsApplication
的实例

因此,将bean后处理器挂接到应用程序。当轮到process
sessionFactory
时,获取底层的
grailsApplication
,并将Groovy域类注册为域类工件

这里


另一个解决方案是尝试将域类打包为Grails二进制插件,并在此后处理方法中加载插件(以及其捆绑资源)。希望这能有所帮助。

@EntityScan
适用于JPA,如果您使用的是GORM,则不会使用它(至少不会以预期的形式)。我想没有一个等价的注释。如果grails团队能够提供更多帮助(如果您不能添加grails标记,请询问,我会为您做)。谢谢。我已经在问题中添加了grails标签。天哪,这真是糟透了。即使这样,您仍然需要在应用程序的根包下有一个虚拟实体类,以便告诉GORM“是的,请为我启用持久性”。我要向春靴族提出一个问题。谢谢
@Component
class GrailsApplicationPostProcessor implements BeanPostProcessor {

   public static final String DEFAULT_SESSION_FACTORY_BEAN_NAME = "sessionFactory"

   public static final Class [] domainClasses = [
         Client.class, Feature.class, User.class
   ]

   @Override
   Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      if (DEFAULT_SESSION_FACTORY_BEAN_NAME.compareTo(beanName) == 0) {
         if (bean instanceof ConfigurableLocalSessionFactoryBean) {
            ConfigurableLocalSessionFactoryBean sf = (ConfigurableLocalSessionFactoryBean) bean
            GrailsApplication ga = sf.grailsApplication
            String domainClassType = DomainClassArtefactHandler.TYPE
            for (Class c in domainClasses) {
               ga.addArtefact(domainClassType, c)
            }
         }
      }
      bean
   }

   @Override
   Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      bean
   }
}