Add support for detecting FunctionRegistration or Function
User can now provide a Function or an ApplicationInitializer. Also the initializer can create a FunctionRegistration with the handler name instead of a bean with the handler name. Better control of input and output types that way. Fixes gh-231
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>flux-sample</artifactId>
|
||||
<version>1.0.0.M1</version>
|
||||
<version>1.0.0.RC1</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
@@ -18,7 +18,7 @@
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud-function.version>2.0.0.BUILD-SNAPSHOT</spring-cloud-function.version>
|
||||
<wrapper.version>1.0.15.RELEASE</wrapper.version>
|
||||
<wrapper.version>1.0.17.RELEASE</wrapper.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<spring-cloud-function.version>2.0.0.BUILD-SNAPSHOT</spring-cloud-function.version>
|
||||
<wrapper.version>1.0.12.RELEASE</wrapper.version>
|
||||
<wrapper.version>1.0.17.RELEASE</wrapper.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -18,13 +18,10 @@ package org.springframework.cloud.function.deployer;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.cloud.function.context.FunctionalSpringApplication;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
@@ -59,16 +56,7 @@ public class ContextRunner {
|
||||
new MapPropertySource("appDeployer", properties));
|
||||
running = true;
|
||||
Class<?> sourceClass = ClassUtils.resolveClassName(source, null);
|
||||
ApplicationContextInitializer<?> initializer = null;
|
||||
if (ApplicationContextInitializer.class.isAssignableFrom(sourceClass)) {
|
||||
initializer = BeanUtils.instantiateClass(sourceClass, ApplicationContextInitializer.class);
|
||||
sourceClass = Dummy.class;
|
||||
}
|
||||
SpringApplication builder = builder(sourceClass);
|
||||
if (initializer!=null) {
|
||||
builder.addInitializers(initializer);
|
||||
builder.setDefaultProperties(Collections.singletonMap("spring.functional.enabled", "true"));
|
||||
}
|
||||
builder.setEnvironment(environment);
|
||||
builder.setRegisterShutdownHook(false);
|
||||
context = builder.run(args);
|
||||
@@ -131,19 +119,8 @@ public class ContextRunner {
|
||||
}
|
||||
|
||||
private static SpringApplication builder(Class<?> type) {
|
||||
if (type==Dummy.class) {
|
||||
SpringApplication application = new SpringApplication() {
|
||||
@Override
|
||||
protected void load(ApplicationContext context, Object[] sources) {
|
||||
}
|
||||
};
|
||||
// Boot doesn't allow null sources
|
||||
application.setSources(Collections.singleton(Dummy.class.getName()));
|
||||
return application;
|
||||
}
|
||||
return new SpringApplication(type);
|
||||
SpringApplication application = new FunctionalSpringApplication(type);
|
||||
return application;
|
||||
}
|
||||
|
||||
private class Dummy {}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,10 +51,12 @@ import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.ExplodedArchive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
import org.springframework.cloud.deployer.resource.support.DelegatingResourceLoader;
|
||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
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.cloud.function.core.FluxFunction;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -381,6 +383,32 @@ class FunctionCreatorConfiguration {
|
||||
Object result = null;
|
||||
if (this.runner != null) {
|
||||
result = this.runner.getBean(type);
|
||||
if (result == null) {
|
||||
if (this.runner.containsBean(FunctionCatalog.class.getName())) {
|
||||
Object catalog = this.runner
|
||||
.getBean(FunctionCatalog.class.getName());
|
||||
result = this.runner.evaluate("lookup(#function).getTarget()",
|
||||
catalog, "function", type);
|
||||
if (result != null) {
|
||||
logger.info("Located registration: " + type + " of type "
|
||||
+ result.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
logger.info("Located bean: " + type + " of type "
|
||||
+ result.getClass());
|
||||
if (result.getClass().getName()
|
||||
.equals(FunctionRegistration.class.getName())) {
|
||||
result = this.runner.evaluate("getTarget()", result);
|
||||
}
|
||||
}
|
||||
if (result != null) {
|
||||
if (result.getClass().getName()
|
||||
.equals(FluxFunction.class.getName())) {
|
||||
result = this.runner.evaluate("getTarget()", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == null) {
|
||||
logger.info("No bean found. Instantiating: " + type);
|
||||
@@ -390,7 +418,6 @@ class FunctionCreatorConfiguration {
|
||||
}
|
||||
}
|
||||
if (result != null) {
|
||||
logger.info("Located bean: " + type);
|
||||
return result;
|
||||
}
|
||||
throw new IllegalStateException("Cannot create bean for: " + type);
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.function.Supplier;
|
||||
|
||||
import org.junit.Assume;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -97,13 +96,45 @@ public abstract class FunctionCreatorConfigurationTests {
|
||||
@EnableAutoConfiguration
|
||||
@TestPropertySource(properties = {
|
||||
"function.location=app:classpath,file:target/test-classes,file:target/test-classes/app",
|
||||
"function.bean=myDoubler",
|
||||
"function.bean=doubler",
|
||||
"function.main=org.springframework.cloud.function.test.FunctionRegistrar" })
|
||||
public static class SingleFunctionWithRegistrarTests
|
||||
extends FunctionCreatorConfigurationTests {
|
||||
|
||||
@Test
|
||||
@Ignore // related to boot 2.1 no bean override change
|
||||
public void testDouble() {
|
||||
Function<Flux<Integer>, Flux<Integer>> function = catalog
|
||||
.lookup(Function.class, "function0");
|
||||
assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo(4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@TestPropertySource(properties = {
|
||||
"function.location=app:classpath,file:target/test-classes,file:target/test-classes/app",
|
||||
"function.bean=frenchizer",
|
||||
"function.main=org.springframework.cloud.function.test.FunctionRegistrar" })
|
||||
public static class SingleFunctionWithRegistrarAndRegistrationTests
|
||||
extends FunctionCreatorConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void testFrenchize() {
|
||||
Function<Flux<Integer>, Flux<String>> function = catalog
|
||||
.lookup(Function.class, "function0");
|
||||
assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo("deux");
|
||||
}
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@TestPropertySource(properties = {
|
||||
"function.location=app:classpath,file:target/test-classes,file:target/test-classes/app",
|
||||
"function.bean=myDoubler",
|
||||
"function.main=org.springframework.cloud.function.test.FunctionInitializer" })
|
||||
public static class SingleFunctionWithInitializerTests
|
||||
extends FunctionCreatorConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void testDouble() {
|
||||
Function<Flux<Integer>, Flux<Integer>> function = catalog
|
||||
.lookup(Function.class, "function0");
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright 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.test;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.cloud.function.context.FunctionalSpringApplication;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class FunctionInitializer
|
||||
implements ApplicationContextInitializer<GenericApplicationContext> {
|
||||
|
||||
@Bean
|
||||
public Doubler myDoubler() {
|
||||
return new Doubler();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Frenchizer myFrenchizer() {
|
||||
return new Frenchizer();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication application = new FunctionalSpringApplication(
|
||||
FunctionInitializer.class);
|
||||
application.run(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(GenericApplicationContext context) {
|
||||
// TODO: support for FunctionRegistration
|
||||
context.registerBean("myDoubler", Doubler.class, () -> myDoubler());
|
||||
context.registerBean("myFrenchizer", Frenchizer.class, () -> myFrenchizer());
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
package org.springframework.cloud.function.test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||
import org.springframework.cloud.function.context.FunctionType;
|
||||
import org.springframework.cloud.function.context.FunctionalSpringApplication;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
@@ -41,21 +41,21 @@ public class FunctionRegistrar
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
SpringApplication application = new SpringApplication(Object.class) {
|
||||
@Override
|
||||
protected void load(ApplicationContext context, Object[] sources) {
|
||||
}
|
||||
};
|
||||
application.addInitializers(new FunctionRegistrar());
|
||||
application.setDefaultProperties(
|
||||
Collections.singletonMap("spring.functional.enabled", "true"));
|
||||
SpringApplication application = new FunctionalSpringApplication(
|
||||
FunctionRegistrar.class);
|
||||
application.run(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(GenericApplicationContext context) {
|
||||
// TODO: support for FunctionRegistration
|
||||
context.registerBean("myDoubler", Doubler.class, () -> myDoubler());
|
||||
context.registerBean("myFrenchizer", Frenchizer.class, () -> myFrenchizer());
|
||||
context.registerBean("theDoubler", FunctionRegistration.class,
|
||||
() -> new FunctionRegistration<>(myDoubler(), "doubler")
|
||||
.type(FunctionType.of((Doubler.class))));
|
||||
context.registerBean("frenchizer", FunctionRegistration.class, () -> {
|
||||
Frenchizer function = myFrenchizer();
|
||||
function.init();
|
||||
return new FunctionRegistration<>(function, "theFrenchizer")
|
||||
.type(FunctionType.of((Frenchizer.class)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user