Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

Commit fbf7771

Browse files
committed
Recognize @async and create class proxy for types
Introduce a component processor that finds @async usage and if found ensures a class proxy (AotProxy) is created at build time for use at runtime. New sample async added. Fixes #826
1 parent 816460e commit fbf7771

File tree

10 files changed

+207
-0
lines changed

10 files changed

+207
-0
lines changed

samples/async/build.sh

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#!/usr/bin/env bash
2+
3+
${PWD%/*samples/*}/scripts/compileWithMaven.sh && ${PWD%/*samples/*}/scripts/test.sh

samples/async/pom.xml

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project
3+
xmlns="http://maven.apache.org/POM/4.0.0"
4+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
6+
<modelVersion>4.0.0</modelVersion>
7+
<parent>
8+
<groupId>org.springframework.experimental</groupId>
9+
<artifactId>spring-native-sample-parent</artifactId>
10+
<version>0.10.1-SNAPSHOT</version>
11+
<relativePath>../maven-parent/pom.xml</relativePath>
12+
</parent>
13+
<groupId>com.example</groupId>
14+
<artifactId>async</artifactId>
15+
<version>0.0.1-SNAPSHOT</version>
16+
17+
<properties>
18+
<java.version>1.8</java.version>
19+
</properties>
20+
21+
<dependencies>
22+
<dependency>
23+
<groupId>org.springframework.experimental</groupId>
24+
<artifactId>spring-native</artifactId>
25+
</dependency>
26+
<dependency>
27+
<groupId>org.springframework.boot</groupId>
28+
<artifactId>spring-boot-starter</artifactId>
29+
<exclusions>
30+
<!-- On purpose exclusion to test java.util.logging -->
31+
<exclusion>
32+
<groupId>org.springframework.boot</groupId>
33+
<artifactId>spring-boot-starter-logging</artifactId>
34+
</exclusion>
35+
</exclusions>
36+
</dependency>
37+
<dependency>
38+
<groupId>org.springframework.boot</groupId>
39+
<artifactId>spring-boot-starter-test</artifactId>
40+
<scope>test</scope>
41+
</dependency>
42+
</dependencies>
43+
44+
<!-- Check out the parent POM for the plugins configuration -->
45+
<build>
46+
<plugins>
47+
<plugin>
48+
<groupId>org.springframework.experimental</groupId>
49+
<artifactId>spring-aot-maven-plugin</artifactId>
50+
<configuration>
51+
<removeYamlSupport>true</removeYamlSupport>
52+
<removeSpelSupport>true</removeSpelSupport>
53+
</configuration>
54+
</plugin>
55+
<plugin>
56+
<groupId>org.springframework.boot</groupId>
57+
<artifactId>spring-boot-maven-plugin</artifactId>
58+
</plugin>
59+
</plugins>
60+
</build>
61+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.example.async;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.scheduling.annotation.EnableAsync;
6+
7+
@SpringBootApplication
8+
@EnableAsync
9+
public class AsyncApplication {
10+
11+
public static void main(String[] args) throws InterruptedException {
12+
SpringApplication.run(AsyncApplication.class, args);
13+
Thread.currentThread().join(); // To be able to measure memory consumption
14+
}
15+
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.example.async;
2+
3+
import org.springframework.beans.factory.annotation.Autowired;
4+
import org.springframework.boot.CommandLineRunner;
5+
import org.springframework.stereotype.Component;
6+
7+
@Component
8+
public class CLR implements CommandLineRunner {
9+
10+
public static String prefix = "missing:";
11+
12+
@Autowired
13+
Runner runner;
14+
15+
@Override
16+
public void run(String... args) throws Exception {
17+
System.out.println("event application running!");
18+
runner.run();
19+
prefix = "set:";
20+
}
21+
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.example.async;
2+
3+
import org.springframework.scheduling.annotation.Async;
4+
import org.springframework.stereotype.Component;
5+
6+
@Component
7+
public class Runner {
8+
9+
@Async
10+
public void run() {
11+
try { Thread.sleep(2000); } catch (InterruptedException e) { }
12+
System.out.println(CLR.prefix+"Asynchronous action running...");
13+
}
14+
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.example.async;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import org.springframework.boot.test.context.SpringBootTest;
6+
7+
@SpringBootTest
8+
public class AsyncApplicationTests {
9+
10+
@Test
11+
public void contextLoads() {
12+
}
13+
14+
}

samples/async/verify.sh

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
if [[ `cat target/native/test-output.txt | grep "set:Asynchronous action running..."` ]]; then
3+
exit 0
4+
fi
5+
exit 1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework;
18+
19+
import java.util.Collections;
20+
import java.util.List;
21+
22+
import org.springframework.nativex.hint.ProxyBits;
23+
import org.springframework.nativex.type.ComponentProcessor;
24+
import org.springframework.nativex.type.Method;
25+
import org.springframework.nativex.type.NativeContext;
26+
import org.springframework.nativex.type.Type;
27+
import org.springframework.nativex.type.TypeSystem;
28+
29+
/**
30+
* Recognize spring.components that need an AotProxy generating in order to work. This is
31+
* a simple version that triggers proxy creation based on one of a number of annotations
32+
* appearing on a method in a component. For simple cases this might be sufficient, if
33+
* the annotations presence needs something deeper to happen, maybe it would spin off
34+
* into its own component processor.
35+
*
36+
* @author Andy Clement
37+
*/
38+
public class AotProxyComponentProcessor implements ComponentProcessor {
39+
40+
// A list of annotations that, if found on a method in a component, should trigger
41+
// creation of an AotProxy for the class
42+
public static String[] MethodLevelAnnotations = new String[]{
43+
"Lorg/springframework/scheduling/annotation/Async;"
44+
};
45+
46+
@Override
47+
public boolean handle(NativeContext imageContext, String componentType, List<String> classifiers) {
48+
TypeSystem ts = imageContext.getTypeSystem();
49+
Type component = ts.resolveDotted(componentType);
50+
for (String annotationName: MethodLevelAnnotations) {
51+
if (ts.Lresolve(annotationName,true)!=null) {
52+
List<Method> interestingMethods = component.getMethods(m -> m.hasAnnotation(annotationName,false));
53+
if (!interestingMethods.isEmpty()) {
54+
imageContext.log("AotProxyComponentProcessor: found annotation "+annotationName+" on component "+componentType+": creating class proxy");
55+
return true;
56+
}
57+
}
58+
}
59+
return false;
60+
}
61+
62+
@Override
63+
public void process(NativeContext imageContext, String componentType, List<String> classifiers) {
64+
// TODO is IS_STATIC always right here?
65+
imageContext.addAotProxy(componentType, Collections.emptyList(), ProxyBits.IS_STATIC);
66+
imageContext.log("AotProxyComponentProcessor: creating proxy for this class: "+componentType);
67+
}
68+
69+
}

spring-native-configuration/src/main/resources/META-INF/services/org.springframework.nativex.type.ComponentProcessor

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ org.springframework.SpringAtRepositoryComponentProcessor
22
org.springframework.data.SpringDataComponentProcessor
33
org.springframework.data.JpaComponentProcessor
44
org.springframework.web.WebComponentProcessor
5+
org.springframework.AotProxyComponentProcessor
56
org.springframework.SynthesizerComputationComponentProcessor
67
org.springframework.TransactionalComponentProcessor
78
org.springframework.TransactionalEventListenerComponentProcessor

0 commit comments

Comments
 (0)