Загрузите spring bean-компоненты из пользовательских файлов groovy в приложении Grails

Попытка загрузить bean-компоненты Spring из пользовательского файла groovy в Grails 2.3.7. Я знаю, что этот вопрос уже задавали раньше, но после нескольких часов поиска я не смог найти последовательный подход, который загружается из пути к классам.

Цель

  • Модульность resources.groovy в несколько пользовательских файлов ресурсов
  • Поместите пользовательские файлы ресурсов в стандартное расположение: grails-app/conf/spring
  • Используйте плагин, чтобы творить чудеса; минимизировать накладные расходы

Пытался...

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

Обратите внимание, что я использую beans {}, а не beans = {}, очевидно это имеет значение:

resources.groovy

Это работает...

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

...и, согласно документам, это тоже должно, но не:

importBeans("classpath:*MyBeansConfig.groovy")

ОБНОВЛЕНИЕ - РАБОЧИЕ ВАРИАНТЫ

(работает с Grails 2.3.7)

Вариант 1: (источник/java)

Следуя совету lukelazarovic, этот подход работает, поскольку Grails автоматически копирует (а не компилирует) файлы groovy в src/java в classpath; отлично работает в eclipse и с военным развертыванием:

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

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

Вариант 2: (grails-app/conf/spring)

Этот подход позволяет создавать пользовательские файлы конфигурации bean-компонентов в grails-app/conf/spring (спасибо автор идей и 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

Никакой конфигурации!... просто создайте файлы конфигурации bean-компонента, используя соглашение *BeansConfig.groovy, готово!

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

Обновление от 24.09.2015

Обнаружены некоторые проблемы с вариантом 3:

  • загрузка дубликатов файлов ресурсов
  • ресурсы Spring неправильно настроены для test-app

Нам удалось исправить указанную выше проблему, чтобы все файлы ресурсов в grails-app/conf/spring работали одинаково при выполнении Grails в eclipse, WAR, test-app и т. д.

Первый шаг: мы создали класс, чтобы лучше контролировать поиск и загрузку файлов ресурсов; это было необходимо, так как некоторые файлы загружались более одного раза из-за перекрестных ссылок 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.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)
   }
}

Убран суффикс 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.


person raffian    schedule 04.06.2014    source источник
comment
Я ценю, что вы собрали всю вышеуказанную информацию! Спасибо!   -  person mowwwalker    schedule 23.09.2015
comment
@mowwwalker спасибо, что напомнили мне обновить этот пост! см. изменения выше, надеюсь, это поможет!   -  person raffian    schedule 24.09.2015


Ответы (4)


У меня была аналогичная проблема всего несколько дней назад с отличным файлом конфигурации, который я добавил в grails-app/conf. Хотя это работает с другими ресурсами (они копируются и доступны в пути к классам), проблема с файлом groovy заключалась просто в том, что он был скомпилирован и был включен файл класса, то есть не сам файл groovy.

Я не нашел хорошей документации о том, как это следует сделать, и, наконец, просто добавил ее в web-app/WEB-INF/classes. Размещенные здесь файлы Groovy будут скопированы (не скомпилированы) и доступны в пути к классам.

person Steinar    schedule 04.06.2014

У меня была такая же проблема с пользовательскими файлами XML в Grails 2.1.2.

Наличие XML-ресурсов в grails-app/conf/spring не работало в производственной среде AFAIR.

Чтобы заставить его работать как в среде разработки, так и в рабочей среде, я, наконец, поместил ресурсы в src/java. Я думаю, вы можете добиться того же результата, поместив свои заводные файлы в src/groovy.

person lukelazarovic    schedule 04.06.2014
comment
src/java должен работать, но src/groovy, я думаю, скомпилирует класс, я помню, что читал что-то об этом прошлой ночью, можете ли вы подтвердить? - person raffian; 04.06.2014
comment
Я не уверен, что вы имеете в виду - все файлы groovy, в том числе файлы в приложении grails, компилируются в файлы классов, когда вы запускаете войну grails - person lukelazarovic; 04.06.2014
comment
Я знаю, но loadBeans() читает файл groovy, он не будет работать с файлами классов; когда файлы конфигурации находятся в src/groovy, он не работает (только что проверил) - person raffian; 04.06.2014

Мы также можем импортировать bean-компоненты из другого файла groovy/xml следующим образом: - используйте следующее в resources.groovy -

importBeans 'file:camel-beans.groovy' ИЛИ ​​importBeans('classpath:/camel-config.xml')

Поместите camel-beans.groovy вместе с resources.groovy и предоставьте пакет как «пружину пакета» для первого случая, в противном случае поместите его в путь к классам веб-приложения и используйте второй способ сделать это.

person Nitesh Saxena    schedule 22.08.2016

Если ваш resources.groovy находится по следующему пути

grails-app/conf/spring/resources.groovy

и ваш camel-beans.groovy находится по следующему пути

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

затем вы можете сослаться на camel-beans.groovy в файле resources.groovy, добавив следующую строку в resources.groovy

importBeans('file:**/camel-beans.groovy')
person Aamir Ali    schedule 27.02.2017