Skip to content

Latest commit

ย 

History

History
268 lines (198 loc) ยท 16.5 KB

File metadata and controls

268 lines (198 loc) ยท 16.5 KB

๐ŸŒฑ Sprout

English | ํ•œ๊ตญ์–ด | ๐Ÿ“– Documentation

Spring์ด ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋งŒ๋“  ๊ฒฝ๋Ÿ‰ Java ์›น ํ”„๋ ˆ์ž„์›Œํฌ. ์ด์ œ ์™„์ „ํžˆ ์ž‘๋™ํ•˜๋Š” NIO & ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์„œ๋ฒ„์™€ ๋น„๋™๊ธฐ WebSocket ์Šคํƒ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ๋ช…ํ™•์„ฑ ยท ํ•ดํ‚น ๊ฐ€๋Šฅ์„ฑ ยท ํ™•์žฅ์„ฑ์„ ์ค‘์‹œํ•ฉ๋‹ˆ๋‹ค.

๋ฒ”์œ„: ์ปจํ…Œ์ด๋„ˆ/AOP/์›น/์„œ๋ฒ„ ๋‚ด๋ถ€ ๊ตฌ์กฐ์— ์ง‘์ค‘ํ•ฉ๋‹ˆ๋‹ค. ์ „์ฒด ORM์€ v1.0์—์„œ ์˜๋„์ ์œผ๋กœ ์ œ์™ธํ•˜์—ฌ ๋ฒ”์œ„๋ฅผ ์ž‘๊ฒŒ ์œ ์ง€ํ•˜๊ณ  ์ฝ”๋“œ ๊ฐ์‚ฌ๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.


โœจ ํ•ต์‹ฌ ๊ธฐ๋Šฅ (v1.0.0)

