从 grails 应用程序中的自定义 groovy 文件加载 spring bean

Posted

技术标签:

【中文标题】从 grails 应用程序中的自定义 groovy 文件加载 spring bean【英文标题】:Load spring beans from custom groovy files in grails app 【发布时间】:2014-07-24 13:41:39 【问题描述】:

尝试从 Grails 2.3.7. 中的自定义 groovy 文件加载 spring bean 我知道这个问题之前已经被问过,但经过数小时的搜索,我无法找到从类路径加载的一致方法。

目标

resources.groovy模块化成多个自定义资源文件 将自定义资源文件放在标准位置:grails-app/conf/spring 使用插件来变魔术;尽量减少开销

试过...

//## grails-app/conf/spring/MyBeansConfig.groovy 
beans 
   testsvc(TestService)
      msg = 'hello'
   

请注意,我使用的是beans ,而不是beans = ,apparently,这会有所不同:

resources.groovy

这行得通...

beans = 
  loadBeans 'file:C:\\Proj\Test1\grails-app\\conf\\spring\\MyBeansConfig.groovy'

...根据docs,这也应该,但不是:

importBeans("classpath:*MyBeansConfig.groovy")

更新 - 工作选项

(适用于 Grails 2.3.7)

选项一:(src/java)

遵循lukelazarovic 的建议,这种方法有效,因为Grails 自动将src/java 中的groovy 文件复制(而不是编译)到类路径;在 Eclipse 和战争部署中工作正常:

//bean config files here
src/java/MyBeansConfig.groovy
src/java/FooBeansConfig.groovy

//resources.groovy
loadBeans('classpath*:*BeansConfig.groovy')

选项 2:(grails-app/conf/spring)

这种方法允许在 grails-app/conf/spring 中自定义 bean 配置文件(感谢 ideascultor 和 mark.esher)

   //bean config files here
   grails-app/conf/spring/MyBeansConfig.groovy

   //## resources.groovy
   //for eclipse/local testing
   loadBeans('file:./grails-app/conf/spring/*BeansConfig.groovy')
   //for WAR/classpath 
   loadBeans('classpath*:*BeansConfig.groovy')


   //## BuildConfig.groovy
   grails.war.resources =  stagingDir, args ->
      copy(todir: "$stagingDir/WEB-INF/classes/spring") 
         fileset(dir:"grails-app/conf/spring") 
            include(name: "*BeansConfig.groovy")
            exclude(name: "resources.groovy")        
            exclude(name: "resources.xml")
         
      
   

选项 3:(自定义插件)

如果您使用自定义插件,这种方法是理想的;样板配置被重构到插件中:

插件配置

   //## scripts/_Events.groovy
   eventCreateWarStart =  warName, stagingDir ->
      def libDir = new File("$stagingDir/WEB-INF/classes/spring")

      ant.copy(todir: libDir) 
         fileset(dir:"grails-app/conf/spring") 
            include(name: "*BeansConfig.groovy")
            exclude(name: "resources.groovy")
            exclude(name: "resources.xml")
         
      
   

   //## MyGrailsPlugin.groovy
   def doWithSpring =        
      loadBeans('file:./grails-app/conf/spring/*BeansConfig.groovy')
      loadBeans('classpath*:*BeansConfig.groovy') 
   

Grails 应用程序

没有配置!...只需使用*BeansConfig.groovy 约定创建您的 bean 配置文件,一切顺利!

//bean config files here
grails-app/conf/spring/MyBeansConfig.groovy

2015 年 9 月 24 日更新

发现选项 3 存在一些问题:

加载重复的资源文件 没有为test-app正确配置spring资源

我们设法解决了上述问题,使得grails-app/conf/spring 中的任何资源文件在 eclipse、WAR、test-app 等中执行 Grails 时都可以正常工作。

第一步:我们创建了一个类来更好地控制资源文件的定位和加载;这是必要的,因为由于交叉引用的 bean,一些文件被多次加载。 我们使用一个插件来封装这个功能,所以这个类存在于那个插件中:

