Upgrade to Pro — share decks privately, control downloads, hide ads and more …

軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2...

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

軽量Java基盤の設計 DIコンテナに頼らない、長期保守と1秒起動の実現 JJUG CCC 2026 Spring

JJUG CCC 2026 Springの発表資料です。

Avatar for Masaaki Takahashi

Masaaki Takahashi

June 01, 2026

Other Decks in Programming

Transcript

  1. Web • • Spring+Hibernate/Quarkus+Hibernate/JAX-RS+Hibernate/JAX-RS+DbUtils • • 100 Entity 1 20

    • 400 Service Entity CRUD • 400 Controller MPA Web • 900 • • Controller
  2. ※2025 / # DI 10 EntityManager 10 22 Spring Web

    MVC + Hibernate JVM /Native Image 20 Quarkus + Hibernate DI 8 JAX-RS/RestEasy + Hibernate ORM 2 JAX-RS/RestEasy + Commons DbUtils Quarkus 20 Quarkus
  3. // DI public class OrderService { // // DI public

    OrderService(PaymentService paymentService) { this.paymentService = paymentService; } }
  4. // public class OrderService { private final PaymentService paymentService; //

    // ServiceLocator public OrderService() { this.paymentService = ServiceLocator.get(PaymentService.class); } }
  5. DiRegistry Dependency Inversion Registry • ID • • DiRegistry DI

    Dependency Injection DIP Dependency Inversion Principle Composition Root
  6. 24

  7. // DiRegistryBase extends public class AppRegistry extends DiRegistryBase<AppResources> { //

    // public final static DiProfile<AppResources> PROFILE = DiProfile.<AppResources>builder() // .resource( AppResources.DB_SESSION_FACTORY, // ID "com.example.fw.db.SessionFactoryImpl", // new String[] { "hikaricp.properties" // } ) .resource(……) .build(); }
  8. public class AppRegistry extends DiRegistryBase<AppResources> { // …… public AppRegistry()

    { this(PROFILE); } public static AppRegistry getInstance() { return INSTANCE; } public static AppRegistry setProfile(DiProfile profile) { PROFILE = profile; } }
  9. public interface DiRegistry<R> { <T> T get(R key) throws SystemException;

    } public abstract class DiRegistryBase<R> implements DiRegistry<R> { // // ConcurrentHashMap private final DiProfile<R> profile; public DiRegistryBase(DiProfile<R> profile) { this.profile = profile; } @Override public <T> T get(R key) throws SystemException { return (T) getResource(key); } } DiRegistry
  10. public abstract class DiRegistryBase<R> implements DiRegistry<R> { // private Object

    getResource(R key) throws SystemException { var diResource = profile.getResources().stream() .filter(resource -> resource.getResource().equals(key)) .findFirst() .orElse(null); try { // return Class.forName(diResource.getClassName()). getConstructor(String[].class). newInstance(diResource.getArgs()); } catch (Exception e) { throw new SystemException(e); } } }
  11. public abstract class AppTestBase { // static { AppRegistry.setProfile( //

    DiProfile.<AppResources>builder() // ...... .resource( AppResources.DB_SESSION_FACTORY, "com.example.fw.db.MockSessionFactoryImpl", new String[] {} ) .build() ); } } DiRegistry DiRegistry
  12. Spring Framework DiRegistry • Auth • JDBC • Batch/OnBach •

    Appserver • Template • FaaS • ……
  13. src/main/java/ ├─ module-info.java // JPMS ├┬ com.example.fw.mail/ // │├─ MailFactory

    (interface) │└─ Mail (interface) ├┬ com.example.fw.mail.javamail/ // JavaMail │├─ MailFactoryImpl │└─ MailImpl └┬ com.example.fw.mail.sesv2/ // AmazonSES ├─ MailFactoryImpl └─ MailImpl JavaMail AmazonSES Mail
  14. // module-info.java module com.example.fw.mail { exports com.example.fw.mail; // // exports

    com.example.fw.mail.javamail // // exports com.example.fw.mail.sesv2 // opens com.example.fw.mail.javamail to com.example.fw.core; // DiRegistry javamail opens com.example.fw.mail.sesv2 to com.example.fw.core; // DiRegistry sesv2 requires jakarta.mail; requires software.amazon.awssdk.services.sesv2; } module-info.java
  15. // com.example.fw.mail public interface MailFactory { Mail newMail(String mailId); }

    // com.example.fw.mail public interface Mail { void addTo(String mailAddress); void setSubject(String subject); void setBody(String body); void send() throws SystemException; } MailFactory Mail
  16. public class MailFactoryImpl implements MailFactory { private final MailConfig config;

    public MailFactoryImpl(String[] args) { this.config = ConfigFactory.getConfig(args[0], MailConfig.class); } @Override public Mail newMail(String mailId) { return new MailImpl(this, mailId); } } public class MailImpl implements Mail { @Override public void send() throws SystemException { var mail = render(getMailRenderer()); getMailSender().sendMail(mail); } } JavaMail MailFactoryImpl MailImpl
  17. dependencies { // Core dependencies implementation(libs.slf4j.api) // CompileOnly dependencies compileOnly(libs.jakarta.mail)

    compileOnly(libs.angus.mail) compileOnly(platform(libs.awssdk2.bom)) compileOnly(libs.awssdk2.ses) // RuntimeOnly dependencies runtimeOnly(libs.logback.core) runtimeOnly(libs.logback.classic) } Gradle dependencies JavaMail AmazonSES compileOnly runtimeOnly
  18. public class AppRegistry extends DiRegistryBase<AppResources> { public final static DiProfile<AppResources>

    PROFILE = DiProfile.<AppResources>builder() // ...... .resource( AppResources.MAIL_FACTORY, // JavaMail Amazon SES "com.example.fw.mail.javamail.MailFactoryImpl", // "com.example.fw.mail.sesv2.MailFactoryImpl", new String[] { // "mail-config.yaml", } ) .build(); } DiRegistry MailFactory
  19. // DiRegistry // JPMS var mailFactory = (MailFactory) AppRegistry.getInstance().get(AppResources.MAIL_FACTORY); var

    mail = mailFactory.newMail("HELLO_WORLD"); mail.addTo("[email protected]"); mail.setSubject("Hello,world"); mail.setBody("Hello,world!"); mail.send(); // JavaMail
  20. REST API FaaS AWS Lambda DB 1 S3 1 (

    FW/Python/SpringBoot) REST API SnapStart SnapStart Lambda
  21. SnapStart 30 ms 3,500 ms SnapStart 12MB 512MB FW 300

    ms 1,500 ms SnapStart 0.8MB 512MB Python 30 ms 9,000 ms SnapStart 34MB 512MB SpringBoot ※ SnapStart DiRegistry 2MB JDBC 2
  22. public class Application implements RequestHandler<……> { static { warmUpAndRestart(); }

    // static private static void warmUpAndRestart() { // Map<String, Object> input = Map.of(……); // /system/dbS3Ping getFunctionDispatcher().dispatch(input, Map.of()); // AppRegistry.getInstance().restart(); } } static warmUpAndRestart SnapStart static
  23. FW Lambda 2 Python 30 ms 3,500 ms → 1,700

    ms SnapStart 12MB 512MB FW 300 ms 1,500 ms SnapStart 0.8MB 512MB Python 30 ms 9,000 ms SnapStart 34MB 512MB SpringBoot ※ SnapStart DiRegistry DiRegistry
  24. Java REST API Web FaaS • Tomcat AP • AP

    FaaS • DB AWS RDS Proxy • Java FaaS