์˜์—ญ ์ƒํƒœ & ์ฃผ์š” ํŠน์ง•
IoC / DI ์ปจํ…Œ์ด๋„ˆ โ€ข @Component, @Service, @Controller, @Repository, @Configuration, @Aspect ์Šค์บ”.
โ€ข ์ƒ์„ฑ์ž ๊ธฐ๋ฐ˜ ์ฃผ์ž….
โ€ข @Order ์ง€์›๊ณผ ํ•จ๊ป˜ ์ž๋™ List<T> ์ฑ„์šฐ๊ธฐ.
โ€ข ์ˆœํ™˜ ์˜์กด์„ฑ ๊ฐ์ง€ (์œ„์ƒ ์ •๋ ฌ).
โ€ข BeanDefinitionRegistrar๋ฅผ ํ†ตํ•œ ์ž๋™ ๊ตฌ์„ฑ (ํ•ฉ๋ฆฌ์ ์ธ ๊ธฐ๋ณธ๊ฐ’ ์ œ๊ณต).
๋นˆ ์ •์˜ โ€ข ConstructorBeanDefinition & MethodBeanDefinition.
โ€ข ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ ๋˜๋Š” ์ƒ์„ฑ์ž ์ „๋žต.
โ€ข ์ƒ์„ฑ์ž ๋ฉ”ํƒ€ ์บ์‹œ โ†’ ํ•„์ˆ˜ ์ธ์ž ์ƒ์„ฑ์ž๋ฅผ ์œ„ํ•œ ์•ˆ์ „ํ•œ ํ”„๋ก์‹œ ์ƒ์„ฑ.
AOP โ€ข ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ (@Before, @After, @Around).
โ€ข AspectJ ์Šคํƒ€์ผ ํฌ์ธํŠธ์ปท (*, .., ?).
โ€ข Spring์—์„œ ์˜๊ฐ์„ ๋ฐ›์€ Advisor/Advice/Pointcut ๊ณ„์ธต ๊ตฌ์กฐ.
โ€ข CGLIB ์„œ๋ธŒํด๋ž˜์‹ฑ + Objenesis ํด๋ฐฑ (๊ธฐ๋ณธ ์ƒ์„ฑ์ž ๋ถˆํ•„์š”).
โ€ข ์ˆœ์„œ๊ฐ€ ์ง€์ •๋œ advisor ์ฒด์ธ, ํƒ€๊ฒŸ๋ณ„ ํ”„๋ก์‹œ.
๊ตฌ์„ฑ ํ”„๋ก์‹œ @Configuration(proxyBeanMethods = true)๋ฅผ ์œ„ํ•œ CGLIB ํ”„๋ก์‹œ โ†’ ๋ฐ˜๋ณต๋˜๋Š” @Bean ํ˜ธ์ถœ ์บ์‹ฑ.
์›น ๋ ˆ์ด์–ด (HTTP) โ€ข ์„ ์–ธ์  ๋ผ์šฐํŒ… (@GetMapping, @PostMapping, โ€ฆ + {var} ํŒจํ„ด).
โ€ข @PathVariable, @RequestParam, @RequestBody ๋“ฑ์„ ์œ„ํ•œ ArgumentResolver.
โ€ข RequestDispatcher๊ฐ€ ๋ฐ”์ธ๋”ฉ โ†’ ํ˜ธ์ถœ โ†’ ํ•ด๊ฒฐ (ResponseEntity, DTO, void).
์„œ๋ฒ„ ์‹ ๊ทœ: java.nio.channels ๊ธฐ๋ฐ˜ NIO ์„œ๋ฒ„.
โ€ข ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ชจ๋“œ: ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ๋˜๋Š” ํด๋ž˜์‹ ํ’€์„ ํ†ตํ•œ HTTP, NIO๋ฅผ ํ†ตํ•œ WS; ์„ค์ •์— ๋”ฐ๋ผ ์„ ํƒ ๊ฐ€๋Šฅ.
โ€ข ํ•™์Šต/๋‹จ์ˆœ์„ฑ์„ ์œ„ํ•œ ๋ธ”๋กœํ‚น ํด๋ฐฑ ์œ ์ง€.
ํ•„ํ„ฐ & ์ธํ„ฐ์…‰ํ„ฐ โ€ข ์„œ๋ธ”๋ฆฟ ์Šคํƒ€์ผ Filter ์ฒด์ธ.
โ€ข ๊ธ€๋กœ๋ฒŒ ํ•„ํ„ฐ (์ธ์ฆ, CORS, ๋กœ๊น…โ€ฆ).
โ€ข ๋ฏธ๋“ค์›จ์–ด ์Šคํƒ€์ผ Interceptor ์ฒด์ธ.
โ€ข RequestDispatcher์— List<Filter> / List<Interceptor> ์ž๋™ ์ฃผ์ž….
๋ณด์•ˆ โ€ข ๋ชจ๋“ˆ์‹ ์ธ์ฆ (AuthenticationManager, AuthenticationProvider, UserDetailsService).
โ€ข AuthenticationFilter๋ฅผ ํ†ตํ•œ ์‚ฌ์šฉ์ž๋ช…/๋น„๋ฐ€๋ฒˆํ˜ธ ๋กœ๊ทธ์ธ.
โ€ข @PreAuthorize๋ฅผ ํ†ตํ•œ ๋ฉ”์„œ๋“œ ๋ณด์•ˆ (AOP ๊ธฐ๋ฐ˜).
โ€ข AuthorizationFilter๋ฅผ ํ†ตํ•œ URL ๊ถŒํ•œ ๋ถ€์—ฌ.
โ€ข ์š”์ฒญ๋ณ„ ThreadLocal์„ ์‚ฌ์šฉํ•˜๋Š” SecurityContextHolder.
โ€ข ์ž๋™ ๊ตฌ์„ฑ (@EnableSproutSecurity).
์˜ˆ์™ธ ์ฒ˜๋ฆฌ โ€ข HTTP ์˜ˆ์™ธ (BadRequest, MethodNotAllowed, โ€ฆ).
โ€ข @ControllerAdvice + @ExceptionHandler.
โ€ข ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ExceptionResolver ์ฒด์ธ.
๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค โ€ข ๊ฒฝ๋Ÿ‰ JdbcTemplate ์ถ”์ƒํ™”.
โ€ข HikariCP ํ†ตํ•ฉ.
โ€ข AOP ๊ธฐ๋ฐ˜ @Transactional ์ง€์›.
โ€ข TransactionManager ์ถ”์ƒํ™” (์ž๋™ ์ปค๋ฐ‹/๋กค๋ฐฑ).
WebSocket (๋น„๋™๊ธฐ/NIO) โ€ข RFC6455 ํ•ธ๋“œ์…ฐ์ดํฌ + ํ”„๋ ˆ์ž„ ํŒŒ์„œ/์ธ์ฝ”๋” (๋งˆ์Šคํ‚น, ping/pong, close).
โ€ข ๋…ผ๋ธ”๋กœํ‚น ์“ฐ๊ธฐ ํ, OP_WRITE ํ† ๊ธ€, ๋“œ๋ ˆ์ธ ํ›„ ์šฐ์•„ํ•œ ์ข…๋ฃŒ.
โ€ข ๋‹จํŽธํ™” ์ฒ˜๋ฆฌ (ํ…์ŠคํŠธ/๋ฐ”์ด๋„ˆ๋ฆฌ ์—ฐ์† ํ”„๋ ˆ์ž„).
โ€ข WebSocketSession ์ถ”์ƒํ™” + ์ƒ๋ช…์ฃผ๊ธฐ ํ›… (@OnOpen, @OnMessage, @OnClose, @OnError).
โ€ข ํ”Œ๋Ÿฌ๊ทธํ˜• WebSocketMessageDispatcher & WebSocketArgumentResolver.
โ€ข HTTP NIO์™€ ๋™์ผํ•œ ์…€๋ ‰ํ„ฐ ๋ฃจํ”„์—์„œ ์‹คํ–‰๋˜๊ฑฐ๋‚˜ ๋ณ„๋„๋กœ ์‹คํ–‰ ๊ฐ€๋Šฅโ€”๊ตฌ์„ฑ ๊ฐ€๋Šฅ.
๋ถ€ํŠธ์ŠคํŠธ๋žฉ ํ•œ ์ค„๋กœ ์‹คํ–‰: SproutApplication.run()์ด ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋ถ€ํŒ…ํ•˜๊ณ  ์„œ๋ฒ„๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿƒโ€โ™‚๏ธ ๋น ๋ฅธ ์‹œ์ž‘

  1. ํด๋ก  & ๋นŒ๋“œ
