7
7
import java .util .*;
8
8
import java .util .concurrent .ConcurrentHashMap ;
9
9
import java .util .concurrent .atomic .AtomicBoolean ;
10
+ import java .util .logging .Level ;
10
11
11
12
import com .microsoft .azure .functions .internal .spi .middleware .Middleware ;
12
13
import com .microsoft .azure .functions .rpc .messages .*;
14
+ import com .microsoft .azure .functions .spi .inject .FunctionInstanceInjector ;
13
15
import com .microsoft .azure .functions .worker .Constants ;
14
16
import com .microsoft .azure .functions .worker .WorkerLogManager ;
15
17
import com .microsoft .azure .functions .worker .binding .BindingDataStore ;
@@ -33,8 +35,19 @@ public class JavaFunctionBroker {
33
35
private final Map <String , ImmutablePair <String , FunctionDefinition >> methods ;
34
36
private final ClassLoaderProvider classLoaderProvider ;
35
37
private String workerDirectory ;
36
- private final AtomicBoolean invocationChainFactoryInitialized = new AtomicBoolean (false );
38
+ private final AtomicBoolean oneTimeLogicInitialized = new AtomicBoolean (false );
37
39
private volatile InvocationChainFactory invocationChainFactory ;
40
+ private volatile FunctionInstanceInjector functionInstanceInjector ;
41
+
42
+ private FunctionInstanceInjector newInstanceInjector () {
43
+ return new FunctionInstanceInjector () {
44
+ @ Override
45
+ public <T > T getInstance (Class <T > functionClass ) throws Exception {
46
+ return functionClass .newInstance ();
47
+ }
48
+ };
49
+ }
50
+
38
51
public JavaFunctionBroker (ClassLoaderProvider classLoaderProvider ) {
39
52
this .methods = new ConcurrentHashMap <>();
40
53
this .classLoaderProvider = classLoaderProvider ;
@@ -44,26 +57,54 @@ public void loadMethod(FunctionMethodDescriptor descriptor, Map<String, BindingI
44
57
throws ClassNotFoundException , NoSuchMethodException , IOException {
45
58
descriptor .validate ();
46
59
addSearchPathsToClassLoader (descriptor );
47
- initializeInvocationChainFactory ();
60
+ initializeOneTimeLogics ();
48
61
FunctionDefinition functionDefinition = new FunctionDefinition (descriptor , bindings , classLoaderProvider );
49
62
this .methods .put (descriptor .getId (), new ImmutablePair <>(descriptor .getName (), functionDefinition ));
50
63
}
51
64
65
+ private void initializeOneTimeLogics () {
66
+ if (!oneTimeLogicInitialized .getAndSet (true )) {
67
+ initializeInvocationChainFactory ();
68
+ initializeFunctionInstanceInjector ();
69
+ }
70
+ }
71
+
52
72
private void initializeInvocationChainFactory () {
53
- if (!invocationChainFactoryInitialized .getAndSet (true )) {
54
- ArrayList <Middleware > middlewares = new ArrayList <>();
55
- try {
56
- //ServiceLoader will use thread context classloader to verify loaded class
57
- Thread .currentThread ().setContextClassLoader (classLoaderProvider .createClassLoader ());
58
- for (Middleware middleware : ServiceLoader .load (Middleware .class )) {
59
- middlewares .add (middleware );
60
- WorkerLogManager .getSystemLogger ().info ("Load middleware " + middleware .getClass ().getSimpleName ());
73
+ ArrayList <Middleware > middlewares = new ArrayList <>();
74
+ ClassLoader prevContextClassLoader = Thread .currentThread ().getContextClassLoader ();
75
+ try {
76
+ //ServiceLoader will use thread context classloader to verify loaded class
77
+ Thread .currentThread ().setContextClassLoader (classLoaderProvider .createClassLoader ());
78
+ for (Middleware middleware : ServiceLoader .load (Middleware .class )) {
79
+ middlewares .add (middleware );
80
+ WorkerLogManager .getSystemLogger ().info ("Load middleware " + middleware .getClass ().getSimpleName ());
81
+ }
82
+ } finally {
83
+ Thread .currentThread ().setContextClassLoader (prevContextClassLoader );
84
+ }
85
+ middlewares .add (getFunctionExecutionMiddleWare ());
86
+ this .invocationChainFactory = new InvocationChainFactory (middlewares );
87
+ }
88
+
89
+ private void initializeFunctionInstanceInjector () {
90
+ ClassLoader prevContextClassLoader = Thread .currentThread ().getContextClassLoader ();
91
+ try {
92
+ //ServiceLoader will use thread context classloader to verify loaded class
93
+ Thread .currentThread ().setContextClassLoader (classLoaderProvider .createClassLoader ());
94
+ Iterator <FunctionInstanceInjector > iterator = ServiceLoader .load (FunctionInstanceInjector .class ).iterator ();
95
+ if (iterator .hasNext ()) {
96
+ this .functionInstanceInjector = iterator .next ();
97
+ WorkerLogManager .getSystemLogger ().info ("Load function instance injector: " + this .functionInstanceInjector .getClass ().getName ());
98
+ if (iterator .hasNext ()){
99
+ WorkerLogManager .getSystemLogger ().warning ("Customer function app has multiple FunctionInstanceInjector implementations." );
100
+ throw new RuntimeException ("Customer function app has multiple FunctionInstanceInjector implementations" );
61
101
}
62
- } finally {
63
- Thread .currentThread ().setContextClassLoader (ClassLoader .getSystemClassLoader ());
102
+ }else {
103
+ this .functionInstanceInjector = newInstanceInjector ();
104
+ WorkerLogManager .getSystemLogger ().info ("Didn't find any function instance injector, creating function class instance every invocation." );
64
105
}
65
- middlewares . add ( getFunctionExecutionMiddleWare ());
66
- this . invocationChainFactory = new InvocationChainFactory ( middlewares );
106
+ } finally {
107
+ Thread . currentThread (). setContextClassLoader ( prevContextClassLoader );
67
108
}
68
109
}
69
110
@@ -99,7 +140,7 @@ private ExecutionContextDataSource buildExecutionContext(String id, InvocationR
99
140
request .getRetryContext ().getMaxRetryCount (), request .getRetryContext ().getException ());
100
141
ExecutionContextDataSource executionContextDataSource = new ExecutionContextDataSource (request .getInvocationId (),
101
142
traceContext , retryContext , methodEntry .left , dataStore , functionDefinition .getCandidate (),
102
- functionDefinition .getContainingClass (), request .getInputDataList ());
143
+ functionDefinition .getContainingClass (), request .getInputDataList (), this . functionInstanceInjector );
103
144
dataStore .addExecutionContextSource (executionContextDataSource );
104
145
return executionContextDataSource ;
105
146
}
0 commit comments