mirror of
https://gitee.com/dcren/initializr.git
synced 2025-09-19 10:08:22 +08:00
@@ -7,6 +7,7 @@ order.
|
|||||||
|
|
||||||
=== Release 1.0.0 (In progress)
|
=== Release 1.0.0 (In progress)
|
||||||
|
|
||||||
|
* https://github.com/spring-io/initializr/issues/96[#96]: export service metrics to redis
|
||||||
* https://github.com/spring-io/initializr/issues/115[#115]: rename /metadata/service to /metadata/config
|
* https://github.com/spring-io/initializr/issues/115[#115]: rename /metadata/service to /metadata/config
|
||||||
* https://github.com/spring-io/initializr/issues/89[#89]: better describe service capability
|
* https://github.com/spring-io/initializr/issues/89[#89]: better describe service capability
|
||||||
* https://github.com/spring-io/initializr/issues/105[#105]: support for dependencies group defaults
|
* https://github.com/spring-io/initializr/issues/105[#105]: support for dependencies group defaults
|
||||||
|
3
initializr-service/application-cloud.yml
Normal file
3
initializr-service/application-cloud.yml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
spring:
|
||||||
|
metrics:
|
||||||
|
export: enabled
|
@@ -6,3 +6,5 @@ applications:
|
|||||||
host: start-development
|
host: start-development
|
||||||
domain: cfapps.io
|
domain: cfapps.io
|
||||||
path: .
|
path: .
|
||||||
|
services:
|
||||||
|
start-redis
|
||||||
|
@@ -25,12 +25,12 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-redis</artifactId>
|
<artifactId>spring-boot-starter-groovy-templates</artifactId>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-groovy-templates</artifactId>
|
<artifactId>spring-boot-starter-redis</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.fasterxml.jackson.core</groupId>
|
<groupId>com.fasterxml.jackson.core</groupId>
|
||||||
|
@@ -39,15 +39,19 @@ import org.springframework.scheduling.annotation.Scheduled
|
|||||||
import org.springframework.util.ObjectUtils
|
import org.springframework.util.ObjectUtils
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
|
||||||
|
* Auto-configuration} to export the metrics of an initializr instnace.
|
||||||
*
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@ConditionalOnBean(RedisConnectionFactory)
|
@ConditionalOnBean(RedisConnectionFactory)
|
||||||
@ConditionalOnProperty(value='spring.metrics.export.enabled', matchIfMissing=true)
|
@ConditionalOnProperty(value = 'spring.metrics.export.enabled')
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
@EnableConfigurationProperties(MetricsProperties)
|
@EnableConfigurationProperties(MetricsProperties)
|
||||||
@AutoConfigureAfter(value=RedisAutoConfiguration, name="org.springframework.boot.actuate.autoconfigure.MetricExportAutoConfiguration")
|
@AutoConfigureAfter(value = RedisAutoConfiguration,
|
||||||
|
name = "org.springframework.boot.actuate.autoconfigure.MetricExportAutoConfiguration")
|
||||||
class InitializrMetricsExporterAutoConfiguration {
|
class InitializrMetricsExporterAutoConfiguration {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -58,19 +62,19 @@ class InitializrMetricsExporterAutoConfiguration {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
ApplicationContext context
|
ApplicationContext context
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
// @ExportMetricWriter // Add this when upgrading to Boot 1.3
|
// @ExportMetricWriter // Add this when upgrading to Boot 1.3
|
||||||
MetricWriter writer() {
|
MetricWriter writer() {
|
||||||
new RedisMetricRepository(connectionFactory,
|
new RedisMetricRepository(connectionFactory,
|
||||||
metrics.prefix + metrics.getId(context.getId()) + '.'
|
metrics.prefix + metrics.getId(context.getId()) + '.'
|
||||||
+ ObjectUtils.getIdentityHexString(context) + '.',
|
+ ObjectUtils.getIdentityHexString(context) + '.',
|
||||||
metrics.key)
|
metrics.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove this when upgrading to Boot 1.3
|
// Remove this when upgrading to Boot 1.3
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingClass(name='org.springframework.boot.actuate.autoconfigure.ActuatorMetricWriter')
|
@ConditionalOnMissingClass(name = 'org.springframework.boot.actuate.autoconfigure.ActuatorMetricWriter')
|
||||||
@Primary
|
@Primary
|
||||||
MetricRepository reader() {
|
MetricRepository reader() {
|
||||||
new InMemoryMetricRepository()
|
new InMemoryMetricRepository()
|
||||||
@@ -78,15 +82,15 @@ class InitializrMetricsExporterAutoConfiguration {
|
|||||||
|
|
||||||
// Remove this when upgrading to Boot 1.3
|
// Remove this when upgrading to Boot 1.3
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingClass(name='org.springframework.boot.actuate.autoconfigure.ActuatorMetricWriter')
|
@ConditionalOnMissingClass(name = 'org.springframework.boot.actuate.autoconfigure.ActuatorMetricWriter')
|
||||||
Exporter exporter(InMemoryMetricRepository reader) {
|
Exporter exporter(InMemoryMetricRepository reader) {
|
||||||
new MetricCopyExporter(reader, writer()) {
|
new MetricCopyExporter(reader, writer()) {
|
||||||
@Override
|
@Override
|
||||||
@Scheduled(fixedRateString = '${spring.metrics.export.default.delayMillis:5000}')
|
@Scheduled(fixedRateString = '${spring.metrics.export.default.delayMillis:5000}')
|
||||||
void export() {
|
void export() {
|
||||||
super.export()
|
super.export()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -16,12 +16,14 @@
|
|||||||
|
|
||||||
package io.spring.initializr.config
|
package io.spring.initializr.config
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* Metrics-related configuration.
|
||||||
*
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties('initializr.metrics')
|
@ConfigurationProperties('initializr.metrics')
|
||||||
class MetricsProperties {
|
class MetricsProperties {
|
||||||
@@ -51,10 +53,6 @@ class MetricsProperties {
|
|||||||
@Value('${spring.metrics.export.default.delayMillis:5000}')
|
@Value('${spring.metrics.export.default.delayMillis:5000}')
|
||||||
long rateMillis = 5000L
|
long rateMillis = 5000L
|
||||||
|
|
||||||
boolean isEnabled() {
|
|
||||||
rateMillis > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
String getPrefix() {
|
String getPrefix() {
|
||||||
if (prefix.endsWith('.')) {
|
if (prefix.endsWith('.')) {
|
||||||
return prefix
|
return prefix
|
||||||
|
@@ -20,15 +20,13 @@ import com.fasterxml.jackson.annotation.JsonIgnore
|
|||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration of the initializr service.
|
* Configuration of the initializr service.
|
||||||
*
|
*
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
@ConfigurationProperties(prefix = 'initializr', ignoreUnknownFields = false)
|
@ConfigurationProperties(prefix = 'initializr')
|
||||||
class InitializrProperties extends InitializrConfiguration {
|
class InitializrProperties extends InitializrConfiguration {
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
|
@@ -14,21 +14,19 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.spring.initializr.metrics;
|
package io.spring.initializr.metrics
|
||||||
|
|
||||||
import static org.junit.Assert.*
|
|
||||||
import io.spring.initializr.generator.ProjectGenerationMetricsListener
|
import io.spring.initializr.generator.ProjectGenerationMetricsListener
|
||||||
import io.spring.initializr.generator.ProjectRequest
|
import io.spring.initializr.generator.ProjectRequest
|
||||||
import io.spring.initializr.metadata.DefaultMetadataElement
|
|
||||||
import io.spring.initializr.metadata.InitializrMetadata
|
import io.spring.initializr.metadata.InitializrMetadata
|
||||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||||
import io.spring.initializr.support.DefaultInitializrMetadataProvider
|
import io.spring.initializr.test.OfflineInitializrMetadataProvider
|
||||||
import io.spring.initializr.test.RedisRunning
|
import io.spring.initializr.test.RedisRunning
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
import org.springframework.beans.factory.annotation.Qualifier
|
import org.springframework.beans.factory.annotation.Qualifier
|
||||||
import org.springframework.boot.actuate.metrics.repository.redis.RedisMetricRepository
|
import org.springframework.boot.actuate.metrics.repository.redis.RedisMetricRepository
|
||||||
@@ -39,41 +37,44 @@ import org.springframework.boot.test.SpringApplicationConfiguration
|
|||||||
import org.springframework.context.annotation.Bean
|
import org.springframework.context.annotation.Bean
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner)
|
@RunWith(SpringJUnit4ClassRunner)
|
||||||
@SpringApplicationConfiguration(classes = Config)
|
@SpringApplicationConfiguration(classes = Config)
|
||||||
@IntegrationTest(['spring.metrics.export.default.delayMillis:500','initializr.metrics.prefix:test.prefix','initializr.metrics.key:key.test'])
|
@IntegrationTest(['spring.metrics.export.default.delayMillis:500',
|
||||||
|
'spring.metrics.export.enabled:true',
|
||||||
|
'initializr.metrics.prefix:test.prefix', 'initializr.metrics.key:key.test'])
|
||||||
public class MetricsExportTests {
|
public class MetricsExportTests {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public RedisRunning running = new RedisRunning()
|
public RedisRunning running = new RedisRunning()
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
ProjectGenerationMetricsListener listener
|
ProjectGenerationMetricsListener listener
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("writer")
|
@Qualifier("writer")
|
||||||
MetricWriter writer
|
MetricWriter writer
|
||||||
|
|
||||||
RedisMetricRepository repository
|
RedisMetricRepository repository
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
void init() {
|
void init() {
|
||||||
repository = (RedisMetricRepository) writer
|
repository = (RedisMetricRepository) writer
|
||||||
repository.findAll().each {
|
repository.findAll().each {
|
||||||
repository.reset(it.name)
|
repository.reset(it.name)
|
||||||
}
|
}
|
||||||
assertTrue("Metrics not empty", repository.findAll().size()==0)
|
assertTrue("Metrics not empty", repository.findAll().size() == 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void exportAndCheckMetricsExist() {
|
void exportAndCheckMetricsExist() {
|
||||||
listener.onGeneratedProject(new ProjectRequest())
|
listener.onGeneratedProject(new ProjectRequest())
|
||||||
Thread.sleep(1000L)
|
Thread.sleep(1000L)
|
||||||
assertTrue("No metrics exported", repository.findAll().size()>0)
|
assertTrue("No metrics exported", repository.findAll().size() > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@EnableAutoConfiguration
|
@EnableAutoConfiguration
|
||||||
@@ -81,12 +82,7 @@ public class MetricsExportTests {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
InitializrMetadataProvider initializrMetadataProvider(InitializrMetadata metadata) {
|
InitializrMetadataProvider initializrMetadataProvider(InitializrMetadata metadata) {
|
||||||
new DefaultInitializrMetadataProvider(metadata) {
|
new OfflineInitializrMetadataProvider(metadata)
|
||||||
@Override
|
|
||||||
protected List<DefaultMetadataElement> fetchBootVersions() {
|
|
||||||
null // Disable metadata fetching from spring.io
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012-2015 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.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.spring.initializr.test
|
||||||
|
|
||||||
|
import io.spring.initializr.metadata.DefaultMetadataElement
|
||||||
|
import io.spring.initializr.metadata.InitializrMetadata
|
||||||
|
import io.spring.initializr.support.DefaultInitializrMetadataProvider
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link DefaultInitializrMetadataProvider} that does not attempt to
|
||||||
|
* use the network to refresh its configuration.
|
||||||
|
*
|
||||||
|
* @author Stephane Nicoll
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
class OfflineInitializrMetadataProvider extends DefaultInitializrMetadataProvider {
|
||||||
|
|
||||||
|
OfflineInitializrMetadataProvider(InitializrMetadata metadata) {
|
||||||
|
super(metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<DefaultMetadataElement> fetchBootVersions() {
|
||||||
|
null // Disable metadata fetching from spring.io
|
||||||
|
}
|
||||||
|
}
|
@@ -20,19 +20,22 @@ import org.junit.Assume
|
|||||||
import org.junit.rules.TestWatcher
|
import org.junit.rules.TestWatcher
|
||||||
import org.junit.runner.Description
|
import org.junit.runner.Description
|
||||||
import org.junit.runners.model.Statement
|
import org.junit.runners.model.Statement
|
||||||
|
|
||||||
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory
|
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Dave Syer
|
* A {@link org.junit.rules.TestRule} that validates Redis is available.
|
||||||
*
|
*
|
||||||
|
* @author Dave Syer
|
||||||
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
class RedisRunning extends TestWatcher {
|
class RedisRunning extends TestWatcher {
|
||||||
|
|
||||||
JedisConnectionFactory connectionFactory;
|
JedisConnectionFactory connectionFactory;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
Statement apply(Statement base, Description description) {
|
Statement apply(Statement base, Description description) {
|
||||||
if (connectionFactory==null) {
|
if (connectionFactory == null) {
|
||||||
connectionFactory = new JedisConnectionFactory()
|
connectionFactory = new JedisConnectionFactory()
|
||||||
connectionFactory.afterPropertiesSet()
|
connectionFactory.afterPropertiesSet()
|
||||||
}
|
}
|
||||||
|
@@ -19,10 +19,9 @@ package io.spring.initializr.web
|
|||||||
import java.nio.charset.Charset
|
import java.nio.charset.Charset
|
||||||
|
|
||||||
import io.spring.initializr.mapper.InitializrMetadataVersion
|
import io.spring.initializr.mapper.InitializrMetadataVersion
|
||||||
import io.spring.initializr.metadata.DefaultMetadataElement
|
|
||||||
import io.spring.initializr.metadata.InitializrMetadata
|
import io.spring.initializr.metadata.InitializrMetadata
|
||||||
import io.spring.initializr.support.DefaultInitializrMetadataProvider
|
|
||||||
import io.spring.initializr.metadata.InitializrMetadataProvider
|
import io.spring.initializr.metadata.InitializrMetadataProvider
|
||||||
|
import io.spring.initializr.test.OfflineInitializrMetadataProvider
|
||||||
import io.spring.initializr.test.ProjectAssert
|
import io.spring.initializr.test.ProjectAssert
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@@ -85,7 +84,7 @@ abstract class AbstractInitializrControllerIntegrationTests {
|
|||||||
*/
|
*/
|
||||||
protected void validateContentType(ResponseEntity<String> response, MediaType expected) {
|
protected void validateContentType(ResponseEntity<String> response, MediaType expected) {
|
||||||
def actual = response.headers.getContentType()
|
def actual = response.headers.getContentType()
|
||||||
assertTrue "Non compatible media-type, expected $expected, got $actual" ,
|
assertTrue "Non compatible media-type, expected $expected, got $actual",
|
||||||
actual.isCompatibleWith(expected)
|
actual.isCompatibleWith(expected)
|
||||||
assertEquals 'All text content should be UTF-8 encoded',
|
assertEquals 'All text content should be UTF-8 encoded',
|
||||||
'UTF-8', actual.getParameter('charset')
|
'UTF-8', actual.getParameter('charset')
|
||||||
@@ -93,7 +92,7 @@ abstract class AbstractInitializrControllerIntegrationTests {
|
|||||||
|
|
||||||
|
|
||||||
protected void validateMetadata(ResponseEntity<String> response, MediaType mediaType,
|
protected void validateMetadata(ResponseEntity<String> response, MediaType mediaType,
|
||||||
String version, JSONCompareMode compareMode) {
|
String version, JSONCompareMode compareMode) {
|
||||||
validateContentType(response, mediaType)
|
validateContentType(response, mediaType)
|
||||||
def json = new JSONObject(response.body)
|
def json = new JSONObject(response.body)
|
||||||
def expected = readMetadataJson(version)
|
def expected = readMetadataJson(version)
|
||||||
@@ -147,7 +146,7 @@ abstract class AbstractInitializrControllerIntegrationTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected <T> ResponseEntity<T> execute(String contextPath, Class<T> responseType,
|
protected <T> ResponseEntity<T> execute(String contextPath, Class<T> responseType,
|
||||||
String userAgentHeader, String... acceptHeaders) {
|
String userAgentHeader, String... acceptHeaders) {
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
if (userAgentHeader) {
|
if (userAgentHeader) {
|
||||||
headers.set("User-Agent", userAgentHeader);
|
headers.set("User-Agent", userAgentHeader);
|
||||||
@@ -217,12 +216,7 @@ abstract class AbstractInitializrControllerIntegrationTests {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
InitializrMetadataProvider initializrMetadataProvider(InitializrMetadata metadata) {
|
InitializrMetadataProvider initializrMetadataProvider(InitializrMetadata metadata) {
|
||||||
new DefaultInitializrMetadataProvider(metadata) {
|
new OfflineInitializrMetadataProvider(metadata)
|
||||||
@Override
|
|
||||||
protected List<DefaultMetadataElement> fetchBootVersions() {
|
|
||||||
null // Disable metadata fetching from spring.io
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user