class CustomResourceLoader 
   static loadSpringBeans(BeanBuilder bb)         
         def files = ['*'] //load all resource files 
         //match resources using multiple methods
         def matchedResourceList = []
         files.each 
            matchedResourceList +=
               getPatternResolvedResources("file:./grails-app/conf/spring/" + it + ".groovy").toList()
            matchedResourceList +=
               getPathMatchedResources("classpath*:spring/" + it + ".groovy").toList()
         

         //eliminate duplicates resource loaded from recursive reference
         def resourceMap = [:]       
         matchedResourceList.each
            if(it) resourceMap.put(it.getFilename(), it) 
                    
         //make resources.groovy first in list
         def resourcesFile = resourceMap.remove("resources.groovy")
         if(!resourcesFile)
            throw new RuntimeException("resources.groovy was not found where expected!")

         def resourcesToLoad = [resourcesFile]
         resourceMap.eachk,v -> resourcesToLoad << v          
         log.debug("Spring resource files about to load: ")        
         resourcesToLoad.each bb.loadBeans(it) 
   

   static def getPatternResolvedResources(path)
      ResourcePatternResolver resourcePatternResolver =
         new PathMatchingResourcePatternResolver();
      return resourcePatternResolver.getResources(path);
   

   static def getPathMatchedResources(path)
      return new PathMatchingResourcePatternResolver().getResources(path)
   

去掉BeansConfig.groovy后缀; WAR 生成现在可以获取 grails-app/conf/spring 中的任何资源

plugin, _Events.groovy
eventCreateWarStart =  warName, stagingDir ->
      def libDir = new File("$stagingDir/WEB-INF/classes/spring")
      ant.copy(todir: libDir) 
         fileset(dir:"grails-app/conf/spring") 
            include(name: "*.groovy")          
            exclude(name: "resources.xml")
         
      
   

在插件定义文件中,从doWithSpring()调用加载器,传递BeanBuilder(委托)作为参数(非常重要):

def doWithSpring =        
   CustomResourceLoader.loadSpringBeans(delegate)

就是这样,除了在grails-app/conf/spring创建自定义资源文件外,对插件用户没有任何要求

【问题讨论】:

感谢您整理以上所有信息!谢谢! @mowwwalker 感谢您提醒我更新这篇文章!请参阅上面的更改,希望对您有所帮助! 【参考方案1】:

几天前我遇到了类似的问题,我在grails-app/conf 中添加了一个 groovy 配置文件。虽然这适用于其他资源(它们被复制并在类路径上可用),但 groovy 文件的问题只是它被编译并包含了类文件,即不是 groovy 文件本身。

我没有找到任何关于如何应该完成的好的文档,最后只是将它添加到web-app/WEB-INF/classes。放置在此处的 Groovy 文件将被复制(未编译)并在类路径中可用。

【讨论】:

【参考方案2】:

我在 Grails 2.1.2 中使用自定义 XML 文件时遇到了同样的问题。

grails-app/conf/spring 中拥有 XML 资源在生产环境 AFAIR 中不起作用。

为了使其在开发和生产环境中都能正常工作,我最终将资源放入 src/java。我认为您可以通过将 groovy 文件放入 src/groovy 来获得相同的结果。

【讨论】:

src/java 应该可以工作,但是我相信 src/groovy 会编译这个类,我记得昨晚读过一些关于那个的东西,你可以确认吗? 我不知道你是什么意思 - 当你运行 grails war 时,所有的 groovy 文件,包括 grails-app 中的文件都会编译成类文件 我知道,但是loadBeans() 读取 groovy 文件,它不适用于类文件;当配置文件驻留在 src/groovy 中时,它似乎不起作用(刚刚测试过)【参考方案3】:

我们也可以通过以下方式从不同的 groovy/xml 文件中导入 bean:- 在 resources.groovy 中使用以下内容 -

importBeans 'file:camel-beans.groovy' 要么 importBeans('classpath:/camel-config.xml')

将 camel-beans.groovy 与 resources.groovy 一起放置,并为第一种情况提供包作为“包 spring”,否则将其放在 web 应用程序类路径中并使用第二种方式。

【讨论】:

【参考方案4】:

如果您的 resources.groovy 位于以下路径

grails-app/conf/spring/resources.groovy

而您的 camel-beans.groovy 位于以下路径

grails-app/conf/spring/camel-beans.groovy

然后您可以通过在 resources.groovy 中添加以下行来引用 resources.groovy 文件中的 camel-beans.groovy

importBeans('file:**/camel-beans.groovy')

【讨论】:

以上是关于从 grails 应用程序中的自定义 groovy 文件加载 spring bean的主要内容,如果未能解决你的问题,请参考以下文章

Grails 文档中的自定义事件监听器示例

Grails 插件中的自定义 CSS 和 JS

Grails 2.2.1 无法识别从 BuildConfig.groovy 安装的“发布”插件

Grails / Groovy / GGTS:运行应用程序上的模块版本冲突

使用 Quartz 调试 Groovy/Grails 应用程序中的堆空间问题

如何从grails 3.1.8中的外部文件加载数据源配置?