Push deployer configuration out of autoconfig
It tends to pop back into function apps where it is not needed otherwise. Users that want to use the library need to import the FunctionConfiguration directly using the @EnableFunctionDeployer convenience annotation..
This commit is contained in:
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016-2017 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 org.springframework.cloud.function.deployer;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class BeanCountingApplicationListener
|
||||
implements ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware {
|
||||
|
||||
public static final String MARKER = "Invoker app started";
|
||||
private static Log logger = LogFactory.getLog(BeanCountingApplicationListener.class);
|
||||
private ApplicationContext context;
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext context) throws BeansException {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
@Override
|
||||
public void onApplicationEvent(ApplicationReadyEvent event) {
|
||||
if (!event.getApplicationContext().equals(this.context)) {
|
||||
return;
|
||||
}
|
||||
int count = 0;
|
||||
ConfigurableApplicationContext context = event.getApplicationContext();
|
||||
String id = context.getId();
|
||||
List<String> names = new ArrayList<>();
|
||||
while (context != null) {
|
||||
count += context.getBeanDefinitionCount();
|
||||
names.addAll(Arrays.asList(context.getBeanDefinitionNames()));
|
||||
context = (ConfigurableApplicationContext) context.getParent();
|
||||
}
|
||||
logger.info("Bean count: " + id + "=" + count);
|
||||
logger.debug("Bean names: " + id + "=" + names);
|
||||
try {
|
||||
logger.info("Class count: " + id + "=" + ManagementFactory
|
||||
.getClassLoadingMXBean().getTotalLoadedClassCount());
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
if (isSpringBootApplication(sources(event))) {
|
||||
try {
|
||||
logger.info(MARKER);
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSpringBootApplication(Set<Class<?>> sources) {
|
||||
for (Class<?> source : sources) {
|
||||
if (AnnotatedElementUtils.hasAnnotation(source,
|
||||
SpringBootConfiguration.class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private Set<Class<?>> sources(ApplicationReadyEvent event) {
|
||||
Method method = ReflectionUtils.findMethod(SpringApplication.class,
|
||||
"getAllSources");
|
||||
if (method == null) {
|
||||
method = ReflectionUtils.findMethod(SpringApplication.class, "getSources");
|
||||
}
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
@SuppressWarnings("unchecked")
|
||||
Set<Object> objects = (Set<Object>) ReflectionUtils.invokeMethod(method,
|
||||
event.getSpringApplication());
|
||||
Set<Class<?>> result = new LinkedHashSet<>();
|
||||
for (Object object : objects) {
|
||||
if (object instanceof String) {
|
||||
object = ClassUtils.resolveClassName((String) object, null);
|
||||
}
|
||||
result.add((Class<?>) object);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,11 +57,6 @@ public class ContextRunner {
|
||||
running = true;
|
||||
SpringApplicationBuilder builder = builder(
|
||||
ClassUtils.resolveClassName(source, null));
|
||||
if (ClassUtils.isPresent(
|
||||
"org.springframework.cloud.stream.app.function.app.BeanCountingApplicationListener.BeanCountingApplicationListener()",
|
||||
null)) {
|
||||
builder.listeners(new BeanCountingApplicationListener());
|
||||
}
|
||||
context = builder.environment(environment).registerShutdownHook(false)
|
||||
.run(args);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2016-2017 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 org.springframework.cloud.function.deployer;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* Annotation to be used on a Spring Boot application if it wants to deploy a jar file
|
||||
* containing a function definition.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import(FunctionDeployerConfiguration.class)
|
||||
public @interface EnableFunctionDeployer {
|
||||
|
||||
}
|
||||
@@ -25,6 +25,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableFunctionDeployer
|
||||
public class FunctionApplication {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
@@ -25,13 +25,12 @@ import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -46,25 +45,17 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.loader.JarLauncher;
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
import org.springframework.cloud.deployer.resource.maven.MavenProperties;
|
||||
import org.springframework.cloud.deployer.resource.maven.MavenResource;
|
||||
import org.springframework.cloud.deployer.resource.maven.MavenResourceLoader;
|
||||
import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader;
|
||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||
import org.springframework.cloud.function.context.FunctionRegistry;
|
||||
import org.springframework.cloud.function.context.FunctionType;
|
||||
import org.springframework.cloud.function.context.catalog.FunctionInspector;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
@@ -83,10 +74,9 @@ import org.springframework.util.StreamUtils;
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties
|
||||
public class FunctionConfiguration {
|
||||
class FunctionCreatorConfiguration {
|
||||
|
||||
private static Log logger = LogFactory.getLog(FunctionConfiguration.class);
|
||||
private static Log logger = LogFactory.getLog(FunctionCreatorConfiguration.class);
|
||||
|
||||
@Autowired
|
||||
private FunctionRegistry registry;
|
||||
@@ -104,27 +94,6 @@ public class FunctionConfiguration {
|
||||
|
||||
private BeanCreator creator;
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("maven")
|
||||
public MavenProperties mavenProperties() {
|
||||
return new MavenProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("function")
|
||||
public FunctionProperties functionProperties() {
|
||||
return new FunctionProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(DelegatingResourceLoader.class)
|
||||
public DelegatingResourceLoader delegatingResourceLoader(
|
||||
MavenProperties mavenProperties) {
|
||||
Map<String, ResourceLoader> loaders = new HashMap<>();
|
||||
loaders.put(MavenResource.URI_SCHEME, new MavenResourceLoader(mavenProperties));
|
||||
return new DelegatingResourceLoader(loaders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a function for each of the function classes passed into the
|
||||
* {@link FunctionProperties}. They are named sequentially "function0", "function1",
|
||||
@@ -222,6 +191,13 @@ public class FunctionConfiguration {
|
||||
public URL[] getClassLoaderUrls() throws Exception {
|
||||
List<Archive> archives = getClassPathArchives();
|
||||
if (archives.isEmpty()) {
|
||||
URL url = getArchive().getUrl();
|
||||
if (url.toString().contains(".jar")) { // Surefire or IntelliJ?
|
||||
URL[] classpath = extractClasspath(url.toString());
|
||||
if (classpath != null) {
|
||||
return classpath;
|
||||
}
|
||||
}
|
||||
return new URL[] { getArchive().getUrl() };
|
||||
}
|
||||
return archives.stream().map(archive -> {
|
||||
@@ -234,6 +210,36 @@ public class FunctionConfiguration {
|
||||
}).collect(Collectors.toList()).toArray(new URL[0]);
|
||||
}
|
||||
|
||||
private URL[] extractClasspath(String url) {
|
||||
// This works for a jar indirection like in surefire and IntelliJ
|
||||
if (url.endsWith(".jar!/")) {
|
||||
url = url.substring(0, url.length() - "!/".length());
|
||||
if (url.startsWith("jar:")) {
|
||||
url = url.substring("jar:".length());
|
||||
}
|
||||
if (url.startsWith("file:")) {
|
||||
url = url.substring("file:".length());
|
||||
}
|
||||
}
|
||||
if (url.endsWith(".jar")) {
|
||||
JarFile jar;
|
||||
try {
|
||||
jar = new JarFile(new File(url));
|
||||
String path = jar.getManifest().getMainAttributes()
|
||||
.getValue("Class-Path");
|
||||
if (path != null) {
|
||||
List<URL> result = new ArrayList<>();
|
||||
for (String element : path.split(" ")) {
|
||||
result.add(new URL(element));
|
||||
}
|
||||
return result.toArray(new URL[0]);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +275,8 @@ public class FunctionConfiguration {
|
||||
runner.run("--spring.main.webEnvironment=false",
|
||||
"--spring.cloud.stream.enabled=false",
|
||||
"--spring.main.bannerMode=OFF",
|
||||
"--spring.main.webApplicationType=none");
|
||||
"--spring.main.webApplicationType=none",
|
||||
"--function.deployer.enabled=false");
|
||||
this.runner = runner;
|
||||
}
|
||||
finally {
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2016-2017 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 org.springframework.cloud.function.deployer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.deployer.resource.maven.MavenProperties;
|
||||
import org.springframework.cloud.deployer.resource.maven.MavenResource;
|
||||
import org.springframework.cloud.deployer.resource.maven.MavenResourceLoader;
|
||||
import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(prefix = "function.deployer", name = "enabled", matchIfMissing = true)
|
||||
@EnableConfigurationProperties
|
||||
@Import(FunctionCreatorConfiguration.class)
|
||||
public class FunctionDeployerConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("maven")
|
||||
public MavenProperties mavenProperties() {
|
||||
return new MavenProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("function")
|
||||
public FunctionProperties functionProperties() {
|
||||
return new FunctionProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(DelegatingResourceLoader.class)
|
||||
public DelegatingResourceLoader delegatingResourceLoader(
|
||||
MavenProperties mavenProperties) {
|
||||
Map<String, ResourceLoader> loaders = new HashMap<>();
|
||||
loaders.put(MavenResource.URI_SCHEME, new MavenResourceLoader(mavenProperties));
|
||||
return new DelegatingResourceLoader(loaders);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.function.deployer.FunctionConfiguration
|
||||
Reference in New Issue
Block a user