$ git clone https://github.com/yyubin/sprout.git
$ cd sprout && ./gradlew build
  1. ์‹คํ–‰

Java 21 + CGLIB ํ”„๋ก์‹œ๋Š” --add-opens ํ”Œ๋ž˜๊ทธ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค (๊นŠ์€ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์ œ๊ฑฐํ•  ๋•Œ๊นŒ์ง€):

$ java \
  --add-opens=java.base/java.lang=ALL-UNNAMED \
  --add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
  --add-opens=java.base/java.io=ALL-UNNAMED \
  --add-opens=java.base/java.util=ALL-UNNAMED \
  -jar build/libs/sprout.jar

์„œ๋ฒ„ ๋ชจ๋“œ/์Šค๋ ˆ๋“œ ๋ชจ๋ธ์€ ์ด์ œ CLI ์ธ์ž๊ฐ€ ์•„๋‹Œ application.yml์—์„œ ์ฝ์–ด์˜ต๋‹ˆ๋‹ค.

  1. ์ตœ์†Œ ์˜ˆ์ œ (๋ณ€๊ฒฝ ์—†์Œ)
@ComponentScan("app")
public class DemoApplication {
    public static void main(String[] args) throws Exception {
        SproutApplication.run(DemoApplication.class);
    }
}
@Aspect
public class LoggingAspect {
    @Around(pointcut = "app..*Service.*")
    public Object logExecTime(ProceedingJoinPoint pjp) throws Throwable {
        long t0 = System.nanoTime();
        try {
            return pjp.proceed();
        } finally {
            System.out.printf("%s took %d ยตs%n", pjp.getSignature().toLongString(),
                              (System.nanoTime()-t0)/1_000);
        }
    }
}
@Controller
@RequestMapping("/api")
public class TestController {
    private final GreetingService svc;
    public TestController(GreetingService svc) { this.svc = svc; }

