Skip to content

Commit

Permalink
Make sure the application and pluginManager are only created once, an…
Browse files Browse the repository at this point in the history
…d combine scanning and non scanning configuration classes into one to simplify things
  • Loading branch information
graemerocher committed May 28, 2014
1 parent fc681b1 commit ec766ca
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 111 deletions.
@@ -1,52 +1,90 @@
package grails.boot.config

import groovy.transform.CompileStatic
import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.codehaus.groovy.grails.plugins.DefaultGrailsPluginManager
import org.codehaus.groovy.grails.plugins.GrailsPluginManager
import org.grails.boot.support.GrailsPluginManagerPostProcessor
import org.grails.boot.support.GrailsApplicationPostProcessor
import org.springframework.context.ResourceLoaderAware
import org.springframework.context.annotation.Bean
import org.springframework.core.io.Resource
import org.springframework.core.io.ResourceLoader
import org.springframework.core.io.support.PathMatchingResourcePatternResolver
import org.springframework.core.io.support.ResourcePatternResolver
import org.springframework.core.type.classreading.CachingMetadataReaderFactory
import org.springframework.util.ClassUtils

/**
* A handy utility class for creating a Grails Boot configuration
* A Grails configuration that scans for classes using the packages defined by the packages() method and creates the necessary
* {@link org.codehaus.groovy.grails.commons.GrailsApplication} and {@link org.codehaus.groovy.grails.plugins.GrailsPluginManager} beans
* that constitute a Grails application.
*
* @see GrailsApplicationPostProcessor
*
* @author Graeme Rocher
* @since 3.0
*/
@CompileStatic
abstract class GrailsConfiguration {
class GrailsConfiguration implements ResourceLoaderAware {

/**
* @return The classes that constitute the Grails application
*/
abstract Collection<Class> classes()
public static final String CLASS_RESOURCE_PATTERN = "/**/*.class"

ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver()

/**
* @return The {@link GrailsApplication} instance
* @return A post processor that uses the {@link org.codehaus.groovy.grails.plugins.GrailsPluginManager} to configure the {@link org.springframework.context.ApplicationContext}
*/
@Bean(destroyMethod = 'clear')
GrailsApplication grailsApplication() {
def application = new DefaultGrailsApplication( classes() as Class[] )
application.initialise()
return application
@Bean
GrailsApplicationPostProcessor grailsApplicationPostProcessor() {
return new GrailsApplicationPostProcessor(classes() as Class[])
}

/**
* @return The {@link GrailsPluginManager} instance
* @return The classes that constitute the Grails application
*/
@Bean(destroyMethod = 'shutdown')
GrailsPluginManager pluginManager() {
def manager = new DefaultGrailsPluginManager(grailsApplication())
manager.loadPlugins()
return manager
Collection<Class> classes() {
def readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver)
def packages = packages()
Collection<Class> classes = []
for (pkg in packages) {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(pkg.name) + CLASS_RESOURCE_PATTERN;

classes.addAll scanUsingPattern(pattern, readerFactory)
}

// try the default package in case of a script without recursing into subpackages
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "*.class"
classes.addAll scanUsingPattern(pattern, readerFactory)


return classes
}

/**
* @return A post processor that uses the {@link GrailsPluginManager} to configure the {@link org.springframework.context.ApplicationContext}
* @return The packages to scan
*/
@Bean
GrailsPluginManagerPostProcessor pluginManagerPostProcessor() {
return new GrailsPluginManagerPostProcessor(pluginManager())
Collection<Package> packages() {
[ getClass().package ]
}

@Override
void setResourceLoader(ResourceLoader resourceLoader) {
this.resourcePatternResolver = new PathMatchingResourcePatternResolver(resourceLoader)
}

private Collection<Class> scanUsingPattern(String pattern, CachingMetadataReaderFactory readerFactory) {
def resources = this.resourcePatternResolver.getResources(pattern)
def classLoader = Thread.currentThread().contextClassLoader
Collection<Class> classes = []
for (Resource res in resources) {
// ignore closures / inner classes
if(!res.filename.contains('$')) {
def reader = readerFactory.getMetadataReader(res)
def metadata = reader.annotationMetadata
if (metadata.annotationTypes.any() { String annotation -> annotation.startsWith('grails.') }) {
classes << classLoader.loadClass(reader.classMetadata.className)
}
}
}
return classes
}

}

This file was deleted.

@@ -1,7 +1,10 @@
package org.grails.boot.support

import groovy.transform.CompileStatic
import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.codehaus.groovy.grails.commons.spring.DefaultRuntimeSpringConfiguration
import org.codehaus.groovy.grails.plugins.DefaultGrailsPluginManager
import org.codehaus.groovy.grails.plugins.GrailsPluginManager
import org.springframework.beans.BeansException
import org.springframework.beans.factory.ListableBeanFactory
Expand All @@ -21,12 +24,16 @@ import org.springframework.context.event.ContextRefreshedEvent
* @since 3.0
*/
@CompileStatic
class GrailsPluginManagerPostProcessor implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
class GrailsApplicationPostProcessor implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {

GrailsApplication grailsApplication
GrailsPluginManager pluginManager

GrailsPluginManagerPostProcessor(GrailsPluginManager pluginManager) {
this.pluginManager = pluginManager
GrailsApplicationPostProcessor(Class...classes) {
grailsApplication = new DefaultGrailsApplication( classes as Class[] )
grailsApplication.initialise()
pluginManager = new DefaultGrailsPluginManager(grailsApplication)
pluginManager.loadPlugins()
}

@Override
Expand All @@ -40,7 +47,8 @@ class GrailsPluginManagerPostProcessor implements BeanDefinitionRegistryPostProc

@Override
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

beanFactory.registerSingleton(GrailsApplication.APPLICATION_ID, grailsApplication)
beanFactory.registerSingleton(GrailsPluginManager.BEAN_NAME, pluginManager)
}

@Override
Expand Down
Expand Up @@ -2,7 +2,6 @@ package grails.boot

import grails.artefact.Artefact
import grails.boot.config.GrailsConfiguration
import grails.boot.config.ScanningGrailsConfiguration
import grails.web.Controller
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory
Expand Down Expand Up @@ -33,7 +32,7 @@ class EmbeddedContainerWithGrailsSpec extends Specification {
}

@Configuration
static class Application extends ScanningGrailsConfiguration {
static class Application extends GrailsConfiguration {
@Bean
public EmbeddedServletContainerFactory containerFactory() {
return new TomcatEmbeddedServletContainerFactory(0);
Expand All @@ -50,6 +49,8 @@ class FooController {
def list() {
render "all foos"
}

def closure = {}
}

@Artefact('UrlMappings')
Expand Down
@@ -1,15 +1,12 @@
package grails.boot

import grails.boot.config.GrailsConfiguration
import grails.boot.config.ScanningGrailsConfiguration
import org.springframework.boot.SpringApplication
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory
import org.springframework.context.ApplicationContext
import org.springframework.context.ConfigurableApplicationContext
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import spock.lang.Specification

/**
Expand All @@ -34,7 +31,7 @@ class GrailsSpringApplicationSpec extends Specification{


@Configuration
static class Application extends ScanningGrailsConfiguration {
static class Application extends GrailsConfiguration {
@Bean
public EmbeddedServletContainerFactory containerFactory() {
return new TomcatEmbeddedServletContainerFactory(0);
Expand Down

0 comments on commit ec766ca

Please sign in to comment.