mirror of
https://gitee.com/dcren/initializr.git
synced 2025-07-15 14:04:30 +08:00
Cache templates
This commit improves massively class loading performance by caching all templates used by the generator. GroovyTemplate is now a bean rather than a private utility. Templates are cached by default and the cache is disabled automatically if Devtools is in use (via a check of spring.groovy.template.cache). Closes gh-288
This commit is contained in:
parent
dd0442b5de
commit
61cc7eb41d
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2015 the original author or authors.
|
||||
* Copyright 2012-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -18,10 +18,9 @@ package io.spring.initializr.generator
|
||||
|
||||
import io.spring.initializr.metadata.InitializrMetadata
|
||||
import io.spring.initializr.metadata.Type
|
||||
import io.spring.initializr.util.GroovyTemplate
|
||||
import io.spring.initializr.util.VersionRange
|
||||
|
||||
import static io.spring.initializr.util.GroovyTemplate.template
|
||||
|
||||
/**
|
||||
* Generate help pages for command-line clients.
|
||||
*
|
||||
@ -39,6 +38,12 @@ class CommandLineHelpGenerator {
|
||||
=========|_|==============|___/=/_/_/_/
|
||||
'''
|
||||
|
||||
private final GroovyTemplate template
|
||||
|
||||
CommandLineHelpGenerator(GroovyTemplate template) {
|
||||
this.template = template
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the capabilities of the service as a generic plain text
|
||||
* document. Used when no particular agent was detected.
|
||||
@ -46,7 +51,7 @@ class CommandLineHelpGenerator {
|
||||
String generateGenericCapabilities(InitializrMetadata metadata, String serviceUrl) {
|
||||
def model = initializeCommandLineModel(metadata, serviceUrl)
|
||||
model['hasExamples'] = false
|
||||
template 'cli-capabilities.txt', model
|
||||
template.process 'cli-capabilities.txt', model
|
||||
}
|
||||
|
||||
/**
|
||||
@ -55,9 +60,9 @@ class CommandLineHelpGenerator {
|
||||
*/
|
||||
String generateCurlCapabilities(InitializrMetadata metadata, String serviceUrl) {
|
||||
def model = initializeCommandLineModel(metadata, serviceUrl)
|
||||
model['examples'] = template 'curl-examples.txt', model
|
||||
model['examples'] = template.process 'curl-examples.txt', model
|
||||
model['hasExamples'] = true
|
||||
template 'cli-capabilities.txt', model
|
||||
template.process 'cli-capabilities.txt', model
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,9 +71,9 @@ class CommandLineHelpGenerator {
|
||||
*/
|
||||
String generateHttpieCapabilities(InitializrMetadata metadata, String serviceUrl) {
|
||||
def model = initializeCommandLineModel(metadata, serviceUrl)
|
||||
model['examples'] = template 'httpie-examples.txt', model
|
||||
model['examples'] = template.process 'httpie-examples.txt', model
|
||||
model['hasExamples'] = true
|
||||
template 'cli-capabilities.txt', model
|
||||
template.process 'cli-capabilities.txt', model
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,7 +83,7 @@ class CommandLineHelpGenerator {
|
||||
String generateSpringBootCliCapabilities(InitializrMetadata metadata, String serviceUrl) {
|
||||
def model = initializeSpringBootCliModel(metadata, serviceUrl)
|
||||
model['hasExamples'] = false
|
||||
template('boot-cli-capabilities.txt', model)
|
||||
template.process('boot-cli-capabilities.txt', model)
|
||||
}
|
||||
|
||||
protected Map initializeCommandLineModel(InitializrMetadata metadata, serviceUrl) {
|
||||
|
@ -20,6 +20,7 @@ import groovy.util.logging.Slf4j
|
||||
import io.spring.initializr.InitializrException
|
||||
import io.spring.initializr.metadata.Dependency
|
||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||
import io.spring.initializr.util.GroovyTemplate
|
||||
import io.spring.initializr.util.Version
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
@ -28,7 +29,6 @@ import org.springframework.context.ApplicationEventPublisher
|
||||
import org.springframework.util.Assert
|
||||
|
||||
import static io.spring.initializr.metadata.InitializrConfiguration.Env.Maven.ParentPom
|
||||
import static io.spring.initializr.util.GroovyTemplate.template
|
||||
|
||||
/**
|
||||
* Generate a project based on the configured metadata.
|
||||
@ -58,6 +58,9 @@ class ProjectGenerator {
|
||||
@Autowired
|
||||
ProjectRequestResolver requestResolver
|
||||
|
||||
@Autowired
|
||||
GroovyTemplate groovyTemplate = new GroovyTemplate()
|
||||
|
||||
@Autowired
|
||||
ProjectResourceLocator projectResourceLocator = new ProjectResourceLocator()
|
||||
|
||||
@ -321,12 +324,12 @@ class ProjectGenerator {
|
||||
}
|
||||
|
||||
private byte[] doGenerateMavenPom(Map model) {
|
||||
template 'starter-pom.xml', model
|
||||
groovyTemplate.process 'starter-pom.xml', model
|
||||
}
|
||||
|
||||
|
||||
private byte[] doGenerateGradleBuild(Map model) {
|
||||
template 'starter-build.gradle', model
|
||||
groovyTemplate.process 'starter-build.gradle', model
|
||||
}
|
||||
|
||||
private void writeGradleWrapper(File dir) {
|
||||
@ -384,7 +387,7 @@ class ProjectGenerator {
|
||||
|
||||
def write(File target, String templateName, def model) {
|
||||
def tmpl = templateName.endsWith('.groovy') ? templateName + '.tmpl' : templateName
|
||||
def body = template tmpl, model
|
||||
def body = groovyTemplate.process tmpl, model
|
||||
target.write(body)
|
||||
}
|
||||
|
||||
|
@ -16,36 +16,52 @@
|
||||
|
||||
package io.spring.initializr.util
|
||||
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
import groovy.text.GStringTemplateEngine
|
||||
import groovy.text.Template
|
||||
import groovy.text.TemplateEngine
|
||||
import org.codehaus.groovy.control.CompilationFailedException
|
||||
|
||||
import org.springframework.util.ConcurrentReferenceHashMap
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @since 1.0
|
||||
*/
|
||||
class GroovyTemplate {
|
||||
|
||||
// This is a copy/paste from GroovyTemplate in spring-boot-cli. We should migrate
|
||||
// to Spring's native support available in 4.1
|
||||
boolean cache = true
|
||||
|
||||
static String template(String name, Map<String, ?> model) throws IOException,
|
||||
CompilationFailedException, ClassNotFoundException {
|
||||
template(new GStringTemplateEngine(), name, model)
|
||||
private final TemplateEngine engine
|
||||
private final ConcurrentMap<String, Template> templateCaches = new ConcurrentReferenceHashMap<>()
|
||||
|
||||
GroovyTemplate(TemplateEngine engine) {
|
||||
this.engine = engine
|
||||
}
|
||||
|
||||
static String template(TemplateEngine engine, String name, Map<String, ?> model)
|
||||
GroovyTemplate() {
|
||||
this(new GStringTemplateEngine())
|
||||
}
|
||||
|
||||
String process(String name, Map<String, ?> model)
|
||||
throws IOException, CompilationFailedException, ClassNotFoundException {
|
||||
def writable = getTemplate(engine, name).make(model)
|
||||
def template = getTemplate(name)
|
||||
def writable = template.make(model)
|
||||
def result = new StringWriter()
|
||||
writable.writeTo(result)
|
||||
result.toString()
|
||||
}
|
||||
|
||||
static Template getTemplate(TemplateEngine engine, String name)
|
||||
Template getTemplate(String name)
|
||||
throws CompilationFailedException, ClassNotFoundException, IOException {
|
||||
if (cache) {
|
||||
return this.templateCaches.computeIfAbsent(name, { n -> loadTemplate(n) })
|
||||
}
|
||||
return loadTemplate(name)
|
||||
}
|
||||
|
||||
protected Template loadTemplate(String name) {
|
||||
def file = new File("templates", name)
|
||||
if (file.exists()) {
|
||||
return engine.createTemplate(file)
|
||||
@ -59,4 +75,5 @@ class GroovyTemplate {
|
||||
|
||||
return engine.createTemplate(name)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package io.spring.initializr.generator
|
||||
import io.spring.initializr.metadata.Dependency
|
||||
import io.spring.initializr.metadata.Type
|
||||
import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder
|
||||
import io.spring.initializr.util.GroovyTemplate
|
||||
import org.junit.Test
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString
|
||||
@ -30,7 +31,7 @@ import static org.junit.Assert.assertThat
|
||||
*/
|
||||
class CommandLineHelpGeneratorTests {
|
||||
|
||||
private CommandLineHelpGenerator generator = new CommandLineHelpGenerator()
|
||||
private CommandLineHelpGenerator generator = new CommandLineHelpGenerator(new GroovyTemplate())
|
||||
|
||||
@Test
|
||||
void generateGenericCapabilities() {
|
||||
|
@ -18,6 +18,8 @@ package io.spring.initializr.service
|
||||
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||
import io.spring.initializr.util.GroovyTemplate
|
||||
import io.spring.initializr.web.project.LegacyStsController
|
||||
|
||||
import org.springframework.boot.SpringApplication
|
||||
@ -44,8 +46,9 @@ class InitializrService {
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("deprecation")
|
||||
LegacyStsController legacyStsController() {
|
||||
new LegacyStsController()
|
||||
LegacyStsController legacyStsController(InitializrMetadataProvider metadataProvider,
|
||||
GroovyTemplate groovyTemplate) {
|
||||
new LegacyStsController(metadataProvider, groovyTemplate)
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
@ -27,6 +27,7 @@ import io.spring.initializr.metadata.DependencyMetadataProvider
|
||||
import io.spring.initializr.metadata.InitializrMetadataBuilder
|
||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||
import io.spring.initializr.metadata.InitializrProperties
|
||||
import io.spring.initializr.util.GroovyTemplate
|
||||
import io.spring.initializr.web.project.MainController
|
||||
import io.spring.initializr.web.support.DefaultDependencyMetadataProvider
|
||||
import io.spring.initializr.web.support.DefaultInitializrMetadataProvider
|
||||
@ -34,6 +35,7 @@ import io.spring.initializr.web.ui.UiController
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
|
||||
import org.springframework.boot.bind.RelaxedPropertyResolver
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.cache.Cache
|
||||
import org.springframework.cache.CacheManager
|
||||
@ -43,6 +45,7 @@ import org.springframework.cache.concurrent.ConcurrentMapCache
|
||||
import org.springframework.cache.support.SimpleCacheManager
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.core.env.Environment
|
||||
import org.springframework.web.client.RestTemplate
|
||||
|
||||
/**
|
||||
@ -72,8 +75,11 @@ class InitializrAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
MainController initializrMainController() {
|
||||
new MainController()
|
||||
MainController initializrMainController(InitializrMetadataProvider metadataProvider,
|
||||
GroovyTemplate groovyTemplate,
|
||||
ProjectGenerator projectGenerator,
|
||||
DependencyMetadataProvider dependencyMetadataProvider) {
|
||||
new MainController(metadataProvider, groovyTemplate, projectGenerator, dependencyMetadataProvider)
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ -88,6 +94,16 @@ class InitializrAutoConfiguration {
|
||||
new ProjectGenerator()
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
GroovyTemplate groovyTemplate(Environment environment) {
|
||||
def resolver = new RelaxedPropertyResolver(environment, 'spring.groovy.template.')
|
||||
boolean cache = resolver.getProperty('cache', Boolean.class, true)
|
||||
def groovyTemplate = new GroovyTemplate()
|
||||
groovyTemplate.cache = cache
|
||||
groovyTemplate
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
ProjectRequestResolver projectRequestResolver() {
|
||||
|
@ -21,14 +21,12 @@ import javax.servlet.http.HttpServletResponse
|
||||
|
||||
import io.spring.initializr.generator.InvalidProjectRequestException
|
||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||
import io.spring.initializr.util.GroovyTemplate
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder
|
||||
|
||||
import static io.spring.initializr.util.GroovyTemplate.template
|
||||
|
||||
/**
|
||||
* A base controller that uses a {@link InitializrMetadataProvider}
|
||||
*
|
||||
@ -37,11 +35,16 @@ import static io.spring.initializr.util.GroovyTemplate.template
|
||||
*/
|
||||
abstract class AbstractInitializrController {
|
||||
|
||||
@Autowired
|
||||
protected InitializrMetadataProvider metadataProvider
|
||||
|
||||
protected final InitializrMetadataProvider metadataProvider
|
||||
private final GroovyTemplate groovyTemplate
|
||||
private boolean forceSsl
|
||||
|
||||
protected AbstractInitializrController(InitializrMetadataProvider metadataProvider,
|
||||
GroovyTemplate groovyTemplate) {
|
||||
this.metadataProvider = metadataProvider
|
||||
this.groovyTemplate = groovyTemplate
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
void initialize() {
|
||||
forceSsl = metadataProvider.get().configuration.env.forceSsl
|
||||
@ -74,7 +77,7 @@ abstract class AbstractInitializrController {
|
||||
// Google analytics support
|
||||
model['trackingCode'] = metadata.configuration.env.googleAnalyticsTrackingCode
|
||||
|
||||
template templatePath, model
|
||||
groovyTemplate.process templatePath, model
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package io.spring.initializr.web.project
|
||||
|
||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||
import io.spring.initializr.util.GroovyTemplate
|
||||
|
||||
import org.springframework.stereotype.Controller
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.ResponseBody
|
||||
@ -30,6 +33,10 @@ import org.springframework.web.bind.annotation.ResponseBody
|
||||
@Deprecated
|
||||
class LegacyStsController extends AbstractInitializrController {
|
||||
|
||||
LegacyStsController(InitializrMetadataProvider metadataProvider, GroovyTemplate groovyTemplate) {
|
||||
super(metadataProvider, groovyTemplate)
|
||||
}
|
||||
|
||||
@RequestMapping(value = '/sts', produces = 'text/html')
|
||||
@ResponseBody
|
||||
String stsHome() {
|
||||
|
@ -24,7 +24,9 @@ import io.spring.initializr.generator.BasicProjectRequest
|
||||
import io.spring.initializr.generator.CommandLineHelpGenerator
|
||||
import io.spring.initializr.generator.ProjectGenerator
|
||||
import io.spring.initializr.generator.ProjectRequest
|
||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||
import io.spring.initializr.util.Agent
|
||||
import io.spring.initializr.util.GroovyTemplate
|
||||
import io.spring.initializr.web.mapper.DependencyMetadataV21JsonMapper
|
||||
import io.spring.initializr.web.mapper.InitializrMetadataJsonMapper
|
||||
import io.spring.initializr.web.mapper.InitializrMetadataV21JsonMapper
|
||||
@ -67,14 +69,17 @@ class MainController extends AbstractInitializrController {
|
||||
|
||||
static final MediaType HAL_JSON_CONTENT_TYPE = MediaType.parseMediaType('application/hal+json')
|
||||
|
||||
@Autowired
|
||||
private ProjectGenerator projectGenerator
|
||||
|
||||
@Autowired
|
||||
private DependencyMetadataProvider dependencyMetadataProvider
|
||||
|
||||
private CommandLineHelpGenerator commandLineHelpGenerator = new CommandLineHelpGenerator()
|
||||
private final ProjectGenerator projectGenerator
|
||||
private final DependencyMetadataProvider dependencyMetadataProvider
|
||||
private final CommandLineHelpGenerator commandLineHelpGenerator
|
||||
|
||||
MainController(InitializrMetadataProvider metadataProvider, GroovyTemplate groovyTemplate,
|
||||
ProjectGenerator projectGenerator, DependencyMetadataProvider dependencyMetadataProvider) {
|
||||
super(metadataProvider, groovyTemplate)
|
||||
this.projectGenerator = projectGenerator
|
||||
this.dependencyMetadataProvider = dependencyMetadataProvider
|
||||
this.commandLineHelpGenerator = new CommandLineHelpGenerator(groovyTemplate)
|
||||
}
|
||||
|
||||
@ModelAttribute
|
||||
BasicProjectRequest projectRequest(@RequestHeader Map<String,String> headers) {
|
||||
|
Loading…
Reference in New Issue
Block a user