    @GetMapping("/hello/{id}")
    public MessageDto hello(@PathVariable Long id) {
        return new MessageDto(svc.greet(id));
    }
}

โš™๏ธ ๊ตฌ์„ฑ (application.yml)

Sprout๋Š” ์‹œ์ž‘ ์‹œ AppConfig๋ฅผ ํ†ตํ•ด application.yml์„ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ์ค‘์ฒฉ๋œ ํ‚ค๋Š” ์  ํ‘œ๊ธฐ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค (์˜ˆ: server.execution-mode).

author: you
server:
  execution-mode: hybrid   # nio | hybrid (๊ธฐ๋ณธ๊ฐ’: hybrid)
  thread-type: virtual     # virtual | platform (ํ•˜์ด๋ธŒ๋ฆฌ๋“œ/๋ธ”๋กœํ‚น HTTP ์›Œ์ปค์—๋งŒ ์ ์šฉ)
  thread-pool-size: 150    # thread-type = platform์ผ ๋•Œ ์‚ฌ์šฉ

sprout:
  database:
    url: jdbc:mysql://localhost:3306/sprout
    username: root
    password: change-me

์„œ๋ฒ„ ๋ชจ๋“œ

๋ชจ๋“œ HTTP WebSocket ์‚ฌ์šฉ ์‚ฌ๋ก€
blocking ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ ํ•ด๋‹น ์—†์Œ ๋””๋ฒ„๊น…/ํ•™์Šต
nio NIO ์…€๋ ‰ํ„ฐ NIO ๋†’์€ ๋™์‹œ์„ฑ/๋‚ฎ์€ ๋ฉ”๋ชจ๋ฆฌ
hybrid ๊ฐ€์ƒ/ํ’€ (HTTP) NIO (WS) ํ”„๋กœ๋•์…˜ ํ•™์Šต ๊ฒฝํ—˜

์Šค๋ ˆ๋“œ ์œ ํ˜•

์œ ํ˜• ์‚ฌ์šฉ ์‹œ๊ธฐ
virtual ์š”์ฒญ ํ•ธ๋“ค๋Ÿฌ์˜ ๊ธฐ๋ณธ ์„ ํƒ (๊ถŒ์žฅ)
platform pool ๋™์‹œ์„ฑ์„ ์ œํ•œํ•ด์•ผ ํ•  ๋•Œ๋งŒ (JDBC ๋“œ๋ผ์ด๋ฒ„, ๋ธ”๋กœํ‚น I/O)

์—ฐ๊ฒฐ ๋ฐฉ์‹

  • AppConfig๊ฐ€ YAML์„ ํ•œ ๋ฒˆ ์ฝ๊ณ  ํ—ฌํผ๋ฅผ ์ œ๊ณต: getStringProperty, getIntProperty.

  • ServerAutoConfigurationRegistrar๊ฐ€ server.* ํ‚ค๋ฅผ ๊ฒ€์‚ฌํ•˜๊ณ  ๋“ฑ๋ก:

    • HTTP ํ•ธ๋“ค๋Ÿฌ: NioHttpProtocolHandler ๋˜๋Š” BlockingHttpProtocolHandler (ํ•˜์ด๋ธŒ๋ฆฌ๋“œ/๋ธ”๋กœํ‚น์šฉ)
    • RequestExecutorService: VirtualRequestExecutorService (๊ฐ€์ƒ ์Šค๋ ˆ๋“œ) ๋˜๋Š” RequestExecutorPoolService (๊ณ ์ • ํ’€)

