Trying to load spring beans from custom groovy file in Grails 2.3.7.
I know this question has been asked before, but after hours of searching, I'm unable to find a consistent approach that loads from the classpath.
The Goal
- Modularize
resources.groovy
into multiple custom resource files - Put custom resource files in standard location:
grails-app/conf/spring
- Use plugin to do the magic; minimize overhead
Tried...
//## grails-app/conf/spring/MyBeansConfig.groovy
beans {
testsvc(TestService){
msg = 'hello'
}
}
Note above, I'm using beans {}
, not beans = {}
, apparently it makes a difference:
resources.groovy
This works...
beans = {
loadBeans 'file:C:\\Proj\Test1\grails-app\\conf\\spring\\MyBeansConfig.groovy'
}
...and according to docs, this should too, but doesn't:
importBeans("classpath:*MyBeansConfig.groovy")
UPDATE - WORKING OPTIONS
(working for Grails 2.3.7)
Option 1: (src/java)
Following lukelazarovic advice, this approach works since Grails automatically copies (not compiles) groovy files in src/java
to the classpath; works fine in eclipse and with war deployment:
//bean config files here
src/java/MyBeansConfig.groovy
src/java/FooBeansConfig.groovy
//resources.groovy
loadBeans('classpath*:*BeansConfig.groovy')
Options 2: (grails-app/conf/spring)
This approach allows for custom bean config files in grails-app/conf/spring
(credits to ideascultor and 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")
}
}
}
Options 3: (Custom Plugin)
If you're using custom plugins, this approach is ideal; boiler plate config gets refactored into the plugin:
Plugin Config
//## 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 App
No config!...just create your bean config files using the *BeansConfig.groovy
convention, good to go!
//bean config files here
grails-app/conf/spring/MyBeansConfig.groovy
Update 9/24/2015
Found some issues with option 3:
- loading of duplicate resource files
- spring resources not configured correctly for
test-app
We managed to fix the above issue such that any resource files in grails-app/conf/spring
work the same when executing Grails in eclipse, WAR, test-app, etc.
First step: we created a class to have more control over locating and loading resource files; this was necessary as some files were being loaded more than once due to cross-referenced beans. We're using a plugin to encapsulate this functionality, so this class lives in that plugin:
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.each{k,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)
}
}
Removed BeansConfig.groovy
suffix; WAR generation now picks up any resources in 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")
}
}
}
}
In the plugin definition file, call the loader from doWithSpring()
, passing BeanBuilder
(the delegate) as the argument (very important):
def doWithSpring = {
CustomResourceLoader.loadSpringBeans(delegate)
}
That's it, there is no requirement on users of the plugin aside from creating custom resource files in grails-app/conf/spring
I had a similar problem just a few days ago, with a groovy configuration file that I added into grails-app/conf
. While this works with other resources (they are copied and available on the classpath), the problem with the groovy file was simply that it was compiled and the class file was included, i.e. not the groovy file itself.
I didn't find any good documentation on how this should be done and finally just added it to web-app/WEB-INF/classes
. Groovy files placed here will be copied (not compiled) and available on the classpath.
I had the same problem with custom XML files in Grails 2.1.2.
Having XML resources in grails-app/conf/spring
didn't work in production environment AFAIR.
To make it working both in development and production environments I finally put the resources into src/java
. I think you can achieve the same result by putting your groovy files into src/groovy
.
We can import beans from different groovy/xml file in the following way too : - use the following in resources.groovy -
importBeans 'file:camel-beans.groovy' OR importBeans('classpath:/camel-config.xml')
Place camel-beans.groovy along with resources.groovy and provide package as "package spring" for first case, otherwise put it in web app classpath and use the second way to do it.
If your resources.groovy is at following path
grails-app/conf/spring/resources.groovy
and your camel-beans.groovy is at following path
grails-app/conf/spring/camel-beans.groovy
then you can reference camel-beans.groovy in resources.groovy file by adding following line in resources.groovy
importBeans('file:**/camel-beans.groovy')
来源:https://stackoverflow.com/questions/24028410/load-spring-beans-from-custom-groovy-files-in-grails-app