スキル一覧に戻る
yejune

do-lang-java

by yejune

0🍴 0📅 2026年1月15日
GitHubで見るManusで実行

SKILL.md


빠른 참조

Java 21 LTS 전문가 - Spring Boot 3.3, Virtual Threads, 모던 Java 기능을 활용한 엔터프라이즈 개발

자동 활성화: Java 파일(.java), 빌드 파일(pom.xml, build.gradle, build.gradle.kts)

핵심 기능:

  • Java 21 LTS: Virtual Threads, Pattern Matching, Record Patterns, Sealed Classes
  • Spring Boot 3.3: REST Controllers, Services, Repositories, WebFlux Reactive
  • Spring Security 6: JWT 인증, OAuth2, 역할 기반 접근 제어
  • JPA/Hibernate 7: Entity 매핑, 관계, 쿼리, 트랜잭션
  • JUnit 5: 단위 테스트, Mocking, TestContainers 통합
  • 빌드 도구: Maven 3.9, Gradle 8.5 Kotlin DSL

구현 가이드

Java 21 LTS 기능

Virtual Threads (Project Loom):

// 경량 동시 프로그래밍
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i ->
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        })
    );
}

// Structured Concurrency (preview)
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    Supplier<User> user = scope.fork(() -> fetchUser(userId));
    Supplier<List<Order>> orders = scope.fork(() -> fetchOrders(userId));
    scope.join().throwIfFailed();
    return new UserWithOrders(user.get(), orders.get());
}

Switch용 Pattern Matching:

String describe(Object obj) {
    return switch (obj) {
        case Integer i when i > 0 -> "양수: " + i;
        case Integer i -> "비양수: " + i;
        case String s -> "문자열 길이 " + s.length();
        case List<?> list -> "목록 " + list.size() + "개 요소";
        case null -> "널 값";
        default -> "알 수 없는 타입";
    };
}

Record Patterns와 Sealed Classes:

record Point(int x, int y) {}
record Rectangle(Point topLeft, Point bottomRight) {}

int area(Rectangle rect) {
    return switch (rect) {
        case Rectangle(Point(var x1, var y1), Point(var x2, var y2)) ->
            Math.abs((x2 - x1) * (y2 - y1));
    };
}

public sealed interface Shape permits Circle, Rectangle {
    double area();
}
public record Circle(double radius) implements Shape {
    public double area() { return Math.PI * radius * radius; }
}

Spring Boot 3.3

REST Controller:

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;

    @GetMapping("/{id}")
    public ResponseEntity<UserDto> getUser(@PathVariable Long id) {
        return userService.findById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }

    @PostMapping
    public ResponseEntity<UserDto> createUser(@Valid @RequestBody CreateUserRequest request) {
        UserDto user = userService.create(request);
        URI location = URI.create("/api/users/" + user.id());
        return ResponseEntity.created(location).body(user);
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        return userService.delete(id)
            ? ResponseEntity.noContent().build()
            : ResponseEntity.notFound().build();
    }
}

Service 계층:

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;

    public Optional<User> findById(Long id) {
        return userRepository.findById(id);
    }

    @Transactional
    public User create(CreateUserRequest request) {
        if (userRepository.existsByEmail(request.email())) {
            throw new DuplicateEmailException(request.email());
        }
        var user = User.builder()
            .name(request.name())
            .email(request.email())
            .passwordHash(passwordEncoder.encode(request.password()))
            .status(UserStatus.PENDING)
            .build();
        return userRepository.save(user);
    }
}

Spring Security 6

