├── .devcontainer
├── Dockerfile
└── devcontainer.json
├── .gitignore
├── .gitpod.yml
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── README.adoc
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── example
│ │ ├── boot
│ │ └── BootApplication.java
│ │ ├── config
│ │ ├── ApplicationBuilder.java
│ │ ├── BeanCountingApplicationListener.java
│ │ ├── LazyInitBeanFactoryPostProcessor.java
│ │ ├── ShutdownApplicationListener.java
│ │ └── StartupApplicationListener.java
│ │ ├── demo
│ │ └── DemoApplication.java
│ │ ├── empt
│ │ └── EmptyApplication.java
│ │ ├── func
│ │ ├── BuncApplication.java
│ │ ├── CuncApplication.java
│ │ └── FuncApplication.java
│ │ ├── manual
│ │ └── ManualApplication.java
│ │ ├── micro
│ │ └── MicroApplication.java
│ │ ├── mini
│ │ └── MiniApplication.java
│ │ └── reactor
│ │ └── ReactorApplication.java
└── resources
│ ├── META-INF
│ ├── spring.factories
│ ├── thin-actj.properties
│ ├── thin-actr.properties
│ ├── thin-empt.properties
│ ├── thin-jack.properties
│ ├── thin-jdbc.properties
│ └── thin.properties
│ └── application.properties
└── test
└── java
└── com
└── example
├── bench
├── CdsBenchmark.java
├── MicroBenchmark.java
├── ProcessLauncherState.java
├── ProcessLauncherStateTests.java
├── ProfileBenchmark.java
├── VirtualMachineMetrics.java
└── VirtualMachineMetricsTests.java
├── demo
├── DemoApplicationTests.java
├── RestConfiguration.java
└── StaticApplicationTests.java
├── micro
└── MicroApplicationTests.java
└── mini
└── MiniApplicationTests.java
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.245.2/containers/java/.devcontainer/base.Dockerfile
2 |
3 | # [Choice] Java version (use -bullseye variants on local arm64/Apple Silicon): 11, 17, 11-bullseye, 17-bullseye, 11-buster, 17-buster
4 | ARG VARIANT=17-bullseye
5 | FROM mcr.microsoft.com/vscode/devcontainers/java:0-${VARIANT}
6 |
7 | ARG USER=vscode
8 |
9 | VOLUME /home/$USER/.m2
10 |
11 | RUN bash -lc '. /usr/local/sdkman/bin/sdkman-init.sh && sdk install java 19-amzn && sdk use java 19-amzn'
12 | RUN sudo mkdir /home/$USER/.m2 && sudo chown $USER:$USER /home/$USER/.m2
13 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "loom-playground",
3 | "dockerFile": "Dockerfile",
4 | "runArgs": [
5 | "--cap-add=SYS_PTRACE",
6 | "--security-opt",
7 | "seccomp=unconfined",
8 | "--mount",
9 | "type=bind,source=${env:HOME}/.m2,target=/home/vscode/.m2"
10 | ],
11 | "initializeCommand": "mkdir -p ${env:HOME}/.m2",
12 | "postCreateCommand": "sudo chown vscode:vscode /home/vscode/.m2",
13 | "remoteUser": "vscode",
14 | "features": {
15 | "docker-in-docker": "latest"
16 | },
17 | "extensions": [
18 | "vscjava.vscode-java-pack",
19 | "redhat.vscode-xml",
20 | "Pivotal.vscode-boot-dev-pack",
21 | "mhutchie.git-graph",
22 | // N.B. might need to install the pre-release version manually
23 | "redhat.java"
24 | ],
25 | "settings": {
26 | "java.server.launchMode": "Standard",
27 | "java.jdt.ls.java.home": "/usr/local/sdkman/candidates/java/current"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 |
4 | ### VSCode ###
5 | .vscode/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .attach_*
15 | .sts4-cache/
16 |
17 | ### IntelliJ IDEA ###
18 | .idea
19 | *.iws
20 | *.iml
21 | *.ipr
22 |
23 | ### NetBeans ###
24 | nbproject/private/
25 | build/
26 | nbbuild/
27 | dist/
28 | nbdist/
29 | .nb-gradle/
30 |
--------------------------------------------------------------------------------
/.gitpod.yml:
--------------------------------------------------------------------------------
1 | image: gitpod/workspace-mysql
2 | tasks:
3 | - init: ./mvnw install -DskipTests
4 | vscode:
5 | extensions:
6 | - vscjava.vscode-java-pack@0.8.1:LRImBn//d5JhH4PUEI1BaQ==
7 | - vscjava.vscode-java-debug@0.23.0:3ARqL3kPh1J1SwpVjYUjqw==
8 | - vscjava.vscode-java-test@0.22.0:BlvjRRJyZszeJzIS+xEHIA==
9 | - redhat.java@0.54.2:Q60n5quUtfd1EcwzkRq96A==
10 | - vscjava.vscode-maven@0.20.1:gdyOPlzH3PU5IkrigIg85g==
11 |
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dsyer/spring-boot-micro-apps/b7be681d44217139bbea26cc8d580c6bdbeaeb27/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
2 |
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | [.lead]
2 | This project shows how to build "micro" applications with Spring and Spring Boot - the smallest, functional units, with the fewest dependencies and fastest start times
3 |
4 | image::https://gitpod.io/button/open-in-gitpod.svg[Open in Gitpod,link="https://gitpod.io/#https://github.com/dsyer/spring-boot-micro-apps"]
5 |
6 | == Building the Apps
7 |
8 | Build the jar:
9 |
10 | ```
11 | $ ./mvnw clean install -DskipTests
12 | ```
13 |
14 | Run it
15 |
16 | ```
17 | $ java -jar target/micro-0.0.1-SNAPSHOT.jar
18 | ...
19 | 2018-05-23 10:03:41.776 [main] INFO com.example.demo.DemoApplication - Started DemoApplication in 1.885 seconds (JVM running for 3.769)
20 | ...
21 | ```
22 |
23 | The default app is relatively full-bodied - it uses Spring Boot and auto-configuration.
24 |
25 | You can run the smaller apps using command line flags:
26 |
27 | ```
28 | $ java -jar target/micro-0.0.1-SNAPSHOT.jar --thin.main=com.example.mini.MiniApplication
29 | ...
30 | May 23, 2018 10:05:41 AM reactor.util.Loggers$Slf4JLogger info
31 | INFO: Started HttpServer on /127.0.0.1:8080
32 | ```
33 |
34 | The main class could be one of
35 |
36 | |===
37 | | Main | Description |
38 | | com.example.demo.DemoApplication | (The default). Spring Boot with Webflux and full autoconfiguration |
39 | | com.example.manual.ManualApplication| Spring Boot with Webflux but manually importing autoconfiguration using `@ImportAutoConfiguration` |
40 | | com.example.boot.BootApplication | Spring Boot with Webflux and `RouterFunction` but no autoconfiguration |
41 | | com.example.func.FuncApplication | Spring (not Boot) with Webflux and `RouterFunction` using manual functional bean registration |
42 | | com.example.func.BuncApplication | Spring Boot with Webflux and `RouterFunction` using manual functional bean registration |
43 | | com.example.mini.MiniApplication | Raw Spring, no autoconfiguration, but using `@Configuration` and `RouterFunction` |
44 | | com.example.micro.MicroApplication | Raw Spring with no `@Configuration` |
45 |
46 | |===
47 |
48 | The `thin.profile` could be empty (the default) for just `spring-boot-starter-webflux` dependencies, or you can try `jack` for a more "normal" set of dependencies, e.g. with `hibernate-validator`, `jackson`, and `logback`. Other choices add more dependencies (e.g. `actr` for `spring-boot-starter-actuator`). You will need the "jack" profile to use actuators, so `--thin.profile=actr,jack`.
49 |
50 | The apps are already systematically benchmarked here with regular JVMs: https://github.com/dsyer/spring-boot-startup-bench/blob/master/flux/README.adoc. The point of this project is just to extract them out of the JMH benchmarks, and make them easily executable as standalone apps. In the benchmarks, the "jack" profile is the default, and "jlog" is the faster reduced set of dependencies.
51 |
52 | == Benchmarks
53 |
54 | Spring Boot 3.0.0-SNAPSHOT (Java 17):
55 |
56 | ```
57 | class method sample beans classes heap memory median mean range
58 | MicroBenchmark main empt 43.000 4081.000 6.982 33.689 0.568 0.593 0.046
59 | MicroBenchmark main demo 122.000 5662.000 10.669 48.869 0.849 0.901 0.085
60 | MicroBenchmark main manl 57.000 5035.000 9.142 44.431 0.633 0.665 0.031
61 | MicroBenchmark main func 44.000 3921.000 7.310 36.758 0.435 0.464 0.023
62 | CdsBenchmark main empt 43.000 4161.000 7.077 24.739 0.376 0.399 0.037
63 | CdsBenchmark main demo 121.000 6081.000 11.122 30.677 0.497 0.521 0.047
64 | CdsBenchmark main manl 57.000 5669.000 9.871 29.126 0.393 0.410 0.021
65 | ```
66 |
67 | with AOT:
68 |
69 | ```
70 | class method sample beans classes heap memory median mean range
71 | MicroBenchmark main demo 118.000 5296.000 9.448 53.407 0.785 0.814 0.026
72 | CdsBenchmark main demo 118.000 5917.000 10.576 30.216 0.418 0.440 0.032
73 | ```
74 |
75 | Java 19:
76 |
77 | ```
78 | class method sample beans classes heap memory median mean range
79 | CdsBenchmark main empt 43.000 4313.000 8.173 26.725 0.363 0.387 0.040
80 | CdsBenchmark main demo 121.000 6193.000 10.888 30.987 0.496 0.523 0.032
81 | CdsBenchmark main manl 57.000 5817.000 10.675 30.585 0.376 0.410 0.056
82 | ```
83 |
84 | Spring Boot 2.7.3 (Java 17):
85 |
86 | ```
87 | class method sample beans classes heap memory median mean range
88 | MicroBenchmark main empt 43.000 4025.000 6.862 33.436 0.562 0.586 0.030
89 | MicroBenchmark main demo 122.000 5548.000 10.442 48.377 0.848 0.902 0.056
90 | MicroBenchmark main manl 57.000 4998.000 9.005 44.235 0.634 0.659 0.024
91 | CdsBenchmark main empt 43.000 4109.000 6.917 24.652 0.365 0.391 0.033
92 | CdsBenchmark main demo 121.000 6023.000 10.882 30.494 0.492 0.514 0.020
93 | CdsBenchmark main manl 57.000 5626.000 9.683 29.026 0.382 0.402 0.021
94 | ```
95 |
96 | Spring Boot 2.5.4 (Java 17):
97 |
98 | ```
99 | class method sample beans classes heap memory median mean range
100 | MicroBenchmark main empt 43.000 4003.000 6.796 33.240 0.544 0.564 0.022
101 | MicroBenchmark main demo 117.000 5462.000 10.169 46.527 0.817 0.870 0.095
102 | MicroBenchmark main manl 58.000 4935.000 8.848 42.608 0.616 0.650 0.053
103 | CdsBenchmark main empt 43.000 4094.000 6.857 24.568 0.351 0.380 0.032
104 | CdsBenchmark main demo 116.000 5938.000 10.663 29.255 0.471 0.496 0.033
105 | CdsBenchmark main manl 58.000 5565.000 9.513 27.864 0.385 0.396 0.012
106 | ```
107 |
108 | Spring Boot 2.4.3:
109 |
110 | ```
111 | class method sample beans classes heap memory median mean range
112 | MicroBenchmark main empt 37.000 3492.000 5.047 36.515 0.528 0.543 0.012
113 | MicroBenchmark main react ≈ 0 2191.000 6.269 31.371 0.235 0.240 0.009
114 | MicroBenchmark main micro 6.000 3240.000 7.416 40.326 0.330 0.341 0.010
115 | MicroBenchmark main mini 28.000 3827.000 7.370 43.582 0.473 0.480 0.009
116 | MicroBenchmark main func 45.000 3419.000 7.707 40.650 0.466 0.481 0.017
117 | MicroBenchmark main bunc 46.000 4129.000 6.200 43.422 0.554 0.581 0.047
118 | MicroBenchmark main cunc 52.000 4320.000 6.661 44.926 0.588 0.618 0.045
119 | MicroBenchmark main boot 29.000 3435.000 6.571 41.350 0.413 0.421 0.011
120 | MicroBenchmark main manl 57.000 4478.000 6.753 45.894 0.655 0.675 0.021
121 | MicroBenchmark main demo 108.000 4891.000 8.656 50.341 0.818 0.830 0.019
122 | ProfileBenchmark main jack 106.000 5270.000 10.205 54.235 0.851 0.874 0.029
123 | ProfileBenchmark main actr 186.000 5137.000 9.889 53.202 0.928 0.965 0.049
124 | ProfileBenchmark main jdbc 143.000 5119.000 9.801 52.861 0.884 0.914 0.028
125 | ProfileBenchmark main actj 227.000 5375.000 11.170 55.669 1.003 1.023 0.022
126 | ```
127 |
128 | JDK 18 (EA):
129 |
130 | ```
131 | class method sample beans classes heap memory median mean range
132 | MicroBenchmark main empt 43.000 3991.000 6.397 32.698 0.550 0.561 0.016
133 | MicroBenchmark main demo 117.000 5451.000 9.655 45.752 0.818 0.843 0.027
134 | MicroBenchmark main manl 58.000 4925.000 9.328 42.846 0.624 0.643 0.019
135 | CdsBenchmark main empt 43.000 4084.000 6.469 24.158 0.342 0.352 0.013
136 | CdsBenchmark main demo 116.000 5932.000 10.228 28.771 0.471 0.491 0.033
137 | CdsBenchmark main manl 58.000 5556.000 9.106 27.410 0.356 0.371 0.020
138 | ```
139 |
140 | JDK 17:
141 |
142 | ```
143 | class method sample beans classes heap memory median mean range
144 | MicroBenchmark main empt 37.000 3854.000 6.133 31.948 0.490 0.511 0.020
145 | MicroBenchmark main demo 108.000 5262.000 9.216 44.461 0.751 0.772 0.029
146 | MicroBenchmark main manl 57.000 4864.000 8.269 41.515 0.625 0.656 0.037
147 | CdsBenchmark main empt 37.000 3942.000 6.184 23.773 0.302 0.325 0.017
148 | CdsBenchmark main demo 107.000 5709.000 9.715 27.987 0.434 0.444 0.016
149 | CdsBenchmark main manl 57.000 5470.000 8.897 26.995 0.346 0.365 0.021
150 | ```
151 |
152 | Spring Boot 2.3.0:
153 |
154 | ```
155 | class method sample beans classes heap memory median mean range
156 | MicroBenchmark main empt 38.000 3344.000 5.556 36.461 0.515 0.523 0.010
157 | MicroBenchmark main react ≈0 2163.000 5.995 30.828 0.223 0.228 0.007
158 | MicroBenchmark main micro 6.000 3168.000 6.750 38.088 0.311 0.317 0.009
159 | MicroBenchmark main mini 27.000 3731.000 6.625 41.262 0.450 0.455 0.008
160 | MicroBenchmark main func 44.000 3325.000 7.117 39.532 0.447 0.455 0.008
161 | MicroBenchmark main bunc 45.000 3955.000 6.859 43.211 0.505 0.521 0.023
162 | MicroBenchmark main cunc 51.000 4145.000 6.057 43.402 0.545 0.571 0.046
163 | MicroBenchmark main boot 28.000 3397.000 6.204 40.375 0.399 0.404 0.005
164 | MicroBenchmark main manl 54.000 4301.000 6.323 44.583 0.612 0.619 0.012
165 | MicroBenchmark main demo 105.000 4729.000 7.878 48.748 0.788 0.802 0.020
166 | ProfileBenchmark main jack 103.000 5095.000 9.230 52.456 0.835 0.848 0.011
167 | ProfileBenchmark main actr 190.000 5196.000 9.701 53.370 1.009 1.020 0.014
168 | ProfileBenchmark main jdbc 140.000 5135.000 9.240 52.510 0.928 0.941 0.012
169 | ProfileBenchmark main actj 230.000 5401.000 8.676 53.516 1.090 1.114 0.036
170 | ```
171 |
172 | Spring Boot 2.2.1:
173 |
174 | ```
175 | class method sample beans classes heap memory median mean range
176 | MicroBenchmark main react ≈ 0 2166.000 5.897 30.746 0.219 0.224 0.007
177 | MicroBenchmark main empt 32.000 3269.000 6.366 36.951 0.469 0.481 0.015
178 | MicroBenchmark main micro 6.000 3156.000 6.638 37.913 0.305 0.312 0.008
179 | MicroBenchmark main mini 27.000 3734.000 6.660 41.262 0.444 0.450 0.008
180 | MicroBenchmark main func 45.000 3298.000 6.870 39.068 0.435 0.444 0.012
181 | MicroBenchmark main bunc 46.000 3915.000 6.806 42.849 0.503 0.537 0.040
182 | MicroBenchmark main cunc 52.000 4101.000 5.868 42.908 0.529 0.577 0.054
183 | MicroBenchmark main boot 28.000 4043.000 6.012 42.109 0.387 0.395 0.011
184 | MicroBenchmark main manl 53.000 4231.000 6.105 43.980 0.574 0.583 0.011
185 | MicroBenchmark main demo 100.000 4671.000 7.352 47.825 0.731 0.756 0.031
186 | ProfileBenchmark main jack 98.000 5431.000 9.899 54.039 0.778 0.795 0.015
187 | ProfileBenchmark main actr 188.000 5704.000 9.418 55.329 0.945 0.957 0.014
188 | ProfileBenchmark main jdbc 138.000 5625.000 8.262 53.747 0.880 0.980 0.137
189 | ProfileBenchmark main actj 228.000 5884.000 10.758 57.704 1.030 1.142 0.116
190 | ```
191 |
192 | Snapshots after 2.2.0.M4:
193 |
194 | ```
195 | class method sample beans classes heap memory median mean range
196 | MicroBenchmark main empt 29.000 3272.000 6.388 36.948 0.461 0.491 0.051
197 | MicroBenchmark main micro 6.000 3135.000 6.554 37.536 0.296 0.301 0.007
198 | MicroBenchmark main mini 27.000 3697.000 6.546 40.860 0.426 0.438 0.011
199 | MicroBenchmark main func 45.000 3317.000 6.955 39.155 0.427 0.438 0.022
200 | MicroBenchmark main bunc 46.000 3922.000 6.745 42.758 0.471 0.482 0.011
201 | MicroBenchmark main cunc 52.000 4082.000 5.819 42.736 0.510 0.524 0.029
202 | MicroBenchmark main demo 96.000 4632.000 7.120 47.307 0.712 0.738 0.060
203 | ```
204 |
205 | Earlier results:
206 |
207 | ```
208 | class method sample beans classes heap memory median mean range
209 | MainBenchmark main empt 24.000 3230.000 5.103 38.769 0.546 0.555 0.018
210 | MainBenchmark main jlog 80.000 3598.000 6.141 43.006 0.667 0.679 0.019
211 | MainBenchmark main demo 93.000 4365.000 8.024 49.564 0.766 0.773 0.011
212 | MainBenchmark main actr 174.000 5172.000 8.538 54.216 0.902 0.911 0.020
213 | MainBenchmark main jdbc 131.000 5261.000 9.174 55.252 0.883 0.902 0.031
214 | MainBenchmark main actj 214.000 5510.000 9.007 56.571 0.995 1.021 0.065
215 | ```
216 |
217 | ```
218 | class method sample beans classes heap memory median mean range
219 | MiniBenchmark boot jlog 28.000 3336.000 7.082 41.949 0.588 0.597 0.014
220 | MiniBenchmark boot demo 28.000 4012.000 6.508 45.566 0.703 0.710 0.011
221 | MiniBenchmark first jlog 2.000 2176.000 6.556 38.574 0.416 0.418 0.004
222 | MiniBenchmark first demo 2.000 2913.000 5.647 42.091 0.515 0.523 0.008
223 | MiniBenchmark micro jlog 2.000 2176.000 4.608 32.886 0.336 0.345 0.013
224 | MiniBenchmark micro demo 2.000 2913.000 7.318 40.454 0.438 0.451 0.016
225 | MiniBenchmark mini jlog 27.000 3059.000 5.487 38.953 0.534 0.545 0.018
226 | MiniBenchmark mini demo 27.000 3732.000 5.969 43.726 0.631 0.636 0.007
227 | ```
228 |
229 | == Building a Native Image
230 |
231 | Checkout the "native" branch for details of how to build a native image using a buildpack and Spring Boot tooling. You can probably do it by hand with GraalVM as well if you need to, and use the thin jar to calculate its classpath for the build.
232 |
--------------------------------------------------------------------------------
/mvnw:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # ----------------------------------------------------------------------------
3 | # Licensed to the Apache Software Foundation (ASF) under one
4 | # or more contributor license agreements. See the NOTICE file
5 | # distributed with this work for additional information
6 | # regarding copyright ownership. The ASF licenses this file
7 | # to you under the Apache License, Version 2.0 (the
8 | # "License"); you may not use this file except in compliance
9 | # with the License. You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing,
14 | # software distributed under the License is distributed on an
15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 | # KIND, either express or implied. See the License for the
17 | # specific language governing permissions and limitations
18 | # under the License.
19 | # ----------------------------------------------------------------------------
20 |
21 | # ----------------------------------------------------------------------------
22 | # Maven2 Start Up Batch script
23 | #
24 | # Required ENV vars:
25 | # ------------------
26 | # JAVA_HOME - location of a JDK home dir
27 | #
28 | # Optional ENV vars
29 | # -----------------
30 | # M2_HOME - location of maven2's installed home dir
31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven
32 | # e.g. to debug Maven itself, use
33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files
35 | # ----------------------------------------------------------------------------
36 |
37 | if [ -z "$MAVEN_SKIP_RC" ] ; then
38 |
39 | if [ -f /etc/mavenrc ] ; then
40 | . /etc/mavenrc
41 | fi
42 |
43 | if [ -f "$HOME/.mavenrc" ] ; then
44 | . "$HOME/.mavenrc"
45 | fi
46 |
47 | fi
48 |
49 | # OS specific support. $var _must_ be set to either true or false.
50 | cygwin=false;
51 | darwin=false;
52 | mingw=false
53 | case "`uname`" in
54 | CYGWIN*) cygwin=true ;;
55 | MINGW*) mingw=true;;
56 | Darwin*) darwin=true
57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html
59 | if [ -z "$JAVA_HOME" ]; then
60 | if [ -x "/usr/libexec/java_home" ]; then
61 | export JAVA_HOME="`/usr/libexec/java_home`"
62 | else
63 | export JAVA_HOME="/Library/Java/Home"
64 | fi
65 | fi
66 | ;;
67 | esac
68 |
69 | if [ -z "$JAVA_HOME" ] ; then
70 | if [ -r /etc/gentoo-release ] ; then
71 | JAVA_HOME=`java-config --jre-home`
72 | fi
73 | fi
74 |
75 | if [ -z "$M2_HOME" ] ; then
76 | ## resolve links - $0 may be a link to maven's home
77 | PRG="$0"
78 |
79 | # need this for relative symlinks
80 | while [ -h "$PRG" ] ; do
81 | ls=`ls -ld "$PRG"`
82 | link=`expr "$ls" : '.*-> \(.*\)$'`
83 | if expr "$link" : '/.*' > /dev/null; then
84 | PRG="$link"
85 | else
86 | PRG="`dirname "$PRG"`/$link"
87 | fi
88 | done
89 |
90 | saveddir=`pwd`
91 |
92 | M2_HOME=`dirname "$PRG"`/..
93 |
94 | # make it fully qualified
95 | M2_HOME=`cd "$M2_HOME" && pwd`
96 |
97 | cd "$saveddir"
98 | # echo Using m2 at $M2_HOME
99 | fi
100 |
101 | # For Cygwin, ensure paths are in UNIX format before anything is touched
102 | if $cygwin ; then
103 | [ -n "$M2_HOME" ] &&
104 | M2_HOME=`cygpath --unix "$M2_HOME"`
105 | [ -n "$JAVA_HOME" ] &&
106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
107 | [ -n "$CLASSPATH" ] &&
108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
109 | fi
110 |
111 | # For Migwn, ensure paths are in UNIX format before anything is touched
112 | if $mingw ; then
113 | [ -n "$M2_HOME" ] &&
114 | M2_HOME="`(cd "$M2_HOME"; pwd)`"
115 | [ -n "$JAVA_HOME" ] &&
116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
117 | # TODO classpath?
118 | fi
119 |
120 | if [ -z "$JAVA_HOME" ]; then
121 | javaExecutable="`which javac`"
122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
123 | # readlink(1) is not available as standard on Solaris 10.
124 | readLink=`which readlink`
125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
126 | if $darwin ; then
127 | javaHome="`dirname \"$javaExecutable\"`"
128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
129 | else
130 | javaExecutable="`readlink -f \"$javaExecutable\"`"
131 | fi
132 | javaHome="`dirname \"$javaExecutable\"`"
133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'`
134 | JAVA_HOME="$javaHome"
135 | export JAVA_HOME
136 | fi
137 | fi
138 | fi
139 |
140 | if [ -z "$JAVACMD" ] ; then
141 | if [ -n "$JAVA_HOME" ] ; then
142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
143 | # IBM's JDK on AIX uses strange locations for the executables
144 | JAVACMD="$JAVA_HOME/jre/sh/java"
145 | else
146 | JAVACMD="$JAVA_HOME/bin/java"
147 | fi
148 | else
149 | JAVACMD="`which java`"
150 | fi
151 | fi
152 |
153 | if [ ! -x "$JAVACMD" ] ; then
154 | echo "Error: JAVA_HOME is not defined correctly." >&2
155 | echo " We cannot execute $JAVACMD" >&2
156 | exit 1
157 | fi
158 |
159 | if [ -z "$JAVA_HOME" ] ; then
160 | echo "Warning: JAVA_HOME environment variable is not set."
161 | fi
162 |
163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
164 |
165 | # traverses directory structure from process work directory to filesystem root
166 | # first directory with .mvn subdirectory is considered project base directory
167 | find_maven_basedir() {
168 |
169 | if [ -z "$1" ]
170 | then
171 | echo "Path not specified to find_maven_basedir"
172 | return 1
173 | fi
174 |
175 | basedir="$1"
176 | wdir="$1"
177 | while [ "$wdir" != '/' ] ; do
178 | if [ -d "$wdir"/.mvn ] ; then
179 | basedir=$wdir
180 | break
181 | fi
182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc)
183 | if [ -d "${wdir}" ]; then
184 | wdir=`cd "$wdir/.."; pwd`
185 | fi
186 | # end of workaround
187 | done
188 | echo "${basedir}"
189 | }
190 |
191 | # concatenates all lines of a file
192 | concat_lines() {
193 | if [ -f "$1" ]; then
194 | echo "$(tr -s '\n' ' ' < "$1")"
195 | fi
196 | }
197 |
198 | BASE_DIR=`find_maven_basedir "$(pwd)"`
199 | if [ -z "$BASE_DIR" ]; then
200 | exit 1;
201 | fi
202 |
203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
204 | echo $MAVEN_PROJECTBASEDIR
205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
206 |
207 | # For Cygwin, switch paths to Windows format before running java
208 | if $cygwin; then
209 | [ -n "$M2_HOME" ] &&
210 | M2_HOME=`cygpath --path --windows "$M2_HOME"`
211 | [ -n "$JAVA_HOME" ] &&
212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
213 | [ -n "$CLASSPATH" ] &&
214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
215 | [ -n "$MAVEN_PROJECTBASEDIR" ] &&
216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
217 | fi
218 |
219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
220 |
221 | exec "$JAVACMD" \
222 | $MAVEN_OPTS \
223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
226 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM http://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
84 | @REM Fallback to current working directory if not found.
85 |
86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
88 |
89 | set EXEC_DIR=%CD%
90 | set WDIR=%EXEC_DIR%
91 | :findBaseDir
92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
93 | cd ..
94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
95 | set WDIR=%CD%
96 | goto findBaseDir
97 |
98 | :baseDirFound
99 | set MAVEN_PROJECTBASEDIR=%WDIR%
100 | cd "%EXEC_DIR%"
101 | goto endDetectBaseDir
102 |
103 | :baseDirNotFound
104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
105 | cd "%EXEC_DIR%"
106 |
107 | :endDetectBaseDir
108 |
109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
110 |
111 | @setlocal EnableExtensions EnableDelayedExpansion
112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
114 |
115 | :endReadAdditionalConfig
116 |
117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
118 |
119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
121 |
122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
123 | if ERRORLEVEL 1 goto error
124 | goto end
125 |
126 | :error
127 | set ERROR_CODE=1
128 |
129 | :end
130 | @endlocal & set ERROR_CODE=%ERROR_CODE%
131 |
132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
136 | :skipRcPost
137 |
138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
140 |
141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
142 |
143 | exit /B %ERROR_CODE%
144 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.example
8 | micro
9 | 0.0.1-SNAPSHOT
10 | jar
11 |
12 | micro
13 | Demo project for Spring Boot
14 |
15 |
16 | org.springframework.boot
17 | spring-boot-starter-parent
18 | 3.1.3
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 17
25 | 1.0.27.RELEASE
26 | 1.33
27 | com.example.demo.DemoApplication
28 |
29 |
30 |
31 |
32 | org.springframework
33 | spring-context-indexer
34 | true
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-webflux
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-logging
43 |
44 |
45 | org.hibernate.validator
46 | hibernate-validator
47 |
48 |
49 | io.netty
50 | netty-transport-native-epoll
51 |
52 |
53 | jakarta.validation
54 | jakarta.validation-api
55 |
56 |
57 |
58 |
59 | org.slf4j
60 | slf4j-jdk14
61 |
62 |
63 | com.google.code.gson
64 | gson
65 |
66 |
67 | com.github.mp911de.microbenchmark-runner
68 | microbenchmark-runner-junit5
69 | 0.3.0.RELEASE
70 | test
71 |
72 |
73 | com.github.mp911de.microbenchmark-runner
74 | microbenchmark-runner-extras
75 | 0.3.0.RELEASE
76 | test
77 |
78 |
79 | org.springframework.boot.experimental
80 | spring-boot-thin-launcher
81 | ${thin.version}
82 | test
83 |
84 |
85 | org.springframework.boot
86 | spring-boot-starter-test
87 | test
88 |
89 |
90 |
91 |
92 |
93 | tools.jar
94 |
95 | [1.8,1.9)
96 |
97 |
98 |
99 | com.sun
100 | tools
101 | 1.8
102 | system
103 | ${java.home}/../lib/tools.jar
104 |
105 |
106 |
107 |
108 | java11
109 |
110 | [11,23)
111 |
112 |
113 |
114 |
115 | maven-surefire-plugin
116 |
117 | -Djdk.attach.allowAttachSelf=true --add-opens java.base/java.lang=ALL-UNNAMED
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | org.apache.maven.plugins
129 | maven-compiler-plugin
130 |
131 |
132 |
133 | org.openjdk.jmh
134 | jmh-generator-annprocess
135 | ${jmh.version}
136 |
137 |
138 | ${java.version}
139 | ${java.version}
140 |
141 |
142 |
143 | org.springframework.boot
144 | spring-boot-maven-plugin
145 |
146 |
147 | org.springframework.boot.experimental
148 | spring-boot-thin-layout
149 | ${thin.version}
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 | jitpack.io
159 | https://jitpack.io
160 |
161 |
162 | spring-snapshots
163 | Spring Snapshots
164 | https://repo.spring.io/snapshot
165 |
166 | true
167 |
168 |
169 |
170 | spring-milestones
171 | Spring Milestones
172 | https://repo.spring.io/milestone
173 |
174 | false
175 |
176 |
177 |
178 | sonatype-snapshots
179 | https://oss.sonatype.org/content/repositories/snapshots/
180 |
181 | true
182 |
183 |
184 |
185 |
186 |
187 | spring-snapshots
188 | Spring Snapshots
189 | https://repo.spring.io/snapshot
190 |
191 | true
192 |
193 |
194 |
195 | spring-milestones
196 | Spring Milestones
197 | https://repo.spring.io/milestone
198 |
199 | false
200 |
201 |
202 |
203 |
204 |
--------------------------------------------------------------------------------
/src/main/java/com/example/boot/BootApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016-2017 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 | * http://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 | package com.example.boot;
17 |
18 | import java.util.Collections;
19 |
20 | import com.example.config.ApplicationBuilder;
21 | import reactor.core.publisher.Mono;
22 |
23 | import org.springframework.boot.SpringBootConfiguration;
24 | import org.springframework.boot.WebApplicationType;
25 | import org.springframework.boot.builder.SpringApplicationBuilder;
26 | import org.springframework.context.ConfigurableApplicationContext;
27 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
28 | import org.springframework.context.annotation.Bean;
29 | import org.springframework.web.reactive.config.EnableWebFlux;
30 | import org.springframework.web.reactive.function.server.RouterFunction;
31 |
32 | import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
33 | import static org.springframework.web.reactive.function.server.RouterFunctions.route;
34 | import static org.springframework.web.reactive.function.server.ServerResponse.ok;
35 |
36 | /**
37 | * @author Dave Syer
38 | *
39 | */
40 | @SpringBootConfiguration(proxyBeanMethods = false)
41 | @EnableWebFlux
42 | // @Import(LazyInitBeanFactoryPostProcessor.class)
43 | public class BootApplication {
44 |
45 | public static void main(String[] args) throws Exception {
46 | long t0 = System.currentTimeMillis();
47 | SpringApplicationBuilder builder = new SpringApplicationBuilder(
48 | BootApplication.class).web(WebApplicationType.NONE)
49 | .contextFactory(type -> new AnnotationConfigApplicationContext())
50 | .registerShutdownHook(false);
51 | builder.application().setListeners(Collections.emptyList());
52 | try (ConfigurableApplicationContext context = builder.run(args)) {
53 | ApplicationBuilder.start(context, b -> {
54 | System.err.println("Started HttpServer: "
55 | + (System.currentTimeMillis() - t0) + "ms");
56 | });
57 | }
58 | }
59 |
60 | @Bean
61 | public RouterFunction> userEndpoints() {
62 | return route(GET("/"), request -> ok().body(Mono.just("Hello"), String.class));
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/example/config/ApplicationBuilder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016-2017 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 | * http://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 | package com.example.config;
17 |
18 | import java.lang.management.ManagementFactory;
19 | import java.time.Duration;
20 | import java.util.function.Consumer;
21 |
22 | import org.apache.commons.logging.Log;
23 | import org.apache.commons.logging.LogFactory;
24 |
25 | import org.springframework.beans.factory.support.DefaultListableBeanFactory;
26 | import org.springframework.context.ConfigurableApplicationContext;
27 | import org.springframework.context.support.AbstractApplicationContext;
28 | import org.springframework.http.server.reactive.HttpHandler;
29 | import org.springframework.http.server.reactive.ReactorHttpHandlerAdapter;
30 | import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
31 |
32 | import reactor.netty.DisposableServer;
33 | import reactor.netty.http.server.HttpServer;
34 |
35 | /**
36 | * @author Dave Syer
37 | *
38 | */
39 | public class ApplicationBuilder {
40 |
41 | private static final String SHUTDOWN_LISTENER = "SHUTDOWN_LISTENER";
42 | public static final String STARTUP = "Benchmark app started";
43 | private static Log logger = LogFactory.getLog(StartupApplicationListener.class);
44 |
45 | public static void start(ConfigurableApplicationContext context) {
46 | start(context, null);
47 | }
48 |
49 | public static void start(ConfigurableApplicationContext context,
50 | Consumer callback) {
51 | if (!hasListeners(context)) {
52 | ((DefaultListableBeanFactory) context.getBeanFactory())
53 | .registerDisposableBean(SHUTDOWN_LISTENER,
54 | new ShutdownApplicationListener());
55 | new BeanCountingApplicationListener().log(context);
56 | logger.info(STARTUP);
57 | }
58 |
59 | HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context).build();
60 | ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
61 | HttpServer httpServer = HttpServer.create().host("localhost").port(
62 | context.getEnvironment().getProperty("server.port", Integer.class, 8080))
63 | .handle(adapter);
64 | httpServer.bindUntilJavaShutdown(Duration.ofSeconds(60), callback(callback));
65 | }
66 |
67 | private static Consumer callback(
68 | Consumer callback) {
69 | return context -> {
70 | try {
71 | double uptime = ManagementFactory.getRuntimeMXBean().getUptime();
72 | System.err.println("JVM running for " + uptime + "ms");
73 | }
74 | catch (Throwable e) {
75 | }
76 | if (callback != null) {
77 | callback.accept(context);
78 | }
79 | };
80 | }
81 |
82 | private static boolean hasListeners(ConfigurableApplicationContext context) {
83 | if (context.getBeanNamesForType(ShutdownApplicationListener.class).length != 0) {
84 | return true;
85 | }
86 | if (context instanceof AbstractApplicationContext) {
87 | if (((AbstractApplicationContext) context).getApplicationListeners().stream()
88 | .anyMatch(l -> l instanceof ShutdownApplicationListener)) {
89 | return true;
90 | }
91 | }
92 | if ((DefaultListableBeanFactory) context.getBeanFactory()
93 | .getSingleton(SHUTDOWN_LISTENER) != null) {
94 | return true;
95 | }
96 | return false;
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/com/example/config/BeanCountingApplicationListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016-2017 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 | * http://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 | package com.example.config;
17 |
18 | import java.lang.management.ManagementFactory;
19 | import java.util.ArrayList;
20 | import java.util.Arrays;
21 | import java.util.List;
22 |
23 | import org.apache.commons.logging.Log;
24 | import org.apache.commons.logging.LogFactory;
25 |
26 | import org.springframework.beans.BeansException;
27 | import org.springframework.boot.context.event.ApplicationReadyEvent;
28 | import org.springframework.context.ApplicationContext;
29 | import org.springframework.context.ApplicationContextAware;
30 | import org.springframework.context.ApplicationListener;
31 | import org.springframework.context.ConfigurableApplicationContext;
32 |
33 | /**
34 | * @author Dave Syer
35 | *
36 | */
37 | public class BeanCountingApplicationListener
38 | implements ApplicationListener, ApplicationContextAware {
39 |
40 | private static Log logger = LogFactory.getLog(BeanCountingApplicationListener.class);
41 | private ApplicationContext context;
42 |
43 | @Override
44 | public void setApplicationContext(ApplicationContext context) throws BeansException {
45 | this.context = context;
46 | }
47 |
48 | @Override
49 | public void onApplicationEvent(ApplicationReadyEvent event) {
50 | if (!event.getApplicationContext().equals(this.context)) {
51 | return;
52 | }
53 | ConfigurableApplicationContext context = event.getApplicationContext();
54 | log(context);
55 | }
56 |
57 | public void log(ConfigurableApplicationContext context) {
58 | int count = 0;
59 | String id = context.getId();
60 | List names = new ArrayList<>();
61 | while (context != null) {
62 | count += context.getBeanDefinitionCount();
63 | names.addAll(Arrays.asList(context.getBeanDefinitionNames()));
64 | context = (ConfigurableApplicationContext) context.getParent();
65 | }
66 | logger.info("Bean count: " + id + "=" + count);
67 | logger.debug("Bean names: " + id + "=" + names);
68 | try {
69 | logger.info("Class count: " + id + "=" + ManagementFactory
70 | .getClassLoadingMXBean().getTotalLoadedClassCount());
71 | }
72 | catch (Throwable e) {
73 | }
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/com/example/config/LazyInitBeanFactoryPostProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016-2017 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 | * http://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 | package com.example.config;
17 |
18 | import org.springframework.beans.BeansException;
19 | import org.springframework.beans.factory.config.BeanDefinition;
20 | import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
21 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
22 | import org.springframework.stereotype.Component;
23 |
24 | @Component
25 | public class LazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
26 |
27 | private Class>[] exclusionList;
28 |
29 | public LazyInitBeanFactoryPostProcessor() {
30 | }
31 |
32 | public LazyInitBeanFactoryPostProcessor(Class>[] exclusionList) {
33 | this.exclusionList = exclusionList;
34 | }
35 |
36 | @Override
37 | public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
38 | throws BeansException {
39 |
40 | // Iterate over all bean, mark them as lazy if they are not in the exclusion list.
41 | for (String beanName : beanFactory.getBeanDefinitionNames()) {
42 | if (isLazy(beanName, beanFactory)) {
43 | BeanDefinition definition = beanFactory.getBeanDefinition(beanName);
44 | definition.setLazyInit(true);
45 | }
46 | }
47 | }
48 |
49 | private boolean isLazy(String beanName, ConfigurableListableBeanFactory beanFactory) {
50 | if (exclusionList == null || exclusionList.length == 0) {
51 | return true;
52 | }
53 | for (Class> clazz : exclusionList) {
54 | if (beanFactory.isTypeMatch(beanName, clazz)) {
55 | return false;
56 | }
57 | }
58 | return true;
59 | }
60 | }
--------------------------------------------------------------------------------
/src/main/java/com/example/config/ShutdownApplicationListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016-2017 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 | * http://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 | package com.example.config;
17 |
18 | import java.util.LinkedHashSet;
19 | import java.util.Set;
20 |
21 | import org.springframework.beans.BeansException;
22 | import org.springframework.beans.factory.DisposableBean;
23 | import org.springframework.beans.factory.support.DefaultListableBeanFactory;
24 | import org.springframework.boot.SpringBootConfiguration;
25 | import org.springframework.boot.context.event.ApplicationReadyEvent;
26 | import org.springframework.context.ApplicationContext;
27 | import org.springframework.context.ApplicationContextAware;
28 | import org.springframework.context.ApplicationListener;
29 | import org.springframework.core.Ordered;
30 | import org.springframework.core.annotation.AnnotatedElementUtils;
31 | import org.springframework.core.annotation.Order;
32 | import org.springframework.util.ClassUtils;
33 |
34 | /**
35 | * @author Dave Syer
36 | *
37 | */
38 | @Order(Ordered.HIGHEST_PRECEDENCE)
39 | public class ShutdownApplicationListener
40 | implements ApplicationListener, DisposableBean,
41 | ApplicationContextAware {
42 |
43 | private static final String SHUTDOWN_LISTENER = "SHUTDOWN_LISTENER";
44 |
45 | public static final String MARKER = "Benchmark app stopped";
46 |
47 | private ApplicationContext context;
48 |
49 | @Override
50 | public void setApplicationContext(ApplicationContext context) throws BeansException {
51 | this.context = context;
52 | }
53 |
54 | @Override
55 | public void onApplicationEvent(ApplicationReadyEvent event) {
56 | if (!event.getApplicationContext().equals(this.context)) {
57 | return;
58 | }
59 | if (isSpringBootApplication(sources(event))) {
60 | ((DefaultListableBeanFactory) event.getApplicationContext().getBeanFactory())
61 | .registerDisposableBean(SHUTDOWN_LISTENER, this);
62 | }
63 | }
64 |
65 | @Override
66 | public void destroy() throws Exception {
67 | try {
68 | System.out.println(MARKER);
69 | }
70 | catch (Exception e) {
71 | }
72 | }
73 |
74 | private boolean isSpringBootApplication(Set> sources) {
75 | for (Class> source : sources) {
76 | if (AnnotatedElementUtils.hasAnnotation(source,
77 | SpringBootConfiguration.class)) {
78 | return true;
79 | }
80 | }
81 | return false;
82 | }
83 |
84 | private Set> sources(ApplicationReadyEvent event) {
85 | Set