debug:spring-boot について
debug:spring-bootは、Spring Bootアプリケーションの問題を調べる開発者向けのトラブルシューティングガイドです。よくある障害、診断ツール、再現から修正・検証までの手順を扱います。
主な機能
- 01Beanと起動エラーの診断
- 02JPA、セキュリティ、設定の問題を解説
- 03ActuatorとJVM診断ツールの活用
- 044段階のデバッグ手順
- 05Maven、Gradle、Docker、Kubernetesのコマンド
活用シーン
- 01アプリケーションコンテキストの起動失敗を調査
- 02データベースやトランザクションの問題を追跡
- 03デプロイ済みSpring Bootサービスをデバッグ
- 04テストで問題を再現し修正を検証
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ snakeo/ claude-debug-and-refactor-skills-plugin --skill debug:spring-bootインストール後、Claude Code で/debug:spring-bootを入力して読み込まれたか確認します。
詳細
Spring Boot デバッグガイド
あなたは Spring Boot のデバッグに精通しています。問題を効率的に診断して解決するため、この体系的な手順に従ってください。
よくあるエラーパターン
1. NoSuchBeanDefinitionException
症状:
- 「フィールド xyz で必要な型 'X' の Bean が見つかりませんでした」
- 「型 'X' の適格な Bean がありません」
デバッグ手順:
- クラスに
@Component、@Service、@Repository、または@Controllerアノテーションが付いていることを確認します - クラスが
@ComponentScanによるスキャン対象のパッケージ内にあることを確認します(@SpringBootApplicationクラスのパッケージ内、またはその配下である必要があります) @Beanメソッドを持つ@Configurationクラスが読み込まれていることを確認します- Bean が除外される原因となる条件付きアノテーション(
@ConditionalOnProperty、@Profile)がないか確認します @Qualifierの修飾子名に誤字がないか確認します
簡単な解決策:
// Ensure main class is at root package
@SpringBootApplication
public class Application { ... }
// Explicit component scan if needed
@ComponentScan(basePackages = {"com.example.main", "com.example.other"})
// Check bean registration
@Autowired
private ApplicationContext context;
Arrays.stream(context.getBeanDefinitionNames()).forEach(System.out::println);
2. アプリケーションの起動失敗
症状:
- 「Web サーバーを起動できませんでした。ポート 8080 はすでに使用されています」
- 「アプリケーションの実行に失敗しました」
- コンテキストの初期化エラー
デバッグ手順:
- ポートの競合を確認します:
lsof -i :8080またはnetstat -an | grep 8080 - スタックトレース全体を確認し、根本原因を特定します(Spring のバナーより上までスクロールします)
- JPA を使用している場合は、データベースへの接続を確認します
- 必要な環境変数がすべて設定されていることを確認します
- pom.xml または build.gradle に依存関係の不足がないか確認します
簡単な解決策:
# Change port if in use
server.port=8081
# Enable debug startup logging
debug=true
logging.level.org.springframework=DEBUG
# Fail fast on missing properties
spring.main.allow-bean-definition-overriding=false
3. 循環依存
症状:
- 「アプリケーションコンテキスト内の一部の Bean の依存関係が循環しています」
- 「要求された Bean は現在作成中です」
デバッグ手順:
- エラーメッセージの依存関係の連鎖を確認します(A -> B -> C -> A)
- どの依存関係を解消できるか特定します
- 設計のリファクタリングが必要か検討します
簡単な解決策:
// Option 1: Use @Lazy on one dependency
@Autowired
@Lazy
private ServiceB serviceB;
// Option 2: Use setter injection
private ServiceB serviceB;
@Autowired
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
// Option 3: Refactor to event-based communication
@EventListener
public void handleEvent(CustomEvent event) { ... }
4. JPA/Hibernate の問題
症状:
- 「実際のトランザクションが利用可能な EntityManager がありません」
- LazyInitializationException
- 「テーブルが存在しません」/スキーマ検証エラー
- N+1 クエリの問題
デバッグ手順:
- SQL ロギングを有効にして、実際のクエリを確認します
@Transactionalの配置を確認します(public メソッドに付与する必要があります)- エンティティのリレーションシップとカスケードタイプを確認します
- データベースのスキーマがエンティティ定義と一致していることを確認します
簡単な解決策:
# Enable SQL debugging
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
# Schema handling
spring.jpa.hibernate.ddl-auto=validate # Recommended for debugging
spring.jpa.hibernate.ddl-auto=update # Auto-update schema (dev only)
// Fix LazyInitializationException
@Transactional(readOnly = true)
public Entity getWithChildren(Long id) {
Entity e = repository.findById(id).orElseThrow();
e.getChildren().size(); // Force initialization
return e;
}
// Or use EntityGraph
@EntityGraph(attributePaths = {"children", "children.grandchildren"})
Optional<Entity> findById(Long id);
5. セキュリティ設定の問題
症状:
- すべてのエンドポイントで 403 Forbidden が発生する
- 認証が機能しない
- CORS エラー
- CSRF トークンの問題
デバッグ手順:
- セキュリティのデバッグロギングを有効にします
- フィルターチェーンの順序を確認します
- 認証プロバイダーの設定を確認します
- SecurityFilterChain Bean の設定を確認します
簡単な解決策:
# Enable security debugging
logging.level.org.springframework.security=DEBUG
logging.level.org.springframework.security.web.FilterChainProxy=DEBUG
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/actuator/health").permitAll()
.anyRequest().authenticated()
)
.csrf(csrf -> csrf.disable()) // Only for APIs with token auth
.cors(Customizer.withDefaults());
return http.build();
}
}
6. プロパティのバインド失敗
症状:
- 「'x.y.z' のプロパティのバインドに失敗しました」
- 「プレースホルダーを解決できませんでした」
- 設定値が読み込まれない
デバッグ手順:
- プロパティファイルの場所を確認します(src/main/resources)
- プロパティ名が完全に一致していることを確認します(大文字と小文字を区別し、ハイフンとキャメルケースにも注意します)
- 有効なプロファイルを確認します(
spring.profiles.active) @ConfigurationPropertiesのプレフィックスが一致していることを確認します
簡単な解決策:
// Debug property sources
@Autowired
private Environment env;
@PostConstruct
public void debugProperties() {
System.out.println("Active profiles: " + Arrays.toString(env.getActiveProfiles()));
System.out.println("Property value: " + env.getProperty("my.property"));
}
// Ensure @ConfigurationProperties is scanned
@EnableConfigurationProperties(MyProperties.class)
@SpringBootApplication
public class Application { ... }
# Add to see property resolution
logging.level.org.springframework.boot.context.properties=DEBUG
デバッグツール
Spring Boot Actuator
実行時の診断に不可欠です:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
# Expose all actuator endpoints (dev only)
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
主なエンドポイント:
/actuator/health- アプリケーションのヘルスステータス/actuator/beans- 登録済みのすべての Bean/actuator/env- 環境プロパティ/actuator/mappings- リクエストマッピング/actuator/configprops- 設定プロパティ/actuator/conditions- 自動設定レポート
リモート JVM デバッグ
# Maven
mvn spring-boot:run -Dspring-boot.run.jvmArguments="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"
# Gradle
./gradlew bootRun --debug-jvm
# Java directly
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar app.jar
# Docker Compose
environment:
- JAVA_TOOL_OPTIONS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
ports:
- "5005:5005"
Logback/Log4j2 の設定
src/main/resources/logback-spring.xml を作成します:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.web" level="DEBUG"/>
<logger name="org.hibernate.SQL" level="DEBUG"/>
<logger name="com.yourapp" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
Spring Boot DevTools
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
機能:
- コード変更時の自動再起動
- LiveReload のブラウザー連携
- 開発環境でのプロパティバインドの緩和
- H2 コンソールの自動設定
IntelliJ IDEA Spring デバッガー(2025.2+)
- 読み込み済みの有効な Bean とそのメタデータを表示します
- .properties/.yaml ファイル内に実際のプロパティ値をインライン表示します
- Bean のスコープ、プロファイル、コンテキストを調べます
- データベース接続を表示します
- Bean 定義に移動します
4 つのフェーズ(Spring Boot 固有)
フェーズ 1:情報を収集する
# Check application logs
tail -f logs/spring.log
# Check JVM status
jps -lv
jstat -gc <pid>
jstack <pid>
# Check actuator endpoints
curl localhost:8080/actuator/health
curl localhost:8080/actuator/env
curl localhost:8080/actuator/beans
フェーズ 2:再現して切り分ける
// Create minimal test case
@SpringBootTest(classes = {TestConfig.class, ProblemBean.class})
class IsolatedTest {
@Autowired
private ProblemBean bean;
@Test
void reproduceIssue() {
// Minimal steps to reproduce
}
}
// Use test slices for faster isolation
@WebMvcTest(ProblemController.class)
@DataJpaTest
@JsonTest
フェーズ 3:根本原因を診断する
// Add diagnostic logging
@Aspect
@Component
public class DiagnosticAspect {
private static final Logger log = LoggerFactory.getLogger(DiagnosticAspect.class);
@Around("execution(* com.yourapp.service.*.*(..))")
public Object logMethodExecution(ProceedingJoinPoint jp) throws Throwable {
log.debug("Entering: {}", jp.getSignature());
try {
Object result = jp.proceed();
log.debug("Exiting: {} with result: {}", jp.getSignature(), result);
return result;
} catch (Exception e) {
log.error("Exception in {}: {}", jp.getSignature(), e.getMessage());
throw e;
}
}
}
フェーズ 4:修正して検証する
# Run targeted tests
./mvnw test -Dtest=ProblemTest
# Run full test suite
./mvnw verify
# Check for regressions
./mvnw test -Dtest=*IntegrationTest
コマンド早見表
Maven
# Run with debug logging
./mvnw spring-boot:run -Dspring-boot.run.arguments="--debug"
# Run with specific profile
./mvnw spring-boot:run -Dspring-boot.run.profiles=dev
# Skip tests and run
./mvnw spring-boot:run -DskipTests
# Generate dependency tree
./mvnw dependency:tree
# Check for dependency conflicts
./mvnw dependency:analyze
# Force update dependencies
./mvnw clean install -U
Gradle
# Run with debug logging
./gradlew bootRun --args='--debug'
# Run with specific profile
./gradlew bootRun --args='--spring.profiles.active=dev'
# Show dependencies
./gradlew dependencies
# Refresh dependencies
./gradlew build --refresh-dependencies
Docker
# Check container logs
docker logs <container_name> -f
# Shell into container
docker exec -it <container_name> /bin/sh
# Check container health
docker inspect --format='{{.State.Health.Status}}' <container_name>
# View container environment
docker exec <container_name> env | grep SPRING
Kubernetes
# Get pod logs
kubectl logs <pod-name> -f
# Get previous container logs (after crash)
kubectl logs <pod-name> --previous
# Describe pod for events
kubectl describe pod <pod-name>
# Port forward for debugging
kubectl port-forward <pod-name> 5005:5005
# Shell into pod
kubectl exec -it <pod-name> -- /bin/sh
データベースのデバッグ
# Connect to PostgreSQL
psql -h localhost -U user -d database
# Show running queries
SELECT * FROM pg_stat_activity WHERE state = 'active';
# Connect to MySQL
mysql -h localhost -u user -p database
# Show process list
SHOW PROCESSLIST;
JVM の診断
# List Java processes
jps -lv
# Thread dump
jstack <pid> > thread_dump.txt
# Heap dump
jmap -dump:format=b,file=heap.hprof <pid>
# GC stats
jstat -gcutil <pid> 1000
# JVM flags
jinfo -flags <pid>
マイクロサービスのデバッグ
分散トレーシング
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
# Zipkin configuration
management.tracing.sampling.probability=1.0
management.zipkin.tracing.endpoint=http://zipkin:9411/api/v2/spans
相関 ID
@Component
public class CorrelationIdFilter extends OncePerRequestFilter {
private static final String CORRELATION_ID = "X-Correlation-ID";
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain) {
String correlationId = request.getHeader(CORRELATION_ID);
if (correlationId == null) {
correlationId = UUID.randomUUID().toString();
}
MDC.put("correlationId", correlationId);
response.setHeader(CORRELATION_ID, correlationId);
try {
chain.doFilter(request, response);
} finally {
MDC.remove("correlationId");
}
}
}
よくある落とし穴
- private メソッドに対する @Transactional - 動作しません。public にする必要があります
- 同じクラス内から @Transactional メソッドを呼び出す - プロキシを迂回するため、トランザクションが適用されません
- カスタム実装に @Repository がない - 例外変換が適用されません
- コンストラクター内の @Value - フィールドへの注入がまだ行われていません。@PostConstruct を使用してください
- @Autowired を付けた static フィールド - 注入されません
- basePackages を指定しない @ComponentScan - 現在のパッケージとその配下のみをスキャンします
- 誤った場所にある application.properties - src/main/resources のルートに置く必要があります
- プロファイル固有の設定が読み込まれない - spring.profiles.active が設定されているか確認してください
さらに読む
コメント
Markdown 対応