Imprived class loading for new deployer
This commit is contained in:
@@ -443,9 +443,17 @@ public class BeanFactoryAwareFunctionRegistry
|
||||
for (int i = 0; i < outputCount; i++) {
|
||||
Expression parsed = new SpelExpressionParser().parseExpression("getT" + (i + 1) + "()");
|
||||
Object outputArgument = parsed.getValue(value);
|
||||
convertedInputArray[i] = outputArgument instanceof Publisher
|
||||
? this.convertOutputPublisherIfNecessary((Publisher<?>) outputArgument, acceptedOutputMimeTypes[i])
|
||||
: this.convertOutputValueIfNecessary(outputArgument, acceptedOutputMimeTypes);
|
||||
try {
|
||||
convertedInputArray[i] = outputArgument instanceof Publisher
|
||||
? this.convertOutputPublisherIfNecessary((Publisher<?>) outputArgument, acceptedOutputMimeTypes[i])
|
||||
: this.convertOutputValueIfNecessary(outputArgument, acceptedOutputMimeTypes);
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new IllegalStateException("The number of 'acceptedOutputMimeTypes' for function '" + this.functionDefinition
|
||||
+ "' is (" + acceptedOutputMimeTypes.length
|
||||
+ "), which does not match the number of actual outputs of this function which is (" + outputCount + ").", e);
|
||||
}
|
||||
|
||||
}
|
||||
convertedValue = Tuples.fromArray(convertedInputArray);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.springframework.boot.loader.jar.JarFile;
|
||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||
import org.springframework.cloud.function.context.FunctionRegistry;
|
||||
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
@@ -60,22 +59,24 @@ class ExternalFunctionJarLauncher extends JarLauncher {
|
||||
|
||||
private final Archive archive;
|
||||
|
||||
private final boolean applicationWithMain;
|
||||
|
||||
ExternalFunctionJarLauncher(Archive archive) {
|
||||
super(archive);
|
||||
this.archive = archive;
|
||||
this.applicationWithMain = this.isBootApplicationWithMain();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
protected void deploy(ApplicationContext deployerContext, String[] args) {
|
||||
protected void deploy(FunctionRegistry functionRegistry, FunctionProperties functionProperties, String[] args) {
|
||||
|
||||
ClassLoader currentLoader = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
this.launch(deployerContext, args);
|
||||
this.doLaunch(args);
|
||||
Map<String, Object> functions = this.discoverFunctions();
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Discovered functions: " + functions);
|
||||
}
|
||||
FunctionRegistry functionRegistry = deployerContext.getBean(FunctionRegistry.class);
|
||||
for (Entry<String, Object> entry : functions.entrySet()) {
|
||||
FunctionRegistration registration = new FunctionRegistration(entry.getValue(), entry.getKey());
|
||||
Type type = this.findType(entry.getKey());
|
||||
@@ -86,7 +87,7 @@ class ExternalFunctionJarLauncher extends JarLauncher {
|
||||
registration.type(type);
|
||||
functionRegistry.register(registration);
|
||||
}
|
||||
FunctionRegistration registration = this.discovereAndLoadFunctionFromClassName(deployerContext.getBean(FunctionProperties.class));
|
||||
FunctionRegistration registration = this.discovereAndLoadFunctionFromClassName(functionProperties);
|
||||
if (registration != null) {
|
||||
functionRegistry.register(registration);
|
||||
}
|
||||
@@ -109,11 +110,27 @@ class ExternalFunctionJarLauncher extends JarLauncher {
|
||||
* While LaunchedURLClassLoader is completely disconnected with the current
|
||||
* class loader, this will still allow it to see FunctionContextUtils
|
||||
*/
|
||||
return new ClassLoader(new LaunchedURLClassLoader(urls, getClass().getClassLoader().getParent())) {
|
||||
return new LaunchedURLClassLoader(urls, getClass().getClassLoader().getParent()) {
|
||||
boolean functionContextUtilsLoaded;
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||
if (!ExternalFunctionJarLauncher.this.applicationWithMain) {
|
||||
try {
|
||||
return getClass().getClassLoader().loadClass(name);
|
||||
}
|
||||
catch (Exception e) {
|
||||
//ignore and proceed with context ClassLoader
|
||||
}
|
||||
}
|
||||
return super.loadClass(name, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(final String name) throws ClassNotFoundException {
|
||||
if (name.startsWith("reactor.")) {
|
||||
System.out.println();
|
||||
}
|
||||
if (!functionContextUtilsLoaded && className.equals(name)) {
|
||||
Class<?> fcuClass = defineClass(name, fcuBytes, 0, fcuBytes.length);
|
||||
this.functionContextUtilsLoaded = true;
|
||||
@@ -128,6 +145,7 @@ class ExternalFunctionJarLauncher extends JarLauncher {
|
||||
FunctionRegistration<?> functionRegistration = null;
|
||||
AtomicReference<Type> typeRef = new AtomicReference<>();
|
||||
if (StringUtils.hasText(functionProperties.getFunctionClass())) {
|
||||
System.out.println("=====> " + Thread.currentThread().getContextClassLoader());
|
||||
Class<?> functionClass = Thread.currentThread().getContextClassLoader().loadClass(functionProperties.getFunctionClass());
|
||||
|
||||
ReflectionUtils.doWithMethods(functionClass, new MethodCallback() {
|
||||
@@ -139,7 +157,8 @@ class ExternalFunctionJarLauncher extends JarLauncher {
|
||||
@Override
|
||||
public boolean matches(Method method) {
|
||||
String name = method.getName();
|
||||
return typeRef.get() == null && ("apply".equals(name) || "accept".equals(name) || "get".equals(name));
|
||||
return typeRef.get() == null && !method.isBridge()
|
||||
&& ("apply".equals(name) || "accept".equals(name) || "get".equals(name));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -154,13 +173,20 @@ class ExternalFunctionJarLauncher extends JarLauncher {
|
||||
return functionRegistration;
|
||||
}
|
||||
|
||||
protected boolean isBootApplicationWithMain() throws Exception {
|
||||
return StringUtils.hasText(this.archive.getManifest().getMainAttributes().getValue("Start-Class"));
|
||||
protected boolean isBootApplicationWithMain() {
|
||||
try {
|
||||
return StringUtils.hasText(this.archive.getManifest().getMainAttributes().getValue("Start-Class"));
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void launch(ApplicationContext deployerContext, String[] args) throws Exception {
|
||||
private void doLaunch(String[] args) throws Exception {
|
||||
JarFile.registerUrlProtocolHandler();
|
||||
Thread.currentThread().setContextClassLoader(createClassLoader(getClassPathArchives()));
|
||||
System.out.println("=====> " + Thread.currentThread().getContextClassLoader());
|
||||
evalContext.setTypeLocator(new StandardTypeLocator(Thread.currentThread().getContextClassLoader()));
|
||||
|
||||
if (this.isBootApplicationWithMain()) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
import org.springframework.cloud.function.context.FunctionRegistry;
|
||||
import org.springframework.cloud.function.context.catalog.FunctionInspector;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -63,7 +64,7 @@ public class FunctionDeployerBootstrap implements ApplicationContextAware {
|
||||
try {
|
||||
Archive archive = new JarFileArchive(new File(functionProperties.getLocation()));
|
||||
ExternalFunctionJarLauncher launcher = new ExternalFunctionJarLauncher(archive);
|
||||
launcher.deploy(this.applicationContext, args);
|
||||
launcher.deploy(this.applicationContext.getBean(FunctionRegistry.class), this.applicationContext.getBean(FunctionProperties.class), args);
|
||||
|
||||
Constructor<? extends ApplicationContainer> applicationContainerCtr = (Constructor<? extends ApplicationContainer>) configurationClass
|
||||
.getDeclaredConstructor(FunctionCatalog.class, FunctionInspector.class, FunctionProperties.class);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2017-2019 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
|
||||
*
|
||||
* https://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.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.loader.archive.Archive;
|
||||
import org.springframework.boot.loader.archive.JarFileArchive;
|
||||
import org.springframework.cloud.function.context.FunctionRegistry;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
* @since 3.0
|
||||
*
|
||||
*/
|
||||
@EnableAutoConfiguration
|
||||
@EnableConfigurationProperties(FunctionProperties.class)
|
||||
public class FunctionDeployerConfiguration {
|
||||
|
||||
@Bean
|
||||
public SmartInitializingSingleton functionDeployer(FunctionProperties functionProperties,
|
||||
FunctionRegistry functionRegistry, ApplicationArguments arguments) {
|
||||
return new SmartInitializingSingleton() {
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
Archive archive = null;
|
||||
try {
|
||||
archive = new JarFileArchive(new File(functionProperties.getLocation()));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException("Failed to create archive: " + functionProperties.getLocation(), e);
|
||||
}
|
||||
ExternalFunctionJarLauncher launcher = new ExternalFunctionJarLauncher(archive);
|
||||
launcher.deploy(functionRegistry, functionProperties, arguments.getSourceArgs());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user