ํŒ: ์š”์ฒญ ํ•ธ๋“ค๋Ÿฌ์—๋Š” ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ์„ ํ˜ธํ•˜์„ธ์š”; ๋™์‹œ์„ฑ์„ ์ œํ•œํ•ด์•ผ ํ•  ๋•Œ๋งŒ ๊ณ ์ • ํ’€๋กœ ์ „ํ™˜ํ•˜์„ธ์š” (์˜ˆ: JDBC ๋“œ๋ผ์ด๋ฒ„ ๋˜๋Š” ๋ธ”๋กœํ‚น I/O).


๐ŸŽฅ WebSocket ๋ฐ๋ชจ & ๋ฒค์น˜๋งˆํฌ

Sprout WebSocket Demo

์ด ๋น„๋””์˜ค๋Š” Sprout์˜ ์™„์ „ํ•œ ๋…ผ๋ธ”๋กœํ‚น NIO WebSocket ์Šคํƒ์ด ์ž‘๋™ํ•˜๋Š” ๋ชจ์Šต์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

๋ฐ๋ชจ์—์„œ ๋ณด์—ฌ์ง€๋Š” ๊ฒƒ:

  • NIO ๊ธฐ๋ฐ˜ WebSocket ํ•ธ๋“œ์…ฐ์ดํฌ & ํ”„๋ ˆ์ž„ ์ฒ˜๋ฆฌ
  • ๋™์‹œ ํด๋ผ์ด์–ธํŠธ ์—ฐ๊ฒฐ
  • Echo, ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ, ์ฑ„ํŒ… ์Šคํƒ€์ผ ๋ฉ”์‹œ์ง•
  • Ping/Pong ํ”„๋ ˆ์ž„
  • ์šฐ์•„ํ•œ ์ข…๋ฃŒ ์ฒ˜๋ฆฌ
  • OP_WRITE ํ† ๊ธ€์„ ์‚ฌ์šฉํ•œ ๋…ผ๋ธ”๋กœํ‚น ์“ฐ๊ธฐ ํ

๋น„๋””์˜ค์—์„œ ์‚ฌ์šฉ๋œ ํ•ธ๋“ค๋Ÿฌ๋Š” Sprout์˜ API๋กœ ๊ตฌ์ถ•๋œ ์‹ค์ œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ WebSocket ํ•ธ๋“ค๋Ÿฌ์ž…๋‹ˆ๋‹ค (์•„๋ž˜ ์ฐธ์กฐ).


๐Ÿงฉ WebSocket ์˜ˆ์ œ

@Component
@WebSocketHandler("/ws/benchmark")
public class WebSocketBenchmarkHandler {

    private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    @OnOpen
    public void onOpen(WebSocketSession session) {
        sessions.put(session.getId(), session);
    }

    @OnClose
    public void onClose(WebSocketSession session, CloseCode code) {
        sessions.remove(session.getId());
    }

    @MessageMapping("/echo")
    public void echo(WebSocketSession session, @Payload String msg) throws IOException {
        session.sendText(msg);
    }

    @MessageMapping("/broadcast")
    public void broadcast(WebSocketSession session, @Payload String msg) throws IOException {
        for (WebSocketSession s : sessions.values()) {
            if (s.isOpen()) s.sendText(msg);
        }
    }

    @MessageMapping("/ping")
    public void ping(WebSocketSession session, @Payload String ignored) throws IOException {
        session.sendPing("ping".getBytes());
    }
}

๋…ผ๋ธ”๋กœํ‚น ์“ฐ๊ธฐ ๋ฐ ํ”„๋ ˆ์ž„ ๋ ˆ๋ฒจ ์ œ์–ด์™€ ํ•จ๊ป˜ Sprout์˜ NIO ์…€๋ ‰ํ„ฐ ๋ฃจํ”„์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.


๐Ÿงช ํ…Œ์ŠคํŠธ

