plugins/languages/java/skills/spring/SKILL.md
Spring Boot 3.4+ 开发规范 — Virtual Threads 集成、Record `@ConfigurationProperties`、构造函数注入、`@Transactional` 边界、关闭 OSIV、Spring Security 6 lambda DSL、Micrometer + OpenTelemetry 可观测性、Spring Data JPA / Hibernate 6、Flyway 迁移、GraalVM Native Image。当用户开发 Spring REST API、微服务、Web 应用,或讨论 "Spring Boot"、"REST"、"JPA"、"Spring Security"、"@Transactional"、"Actuator"、"Native Image" 时加载。
npx skillsauth add lazygophers/ccplugin java-springInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
基线:Spring Boot 3.4+ (Java 21 LTS 最低,Java 25 LTS 推荐)。
Spring Boot 4.0 计划 2025-11 GA,Java 25 基线、Jakarta EE 11、Hibernate 7。若项目未升级 4.0,按 3.4 规范执行;升级时跑
spring-boot-properties-migrator。
@Autowired 字段注入@Transactional 标在 Service 层;读操作显式 readOnly = truespring.jpa.open-in-view: falseddl-auto: update;用 Flyway/Liquibase@ConfigurationPropertiesspring.threads.virtual.enabled: trueantMatchers@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@ConfigurationProperties(prefix = "app")
public record AppConfig(
String name,
int maxConnections,
Duration timeout,
SecurityConfig security
) {
public record SecurityConfig(String jwtSecret, Duration tokenExpiry) {}
}
@EnableConfigurationProperties(AppConfig.class)
@Configuration
class AppConfiguration {}
# application.yml
spring:
threads:
virtual:
enabled: true
mvc:
problemdetails:
enabled: true
jpa:
open-in-view: false
hibernate:
ddl-auto: validate
properties:
hibernate:
default_batch_fetch_size: 100
jdbc.batch_size: 50
order_inserts: true
order_updates: true
datasource:
hikari:
maximum-pool-size: 10
minimum-idle: 5
management:
endpoints.web.exposure.include: health,info,metrics,prometheus
observations.annotations.enabled: true
tracing.sampling.probability: 1.0
@RestController
@RequestMapping("/api/v1/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) { this.userService = userService; }
@GetMapping("/{id}")
public ResponseEntity<UserResponse> get(@PathVariable Long id) {
return userService.findById(id)
.map(ResponseEntity::ok)
.orElseThrow(() -> new AppRuntimeException(
new ResourceNotFoundException("User", id.toString())));
}
@PostMapping
public ResponseEntity<UserResponse> create(@Valid @RequestBody CreateUserRequest req) {
UserResponse u = userService.create(req);
return ResponseEntity.created(URI.create("/api/v1/users/" + u.id())).body(u);
}
@GetMapping
public Page<UserResponse> list(@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
return userService.findAll(PageRequest.of(page, size));
}
}
@Service
public class UserService {
private static final Logger log = LoggerFactory.getLogger(UserService.class);
private final UserRepository repo;
public UserService(UserRepository repo) { this.repo = repo; }
@Transactional
public UserResponse create(CreateUserRequest req) {
if (repo.existsByEmail(req.email())) {
throw new AppRuntimeException(new DuplicateResourceException("email", req.email()));
}
User saved = repo.save(new User(req.email(), req.name()));
log.info("User created: id={}", saved.getId());
return UserResponse.from(saved);
}
@Transactional(readOnly = true)
public Optional<UserResponse> findById(Long id) {
return repo.findById(id).map(UserResponse::from);
}
@Transactional(readOnly = true)
public Page<UserResponse> findAll(Pageable p) {
return repo.findAll(p).map(UserResponse::from);
}
}
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
boolean existsByEmail(String email);
@Query("SELECT u FROM User u JOIN FETCH u.orders WHERE u.id IN :ids")
List<User> findAllWithOrders(@Param("ids") List<Long> ids);
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/auth/**", "/actuator/health").permitAll()
.anyRequest().authenticated())
.oauth2ResourceServer(o -> o.jwt(Customizer.withDefaults()))
.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.build();
}
}
@Service
public class UserService {
private final Counter usersCreated;
public UserService(MeterRegistry registry) {
this.usersCreated = Counter.builder("users.created")
.description("Users created").register(registry);
}
@Observed(name = "user.create", contextualName = "create-user")
@Transactional
public UserResponse create(CreateUserRequest req) {
// ...
usersCreated.increment();
return UserResponse.from(saved);
}
}
依赖:spring-boot-starter-actuator、micrometer-registry-prometheus、micrometer-tracing-bridge-otel、opentelemetry-exporter-otlp。
-- V1__create_users_table.sql
CREATE TABLE users (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
name VARCHAR(100) NOT NULL,
active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
updated_at TIMESTAMP NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);
plugins {
id 'org.springframework.boot' version '3.4.0'
id 'io.spring.dependency-management' version '1.1.6'
id 'org.graalvm.buildtools.native' version '0.10.3'
}
./gradlew nativeCompile
./build/native/nativeCompile/my-app
| AI 易犯解释 | 实际应核验 |
|---------|---------|
| "@Autowired 字段注入快" | 是否构造函数注入? |
| "OSIV 默认开" | 是否 open-in-view: false? |
| "ddl-auto=update 方便" | 生产是否 Flyway? |
| "Spring Boot 2.x 还能用" | 是否 3.4+ (或 4.0)? |
| "antMatchers 改不动" | 是否升级 requestMatchers? |
| "不需要 tracing" | 是否接 Micrometer + OTel? |
| "JPA 默认就行" | 是否配置 batch_size 防 N+1? |
spring.threads.virtual.enabled=true@Autowired 字段)@Transactional 在 Service;只读用 readOnly=truespring.jpa.open-in-view=false@ConfigurationProperties + Recordbatch_size + default_batch_fetch_sizetools
UI/UX 与布局设计——做界面布局/结构/导航/组件/交互的设计决策。触发:做UI/UX/布局/排版/导航/组件/交互/栅格/响应式/图表选型/字体配对。按媒介路由 HTML/Web、原生 App(iOS/Android/桌面)、CLI、TUI。需后端动态系统不适用;配色/主题/色板走姊妹 skill design-color。
tools
主题与配色设计——做颜色搭配/调色板/主题/品牌色阶/暗模式的设计决策。触发:选配色/调色/主题/色板/品牌色/暗模式/对比度/色盲/UI风格。按媒介路由 HTML/Web(CSS变量)、原生App(平台token)、CLI(ANSI)、TUI(真彩/256/16降级)。保证可访问性(对比度/色盲安全)。需后端动态系统不适用;UI/UX 布局/组件/交互走姊妹 skill design-uiux。
tools
跨任意组件(plugin/skill/agent/command)的验证驱动优化循环纪律 skill。当用户要优化某个已有组件却无明确方向、或要防止改了反而更差(自评乐观偏差 / 多维同改归因失效 / 为凑分加废话膨胀)、或要把一套通用「评分→单变量改→改后验证严格更好才留否则回滚→触顶停」的纪律套到任意组件上时使用。管优化过程本身的纪律(validation gate / ratchet / 独立验证 / 触顶停),不评单组件深度(交 skill-dev),不查插件接线(交 plugin-dev)。仅手动 /optimize-any 触发。
data-ai
两层规则记忆 (基于 .skein/spec)。planning 时 recall 召回相关规则、task finish 后 sediment 沉淀学习 + prune 自动精简过期/重复/断链规则。core 常驻硬规 + recall 按需召回, 经判定门自动写盘 (不逐次问用户)。产出 .skein/spec 下 core/recall 规则文件 + index。另支持空仓 bootstrap 播种规则基线、记忆大面积失效 (大重构/换栈) 时 reconstruct 可逆归档后按项目类型分型重建、maintain 手动体检 (超预算/stale/断链/重复/废弃, --apply 自动修复)、auto-fix (Stop hook 写 .pending-fix 标记 → main 派 skein-specer bg 跑 maintain --apply 全自动修, 断链只报告)。