보안 설정:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/api/public/**").permitAll()
                .requestMatchers("/api/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
            .sessionManagement(session ->
                session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
            .csrf(csrf -> csrf.disable())
            .build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

JPA/Hibernate 패턴

Entity 정의:

@Entity
@Table(name = "users")
@Getter @Setter
@NoArgsConstructor @Builder
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;

    @Column(nullable = false, unique = true)
    private String email;

    @Enumerated(EnumType.STRING)
    private UserStatus status;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Order> orders = new ArrayList<>();
}

커스텀 쿼리 Repository:

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
    boolean existsByEmail(String email);

    @Query("SELECT u FROM User u LEFT JOIN FETCH u.orders WHERE u.id = :id")
    Optional<User> findByIdWithOrders(@Param("id") Long id);

    Page<User> findByNameContainingIgnoreCase(String name, Pageable pageable);
}

Record DTO:

public record UserDto(Long id, String name, String email, UserStatus status) {
    public static UserDto from(User user) {
        return new UserDto(user.getId(), user.getName(), user.getEmail(), user.getStatus());
    }
}

public record CreateUserRequest(
    @NotBlank @Size(min = 2, max = 100) String name,
    @NotBlank @Email String email,
    @NotBlank @Size(min = 8) String password
) {}

고급 패턴

Virtual Threads 통합

@Service
@RequiredArgsConstructor
public class AsyncUserService {
    public UserWithDetails fetchUserDetails(Long userId) throws Exception {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            Supplier<User> userTask = scope.fork(() -> userRepo.findById(userId).orElseThrow());
            Supplier<List<Order>> ordersTask = scope.fork(() -> orderRepo.findByUserId(userId));
            scope.join().throwIfFailed();
            return new UserWithDetails(userTask.get(), ordersTask.get());
        }
    }

    public void processUsersInParallel(List<Long> userIds) {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            userIds.stream().map(id -> executor.submit(() -> processUser(id))).toList();
        }
    }
}

빌드 설정

Maven 3.9:

<project>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.0</version>
    </parent>
    <properties><java.version>21</java.version></properties>
    <dependencies>
        <dependency><groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId></dependency>
        <dependency><groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId></dependency>
    </dependencies>
</project>

Gradle 8.5 (Kotlin DSL):

plugins {
    id("org.springframework.boot") version "3.3.0"
    id("io.spring.dependency-management") version "1.1.4"
    java
}
java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

JUnit 5 테스트

단위 테스트:

@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock private UserRepository userRepository;
    @InjectMocks private UserService userService;

    @Test
    void shouldCreateUser() {
        when(userRepository.existsByEmail(anyString())).thenReturn(false);
        when(userRepository.save(any())).thenReturn(User.builder().id(1L).build());
        var result = userService.create(new CreateUserRequest("John", "john@test.com", "pass"));
        assertThat(result.getId()).isEqualTo(1L);
    }
}

TestContainers 통합 테스트:

@Testcontainers
@SpringBootTest
class UserRepositoryTest {
    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");

    @DynamicPropertySource
    static void props(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
    }

    @Autowired UserRepository repo;

    @Test
    void shouldSaveUser() {
        var user = repo.save(User.builder().name("John").email("john@test.com").build());
        assertThat(user.getId()).isNotNull();
    }
}

Context7 통합

최신 문서용 라이브러리 매핑:

  • /spring-projects/spring-boot - Spring Boot 3.3 문서
  • /spring-projects/spring-framework - Spring Framework 코어
  • /spring-projects/spring-security - Spring Security 6
  • /hibernate/hibernate-orm - Hibernate 7 ORM 패턴
  • /junit-team/junit5 - JUnit 5 테스트 프레임워크

연관 스킬

  • do-lang-kotlin - Kotlin 상호운용성, Spring Kotlin 확장
  • do-domain-backend - REST API, GraphQL, 마이크로서비스 아키텍처
  • do-domain-database - JPA, Hibernate, R2DBC 패턴
  • do-foundation-quality - JUnit 5, Mockito, TestContainers 통합
  • do-infra-docker - JVM 컨테이너 최적화

문제 해결

일반적인 이슈:

  • 버전 불일치: java -version 확인, JAVA_HOME이 Java 21 가리키는지 확인
  • 컴파일 오류: mvn clean compile -X 또는 gradle build --info 실행
  • Virtual Thread 이슈: Java 21+ 확인, 필요시 --enable-preview 사용
  • JPA Lazy Loading: @Transactional 또는 JOIN FETCH 쿼리 사용

성능 팁:

  • Virtual Threads 활성화: spring.threads.virtual.enabled=true
  • 빠른 시작을 위해 GraalVM Native Image 사용
  • HikariCP로 커넥션 풀링 설정

고급 문서

상세 참조 자료:


최종 업데이트: 2025-12-07 상태: Production Ready (v1.0.0)

スコア

総合スコア

50/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

0/10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です