๋ฆฌํฌํŠธ: Tests ยท Coverage

687๊ฐœ ํ…Œ์ŠคํŠธ, 0๊ฐœ ์‹คํŒจ (100% ํ†ต๊ณผ, Gradle 8.10.1 ยท 2025โ€‘10-27)

ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ (Jacoco):

  • ๋ผ์ธ ์ปค๋ฒ„๋ฆฌ์ง€: 85%
  • ๋ธŒ๋žœ์น˜ ์ปค๋ฒ„๋ฆฌ์ง€: 75%

์ปค๋ฒ„๋ฆฌ์ง€ ํ•˜์ด๋ผ์ดํŠธ:

  • ํ•ต์‹ฌ ์ปจํ…Œ์ด๋„ˆ: ์Šค์บ๋‹, ๋นˆ ๊ทธ๋ž˜ํ”„/์œ„์ƒ ์ •๋ ฌ, ์ƒ์„ฑ์ž ์ฃผ์ž…, @Order ๋ฆฌ์ŠคํŠธ ์ฃผ์ž…
  • AOP: advice ๋นŒ๋”/์ธํ„ฐ์…‰ํ„ฐ, advisor ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ, ํฌ์ธํŠธ์ปท ํŒŒ์‹ฑ
  • MVC ๋ ˆ์ด์–ด: ์š”์ฒญ ํŒŒ์‹ฑ (๋ผ์ธ/ํ—ค๋”/์ฟผ๋ฆฌ), ํ•ธ๋“ค๋Ÿฌ ๋งคํ•‘ & ํ˜ธ์ถœ, argument resolver, ์˜ˆ์™ธ advice
  • ๋ณด์•ˆ: ์ธ์ฆ provider, ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฝ”๋”ฉ, ์ปจํ…์ŠคํŠธ ์ „ํŒŒ, ํ•„ํ„ฐ & ๊ถŒํ•œ ๋ถ€์—ฌ aspect
  • ์„œ๋ฒ„ ์Šคํƒ: HTTP Blocking/NIO/Hybrid ์ „๋žต, executor service (๊ฐ€์ƒ vs ํ’€), ํ”„๋กœํ† ์ฝœ detector/handler
  • WebSocket: ํ•ธ๋“œ์…ฐ์ดํฌ, ํ”„๋ ˆ์ž„ ์ธ์ฝ”๋”/ํŒŒ์„œ, ping/pong, ๋‹จํŽธํ™”, ๋น„๋™๊ธฐ ์“ฐ๊ธฐ & ์šฐ์•„ํ•œ ์ข…๋ฃŒ, dispatcher/resolver
  • ์œ ํ‹ธ๋ฆฌํ‹ฐ: HttpUtils (Content-Length & chunked), ์‘๋‹ต ๋ฒ„ํผ ์ƒ์„ฑ, ๊ธฐํƒ€ ํ—ฌํผ

๋„๊ตฌ & ์Šคํƒ€์ผ:

  • JUnit 5 + Mockito (JDK-final ํด๋ž˜์Šค๋ฅผ ์œ„ํ•œ ์ธ๋ผ์ธ/lenient)
  • ๋ฌด๊ฑฐ์šด ๋ชจํ‚น๋ณด๋‹ค ๊ฒฐ์ •๋ก ์  ๋™์ž‘์„ ์„ ํ˜ธํ•˜๋Š” ๊ฐ€์งœ ๊ตฌํ˜„ (์˜ˆ: ํ”„๋ ˆ์ž„ ์ธ์ฝ”๋”/ํŒŒ์„œ)
  • ์‹ค์ œ ์†Œ์ผ“ ์—†์ด NIO ๋™์ž‘์„ ๊ฒ€์ฆํ•˜๊ธฐ ์œ„ํ•œ Selector/interestOps ์ƒํƒœ ๊ฐ€์งœ
  • ๋นŒ๋“œ ๋ฆฌํฌํŠธ: build/reports/tests/test/index.html

