Overview
Explanation
SpringBootアプリケーション起動直後に、Tomcatのスレッドを初期化する方法について記載します。
処理フローは概要の「スレッド初期化のシーケンス図」の通りです。
以下、実際のプログラムを載せておきます。
1. ThreadInitializer
main thread
で実行されるプログラムは、onApplicationEvent
メソッド。
child pool thread
で実行されるプログラムは、callThreadInit
メソッド。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
@Component
@Slf4j
public class ThreadInitializer implements ApplicationListener<ContextRefreshedEvent> {
@Value("${server.tomcat.max-threads}")
private Integer threadNum;
@Autowired
private RestTemplate restTemplate;
@Override
public void onApplicationEvent(ContextRefreshedEvent arg0) {
ExecutorService executor = Executors.newFixedThreadPool(threadNum);
IntStream.range(0, threadNum).forEach(i -> {
executor.submit(() -> {
callThreadInit();
});
});
executor.shutdown();
}
private void callThreadInit() {
try {
Thread.sleep(10000); // サーバーが立ち上がるまで10秒待機する。
restTemplate.getForEntity("http://localhost:8080/threadInit", String.class);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
|
2. Access point for thread initialization
tomcat thread
で実行されるプログラムは、threadInit
メソッド。
1
2
3
4
5
6
7
8
9
10
11
|
@RestController
@Slf4j
public class RestController {
@RequestMapping("/threadInit")
public void threadInit() throws InterruptedException {
log.info("do something for thread init.");
Thread.sleep(10000); // 10秒ほどかかる処理とする。
}
}
|
3. Execution result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
18:36:04: Executing task 'ThreadInitOnDeploymentApplication.main()'...
> Task :compileJava
> Task :processResources UP-TO-DATE
> Task :classes
> Task :ThreadInitOnDeploymentApplication.main()
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.6.RELEASE)
2020-04-25 18:36:08.943 INFO 95474 --- [ main] c.e.t.ThreadInitOnDeploymentApplication : Starting ThreadInitOnDeploymentApplication on MacBook-Air.local with PID 95474 (/Users/takuto-n/Documents/Basic_study/private_repo/ctrl-key-6bit-mask/java/thread-init-on-deployment/build/classes/java/main started by takuto-n in /Users/takuto-n/Documents/Basic_study/private_repo/ctrl-key-6bit-mask/java/thread-init-on-deployment)
2020-04-25 18:36:08.949 INFO 95474 --- [ main] c.e.t.ThreadInitOnDeploymentApplication : No active profile set, falling back to default profiles: default
2020-04-25 18:36:10.715 INFO 95474 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-04-25 18:36:10.755 INFO 95474 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-04-25 18:36:10.756 INFO 95474 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.33]
2020-04-25 18:36:10.896 INFO 95474 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-04-25 18:36:10.897 INFO 95474 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1842 ms
2020-04-25 18:36:11.243 INFO 95474 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-25 18:36:11.514 INFO 95474 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-04-25 18:36:11.527 INFO 95474 --- [ main] c.e.t.ThreadInitOnDeploymentApplication : Started ThreadInitOnDeploymentApplication in 3.404 seconds (JVM running for 4.105)
2020-04-25 18:36:21.721 INFO 95474 --- [nio-8080-exec-7] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-04-25 18:36:21.721 INFO 95474 --- [nio-8080-exec-7] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-04-25 18:36:21.733 INFO 95474 --- [nio-8080-exec-7] o.s.web.servlet.DispatcherServlet : Completed initialization in 12 ms
2020-04-25 18:36:21.780 INFO 95474 --- [nio-8080-exec-4] c.e.t.RestController : do something for thread init.
2020-04-25 18:36:21.780 INFO 95474 --- [nio-8080-exec-5] c.e.t.RestController : do something for thread init.
2020-04-25 18:36:21.780 INFO 95474 --- [nio-8080-exec-1] c.e.t.RestController : do something for thread init.
2020-04-25 18:36:21.781 INFO 95474 --- [nio-8080-exec-8] c.e.t.RestController : do something for thread init.
2020-04-25 18:36:21.781 INFO 95474 --- [nio-8080-exec-6] c.e.t.RestController : do something for thread init.
2020-04-25 18:36:21.781 INFO 95474 --- [nio-8080-exec-2] c.e.t.RestController : do something for thread init.
2020-04-25 18:36:21.780 INFO 95474 --- [nio-8080-exec-9] c.e.t.RestController : do something for thread init.
2020-04-25 18:36:21.782 INFO 95474 --- [io-8080-exec-10] c.e.t.RestController : do something for thread init.
2020-04-25 18:36:21.781 INFO 95474 --- [nio-8080-exec-3] c.e.t.RestController : do something for thread init.
2020-04-25 18:36:21.781 INFO 95474 --- [nio-8080-exec-7] c.e.t.RestController : do something for thread init.
|
4. Considered Point
4.1. 1st Challenge
Tomcat
のThreadPool
はどこで管理されているのかを確認して、そこでスレッド初期化を実施すればいいんじゃないか?と思い、Tomcat
のソースコードを追った。
4.2. 2nd Challenge
色々試行錯誤し、「java how to get tomcat thread pool
」のような単語で、ググってみた。
- 「TomcatのJMXにWebアプリの中からアクセスしたい | DA BLOG」のブログを発見。
- 以下のような何かそれっぽい単語が出てきたので、これで
main thread
側から簡単にTomcat
のThreadPool
にアクセスできるのかな?と思った。
Tomcat
JMX(Java Management Extensions)
Webアプリからアクセス
- そこで、以下のプログラムを組んでみた。
application.properties
で以下の設定が必要。
server.tomcat.mbeanregistry.enabled=true
1
2
3
4
5
6
7
8
9
10
11
12
|
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
ObjectName objectName =
new ObjectName("Tomcat:type=ThreadPool,name=\"http-nio-8080\"");
String[] attributes = new String[] { "currentThreadsBusy", "maxThreads" };
AttributeList attrList = server.getAttributes(objectName, attributes);
attrList.asList()
.forEach(attr -> {
String name = attr.getName();
Object value = attr.getValue();
log.info("name={}, value={}", name, value);
});
|
- 実行結果
1
2
|
2020-04-25 18:25:53.904 INFO 94266 --- [ main] c.e.t.trash.OnStartServer : className=javax.management.Attribute, name=currentThreadsBusy, value=-2
2020-04-25 18:25:53.907 INFO 94266 --- [ main] c.e.t.trash.OnStartServer : className=javax.management.Attribute, name=maxThreads, value=10
|