Skip to content

Commit 56aaea6

Browse files
committed
Make sample application work in native image with dynamic proxies
1 parent fcb447c commit 56aaea6

File tree

7 files changed

+69
-8
lines changed

7 files changed

+69
-8
lines changed
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package org.example.demo;
22

3-
import org.example.demo.service.Service;
43
import org.example.demo.service.ServiceImpl;
54
import org.springframework.context.annotation.Bean;
65
import org.springframework.context.annotation.Configuration;
76

8-
@Configuration
7+
@Configuration(proxyBeanMethods = false)
98
public class Config {
109
@Bean
11-
public Service service() {
10+
public ServiceImpl service() {
1211
return new ServiceImpl(42);
1312
}
1413
}

src/main/java/org/example/demo/Controller.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public Controller(Service service) {
1515
}
1616

1717
@GetMapping("/hello")
18-
String hello() {
19-
return "World" + service.getConstant();
18+
public String hello() {
19+
return "Hello, World " + service.getConstant();
2020
}
2121
}

src/main/java/org/example/demo/DemoApplication.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
55

6-
@SpringBootApplication
6+
@SpringBootApplication(proxyBeanMethods = false)
77
public class DemoApplication {
88

99
public static void main(String[] args) {

src/main/java/org/example/demo/aspect/LoggingAspect.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package org.example.demo.aspect;
22

33
import jakarta.validation.constraints.NotNull;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
47
import org.aspectj.lang.ProceedingJoinPoint;
58
import org.aspectj.lang.annotation.Around;
69
import org.aspectj.lang.annotation.Aspect;
@@ -10,11 +13,20 @@
1013
@Component
1114
public class LoggingAspect {
1215

16+
public final List<String> intercepted = new ArrayList<>();
17+
1318
@Around(
14-
"within(org.example.demo..*) && execution(public * *(..)) && @target(org.example.demo.aspect.AutomaticLogger)")
19+
"within(org.example.demo..*) && execution(public * *(..)) && @within(org.example.demo.aspect.AutomaticLogger)")
1520
public Object log(@NotNull ProceedingJoinPoint jp) throws Throwable {
21+
intercepted.add(jp.getSignature().getDeclaringType().getCanonicalName() + "." + jp.getSignature().getName());
22+
1623
Object result = jp.proceed(jp.getArgs());
1724

25+
if (result instanceof Integer number) {
26+
// modify the value so it can be verified in a test
27+
result = number * 2;
28+
}
29+
1830
// body removed for simplicity
1931
return result;
2032
}

src/main/java/org/example/demo/service/ServiceImpl.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.example.demo.service;
22

3+
import org.example.demo.aspect.AutomaticLogger;
34

5+
@AutomaticLogger
46
public class ServiceImpl implements Service {
57
private final Integer constant;
68

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
spring.application.name=demo
1+
spring.application.name=demo
2+
spring.aop.proxy-target-class=false
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package org.example.demo;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
5+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
6+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
7+
8+
import org.example.demo.aspect.LoggingAspect;
9+
import org.example.demo.service.Service;
10+
import org.junit.jupiter.api.Test;
11+
import org.springframework.aop.support.AopUtils;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
14+
import org.springframework.boot.test.context.SpringBootTest;
15+
import org.springframework.test.web.servlet.MockMvc;
16+
17+
@SpringBootTest
18+
@AutoConfigureMockMvc
19+
class SmokeTests {
20+
21+
@Autowired
22+
LoggingAspect loggingAspect;
23+
24+
@Autowired
25+
Controller controller;
26+
27+
@Autowired
28+
Service service;
29+
30+
@Test
31+
void accessRestEndpoint(@Autowired MockMvc mockMvc) throws Exception {
32+
mockMvc.perform(get("/hello"))
33+
.andExpect(status().isOk())
34+
.andExpect(content().string("Hello, World 84")); // 84 = 2 * 42
35+
36+
assertThat(AopUtils.isAopProxy(this.loggingAspect)).isFalse();
37+
assertThat(AopUtils.isCglibProxy(this.controller)).isTrue();
38+
assertThat(AopUtils.isJdkDynamicProxy(this.service)).isTrue();
39+
40+
assertThat(this.loggingAspect.intercepted)
41+
.containsExactly(
42+
"org.example.demo.Controller.hello",
43+
"org.example.demo.service.Service.getConstant"
44+
);
45+
}
46+
47+
}

0 commit comments

Comments
 (0)