๐Ÿ—บ๏ธ ๋กœ๋“œ๋งต

๋ฆด๋ฆฌ์Šค ๊ณ„ํš / ์™„๋ฃŒ ๋น„๊ณ 
v0.2 โœ… AOP ํ•ต์‹ฌ ์ œ๊ณต @Before/@After/@Around, AspectJ ํฌ์ธํŠธ์ปท
v0.3 โœ… ๋ฏธ๋“ค์›จ์–ด & ๊ธ€๋กœ๋ฒŒ ์ธํ„ฐ์…‰ํ„ฐ ํ•„ํ„ฐ + ์ธํ„ฐ์…‰ํ„ฐ ์ฒด์ธ
v0.4 โœ… ๋ฐ์ดํ„ฐ ์•ก์„ธ์Šค & ๋ณด์•ˆ ํ•ต์‹ฌ JdbcTemplate, @Transactional, ์ธ์ฆ/๊ถŒํ•œ๋ถ€์—ฌ
v0.5 โœ… NIO & ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ์„œ๋ฒ„, ๋น„๋™๊ธฐ WebSocket ์…€๋ ‰ํ„ฐ ๋ฃจํ”„, OP_WRITE ๊ด€๋ฆฌ, ์šฐ์•„ํ•œ ์ข…๋ฃŒ
v1.0 ๐ŸŽฏ ์•ˆ์ •์ ์ธ API & ํ”„๋ ˆ์ž„์›Œํฌ ์„ฑ์ˆ™๋„ ํ”„๋กœ๋•์…˜ ์‚ฌ์šฉ ์ค€๋น„, ํฌ๊ด„์ ์ธ ๋ฌธ์„œ

v1.0 ์ดํ›„ ๋กœ๋“œ๋งต:

๊ธฐ๋Šฅ ์ƒํƒœ ์„ค๋ช…
๊ฒฝ๋Ÿ‰ ORM ๐Ÿ”„ ๊ณ„ํš๋จ ์—”ํ‹ฐํ‹ฐ ๋งคํ•‘, ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ ORM, ๊ฐ„๋‹จํ•œ ์ฟผ๋ฆฌ DSL
ํ”„๋กœ๋•์…˜ ๋„๊ตฌ ๐Ÿ”„ ๊ณ„ํš๋จ ๋ฉ”ํŠธ๋ฆญ, ๋ชจ๋‹ˆํ„ฐ๋ง, ํ–ฅ์ƒ๋œ ์„ฑ๋Šฅ ํ”„๋กœํŒŒ์ผ๋ง
๊ณ ๊ธ‰ ๊ธฐ๋Šฅ ๐Ÿ”„ ๊ณ„ํš๋จ ํ–ฅ์ƒ๋œ ๋ณด์•ˆ, ์บ์‹ฑ ๋ ˆ์ด์–ด, ๊ฒ€์ฆ ํ”„๋ ˆ์ž„์›Œํฌ

๋กœ๋“œ๋งต์€ ์ง€ํ–ฅ์  ์ž…๋‹ˆ๋‹ค. ํ•™์Šต ๊ณ„ํš์— ๋”ฐ๋ผ ๋ณ€๋™ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ™ ๊ฐ์‚ฌ์˜ ๋ง

  • Spring Framework โ€” ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค..
  • Reflections, CGLIB, Objenesis, Jackson โ€” ๋Ÿฐํƒ€์ž„ ๋ฉ”ํƒ€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ & ์ง๋ ฌํ™” ๋ฐฑ๋ณธ.

๐Ÿค ๊ธฐ์—ฌ

PR & ์ด์Šˆ๋ฅผ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค. ๋กœ๋“œ๋งต ํ•ญ๋ชฉ์„ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ๊ธฐ๋Šฅ์„ ์ œ์•ˆํ•ด์ฃผ์„ธ์š”.


๐Ÿ“œ ๋ผ์ด์„ ์Šค

MIT License. LICENSE ์ฐธ์กฐ.