Atlas Mapper 教程系列 (6/10):Spring Boot 集成与自动配置

🎯 学习目标

通过本篇教程,你将学会:

  • 理解 Atlas Mapper 的 Spring Boot 自动配置机制
  • 掌握 Spring Boot Starter 的使用方法
  • 学会自定义配置属性和条件装配
  • 理解依赖注入和 Bean 生命周期管理

📋 概念讲解:Spring Boot 集成架构

自动配置架构图

graph TB subgraph SpringApp["Spring Boot 应用"] A1[Application.java] --> A2["@SpringBootApplication"] A2 --> A3[ComponentScan] A3 --> A4[自动扫描 Mapper] end subgraph Starter["Atlas Mapper Starter"] B1[atlas-mapper-spring-boot-starter] --> B2[spring.factories] B2 --> B3[AtlasMapperAutoConfiguration] B3 --> B4[条件装配] B4 --> B5[Bean 注册] end subgraph Config["配置属性"] C1[application.yml] --> C2["atlas.mapper.*"] C2 --> C3[AtlasMapperProperties] C3 --> C4[配置绑定] end subgraph MapperBean["Mapper Bean"] D1["@Mapper"] --> D2["componentModel = \"spring\""] D2 --> D3[Spring Bean] D3 --> D4[依赖注入] end A3 --> D1 B5 --> D3 C4 --> B3 style A1 fill:#e8f5e8 style B1 fill:#e3f2fd style C1 fill:#fff3e0 style D1 fill:#ffecb3

Bean 生命周期管理

sequenceDiagram participant App as Spring Boot App participant AC as AutoConfiguration participant BF as BeanFactory participant Mapper as Mapper Bean participant Service as Business Service App->>AC: 启动应用 AC->>AC: 检查条件装配 AC->>BF: 注册 Mapper Bean BF->>Mapper: 创建 Mapper 实例 Mapper->>BF: 注册到容器 Service->>BF: 请求注入 Mapper BF->>Service: 注入 Mapper Bean Service->>Mapper: 调用映射方法 Mapper->>Service: 返回映射结果

🔧 实现步骤:Spring Boot 集成详解

步骤 1:添加 Spring Boot Starter 依赖

在你的 Spring Boot 项目中添加 Atlas Mapper Starter:

xml 复制代码
<!-- pom.xml -->
<dependencies>
    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- Atlas Mapper Spring Boot Starter -->
    <dependency>
        <groupId>io.github.nemoob</groupId>
        <artifactId>atlas-mapper-spring-boot-starter</artifactId>
        <version>1.0.0</version>
    </dependency>
    
    <!-- 其他依赖... -->
</dependencies>

步骤 2:配置属性详解

application.yml 中配置 Atlas Mapper:

yaml 复制代码
# application.yml
atlas:
  mapper:
    # 🔥 基础配置
    enabled: true                           # 是否启用 Atlas Mapper
    component-model: spring                 # 组件模型:spring, default, cdi
    
    # 🔥 映射策略配置
    unmapped-target-policy: IGNORE          # 未映射目标字段策略:IGNORE, WARN, ERROR
    unmapped-source-policy: WARN            # 未映射源字段策略:IGNORE, WARN, ERROR
    null-value-mapping-strategy: RETURN_NULL # 空值映射策略:RETURN_NULL, RETURN_DEFAULT
    null-value-check-strategy: ON_IMPLICIT_CONVERSION # 空值检查策略
    
    # 🔥 代码生成配置
    suppress-generator-timestamp: true       # 是否抑制生成器时间戳
    suppress-generator-version-comment: false # 是否抑制版本注释
    
    # 🔥 性能优化配置
    collection-mapping-strategy: ACCESSOR_ONLY # 集合映射策略
    builder-pattern: true                    # 是否使用建造者模式
    
    # 🔥 调试配置
    verbose: false                          # 是否启用详细日志
    show-generated-code: false              # 是否显示生成的代码
    
    # 🔥 自定义配置
    default-component-model: spring         # 默认组件模型
    default-injection-strategy: FIELD       # 默认注入策略:FIELD, CONSTRUCTOR
    
    # 🔥 包扫描配置
    base-packages:                          # 基础包扫描路径
      - "com.example.mapper"
      - "com.example.converter"
    
    # 🔥 类型转换器配置
    type-converters:
      date-format: "yyyy-MM-dd HH:mm:ss"    # 默认日期格式
      number-format: "#,##0.00"             # 默认数字格式
      timezone: "Asia/Shanghai"             # 时区设置

# Spring Boot 相关配置
spring:
  application:
    name: atlas-mapper-demo
  
  # 数据源配置(如果需要)
  datasource:
    url: jdbc:mysql://localhost:3306/demo
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
  
  # JPA 配置(如果使用)
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate:
        format_sql: true

# 日志配置
logging:
  level:
    io.github.nemoob.atlas.mapper: DEBUG    # Atlas Mapper 日志级别
    org.springframework: INFO
    com.example: DEBUG
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

步骤 3:自动配置类详解

查看 Atlas Mapper 的自动配置实现:

java 复制代码
/**
 * Atlas Mapper 自动配置类
 */
@Configuration
@ConditionalOnClass({Mapper.class, AtlasMapperProcessor.class})  // 🔥 条件装配:类存在
@ConditionalOnProperty(                                          // 🔥 条件装配:属性配置
    prefix = "atlas.mapper", 
    name = "enabled", 
    havingValue = "true", 
    matchIfMissing = true
)
@EnableConfigurationProperties(AtlasMapperProperties.class)      // 🔥 启用配置属性
@AutoConfigureAfter({DataSourceAutoConfiguration.class})        // 🔥 配置顺序
public class AtlasMapperAutoConfiguration {
    
    private final AtlasMapperProperties properties;
    
    public AtlasMapperAutoConfiguration(AtlasMapperProperties properties) {
        this.properties = properties;
    }
    
    /**
     * 🔥 配置 Atlas Mapper 处理器
     */
    @Bean
    @ConditionalOnMissingBean(AtlasMapperProcessor.class)
    public AtlasMapperProcessor atlasMapperProcessor() {
        AtlasMapperProcessor processor = new AtlasMapperProcessor();
        
        // 应用配置属性
        processor.setUnmappedTargetPolicy(properties.getUnmappedTargetPolicy());
        processor.setNullValueMappingStrategy(properties.getNullValueMappingStrategy());
        processor.setVerbose(properties.isVerbose());
        processor.setSuppressGeneratorTimestamp(properties.isSuppressGeneratorTimestamp());
        
        return processor;
    }
    
    /**
     * 🔥 配置类型转换器注册表
     */
    @Bean
    @ConditionalOnMissingBean(TypeConverterRegistry.class)
    public TypeConverterRegistry typeConverterRegistry() {
        TypeConverterRegistry registry = new TypeConverterRegistry();
        
        // 注册默认类型转换器
        registry.registerConverter(new StringToDateConverter(properties.getTypeConverters().getDateFormat()));
        registry.registerConverter(new NumberToStringConverter(properties.getTypeConverters().getNumberFormat()));
        registry.registerConverter(new BooleanToStringConverter());
        
        return registry;
    }
    
    /**
     * 🔥 配置 Mapper 扫描器
     */
    @Bean
    @ConditionalOnMissingBean(MapperScanner.class)
    public MapperScanner mapperScanner() {
        MapperScanner scanner = new MapperScanner();
        scanner.setBasePackages(properties.getBasePackages());
        scanner.setComponentModel(properties.getComponentModel());
        return scanner;
    }
    
    /**
     * 🔥 配置性能监控(可选)
     */
    @Bean
    @ConditionalOnProperty(prefix = "atlas.mapper", name = "performance-monitoring", havingValue = "true")
    @ConditionalOnMissingBean(MapperPerformanceMonitor.class)
    public MapperPerformanceMonitor performanceMonitor() {
        return new MapperPerformanceMonitor();
    }
    
    /**
     * 🔥 配置缓存管理器(可选)
     */
    @Bean
    @ConditionalOnProperty(prefix = "atlas.mapper", name = "caching.enabled", havingValue = "true")
    @ConditionalOnMissingBean(MapperCacheManager.class)
    public MapperCacheManager cacheManager() {
        MapperCacheManager cacheManager = new MapperCacheManager();
        cacheManager.setMaxSize(properties.getCaching().getMaxSize());
        cacheManager.setExpireAfterWrite(properties.getCaching().getExpireAfterWrite());
        return cacheManager;
    }
    
    /**
     * 🔥 配置健康检查端点
     */
    @Bean
    @ConditionalOnClass(HealthIndicator.class)
    @ConditionalOnProperty(prefix = "atlas.mapper", name = "health-check", havingValue = "true")
    public AtlasMapperHealthIndicator atlasMapperHealthIndicator() {
        return new AtlasMapperHealthIndicator();
    }
}

步骤 4:配置属性类

java 复制代码
/**
 * Atlas Mapper 配置属性类
 */
@ConfigurationProperties(prefix = "atlas.mapper")
@Data
public class AtlasMapperProperties {
    
    /**
     * 是否启用 Atlas Mapper
     */
    private boolean enabled = true;
    
    /**
     * 组件模型
     */
    private String componentModel = "spring";
    
    /**
     * 未映射目标字段策略
     */
    private ReportingPolicy unmappedTargetPolicy = ReportingPolicy.IGNORE;
    
    /**
     * 未映射源字段策略
     */
    private ReportingPolicy unmappedSourcePolicy = ReportingPolicy.WARN;
    
    /**
     * 空值映射策略
     */
    private NullValueMappingStrategy nullValueMappingStrategy = NullValueMappingStrategy.RETURN_NULL;
    
    /**
     * 空值检查策略
     */
    private NullValueCheckStrategy nullValueCheckStrategy = NullValueCheckStrategy.ON_IMPLICIT_CONVERSION;
    
    /**
     * 是否抑制生成器时间戳
     */
    private boolean suppressGeneratorTimestamp = true;
    
    /**
     * 是否抑制版本注释
     */
    private boolean suppressGeneratorVersionComment = false;
    
    /**
     * 集合映射策略
     */
    private CollectionMappingStrategy collectionMappingStrategy = CollectionMappingStrategy.ACCESSOR_ONLY;
    
    /**
     * 是否使用建造者模式
     */
    private boolean builderPattern = false;
    
    /**
     * 是否启用详细日志
     */
    private boolean verbose = false;
    
    /**
     * 是否显示生成的代码
     */
    private boolean showGeneratedCode = false;
    
    /**
     * 默认组件模型
     */
    private String defaultComponentModel = "spring";
    
    /**
     * 默认注入策略
     */
    private InjectionStrategy defaultInjectionStrategy = InjectionStrategy.FIELD;
    
    /**
     * 基础包扫描路径
     */
    private List<String> basePackages = new ArrayList<>();
    
    /**
     * 类型转换器配置
     */
    private TypeConverters typeConverters = new TypeConverters();
    
    /**
     * 缓存配置
     */
    private Caching caching = new Caching();
    
    /**
     * 性能监控配置
     */
    private boolean performanceMonitoring = false;
    
    /**
     * 健康检查配置
     */
    private boolean healthCheck = false;
    
    /**
     * 类型转换器配置类
     */
    @Data
    public static class TypeConverters {
        private String dateFormat = "yyyy-MM-dd HH:mm:ss";
        private String numberFormat = "#,##0.00";
        private String timezone = "Asia/Shanghai";
        private boolean enableCustomConverters = true;
    }
    
    /**
     * 缓存配置类
     */
    @Data
    public static class Caching {
        private boolean enabled = false;
        private long maxSize = 1000L;
        private Duration expireAfterWrite = Duration.ofMinutes(30);
        private Duration expireAfterAccess = Duration.ofMinutes(10);
    }
}

步骤 5:在 Spring Boot 应用中使用

创建 Spring Boot 主类

java 复制代码
/**
 * Spring Boot 应用主类
 */
@SpringBootApplication
@EnableAtlasMapper  // 🔥 启用 Atlas Mapper(可选,自动配置会处理)
public class AtlasMapperDemoApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(AtlasMapperDemoApplication.class, args);
    }
    
    /**
     * 🔥 自定义配置 Bean(可选)
     */
    @Bean
    public AtlasMapperConfigurer atlasMapperConfigurer() {
        return new AtlasMapperConfigurer() {
            @Override
            public void configure(AtlasMapperConfiguration configuration) {
                // 自定义配置
                configuration.setDefaultDateFormat("yyyy/MM/dd");
                configuration.setDefaultNumberFormat("¥#,##0.00");
            }
        };
    }
}

创建 Mapper 接口

java 复制代码
/**
 * 用户映射器 - 自动注册为 Spring Bean
 */
@Mapper(componentModel = "spring")  // 🔥 指定为 Spring 组件
public interface UserMapper {
    
    UserDto toDto(User user);
    User toEntity(UserDto dto);
    List<UserDto> toDtoList(List<User> users);
    
    /**
     * 🔥 使用配置属性中的默认格式
     */
    @Mapping(target = "createdTime", source = "createdAt", dateFormat = "${atlas.mapper.type-converters.date-format}")
    UserDetailDto toDetailDto(User user);
}

在 Service 中注入使用

java 复制代码
/**
 * 用户服务类 - 注入 Mapper
 */
@Service
@Transactional
public class UserService {
    
    private final UserRepository userRepository;
    private final UserMapper userMapper;  // 🔥 自动注入 Mapper
    
    // 🔥 构造器注入(推荐)
    public UserService(UserRepository userRepository, UserMapper userMapper) {
        this.userRepository = userRepository;
        this.userMapper = userMapper;
    }
    
    /**
     * 获取用户列表
     */
    public List<UserDto> getAllUsers() {
        List<User> users = userRepository.findAll();
        return userMapper.toDtoList(users);  // 🔥 使用注入的 Mapper
    }
    
    /**
     * 根据 ID 获取用户
     */
    public UserDto getUserById(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("用户不存在: " + id));
        return userMapper.toDto(user);
    }
    
    /**
     * 创建用户
     */
    public UserDto createUser(UserDto userDto) {
        User user = userMapper.toEntity(userDto);  // 🔥 DTO -> Entity
        user.setCreatedAt(LocalDateTime.now());
        user.setUpdatedAt(LocalDateTime.now());
        
        User savedUser = userRepository.save(user);
        return userMapper.toDto(savedUser);        // 🔥 Entity -> DTO
    }
    
    /**
     * 更新用户
     */
    public UserDto updateUser(Long id, UserDto userDto) {
        User existingUser = userRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("用户不存在: " + id));
        
        // 🔥 部分更新:只更新非空字段
        updateUserFields(existingUser, userDto);
        existingUser.setUpdatedAt(LocalDateTime.now());
        
        User updatedUser = userRepository.save(existingUser);
        return userMapper.toDto(updatedUser);
    }
    
    /**
     * 批量转换
     */
    public List<UserDto> convertUsers(List<User> users) {
        return userMapper.toDtoList(users);
    }
    
    /**
     * 辅助方法:更新用户字段
     */
    private void updateUserFields(User target, UserDto source) {
        if (source.getName() != null) {
            target.setName(source.getName());
        }
        if (source.getEmail() != null) {
            target.setEmail(source.getEmail());
        }
        // 其他字段更新...
    }
}

创建 REST 控制器

java 复制代码
/**
 * 用户控制器
 */
@RestController
@RequestMapping("/api/users")
@Validated
public class UserController {
    
    private final UserService userService;
    
    public UserController(UserService userService) {
        this.userService = userService;
    }
    
    /**
     * 获取所有用户
     */
    @GetMapping
    public ResponseEntity<List<UserDto>> getAllUsers() {
        List<UserDto> users = userService.getAllUsers();
        return ResponseEntity.ok(users);
    }
    
    /**
     * 根据 ID 获取用户
     */
    @GetMapping("/{id}")
    public ResponseEntity<UserDto> getUserById(@PathVariable Long id) {
        UserDto user = userService.getUserById(id);
        return ResponseEntity.ok(user);
    }
    
    /**
     * 创建用户
     */
    @PostMapping
    public ResponseEntity<UserDto> createUser(@Valid @RequestBody UserDto userDto) {
        UserDto createdUser = userService.createUser(userDto);
        return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
    }
    
    /**
     * 更新用户
     */
    @PutMapping("/{id}")
    public ResponseEntity<UserDto> updateUser(
            @PathVariable Long id, 
            @Valid @RequestBody UserDto userDto) {
        UserDto updatedUser = userService.updateUser(id, userDto);
        return ResponseEntity.ok(updatedUser);
    }
    
    /**
     * 删除用户
     */
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

💻 示例代码:完整的 Spring Boot 集成示例

示例 1:多环境配置

yaml 复制代码
# application.yml - 基础配置
atlas:
  mapper:
    enabled: true
    component-model: spring
    base-packages:
      - "com.example.mapper"

---
# application-dev.yml - 开发环境
spring:
  config:
    activate:
      on-profile: dev

atlas:
  mapper:
    verbose: true                    # 开发环境启用详细日志
    show-generated-code: true        # 显示生成的代码
    performance-monitoring: true     # 启用性能监控
    
logging:
  level:
    io.github.nemoob.atlas.mapper: DEBUG

---
# application-prod.yml - 生产环境
spring:
  config:
    activate:
      on-profile: prod

atlas:
  mapper:
    verbose: false                   # 生产环境关闭详细日志
    show-generated-code: false
    performance-monitoring: true     # 保持性能监控
    caching:
      enabled: true                  # 启用缓存
      max-size: 10000
      expire-after-write: PT1H       # 1小时过期
    
logging:
  level:
    io.github.nemoob.atlas.mapper: WARN

示例 2:自定义配置器

java 复制代码
/**
 * 自定义 Atlas Mapper 配置器
 */
@Configuration
public class AtlasMapperCustomConfiguration {
    
    /**
     * 🔥 自定义类型转换器
     */
    @Bean
    public CustomTypeConverter customTypeConverter() {
        return new CustomTypeConverter();
    }
    
    /**
     * 🔥 自定义映射策略
     */
    @Bean
    public AtlasMapperConfigurer customMapperConfigurer() {
        return configuration -> {
            // 自定义默认配置
            configuration.setDefaultDateFormat("yyyy年MM月dd日");
            configuration.setDefaultNumberFormat("¥#,##0.00");
            configuration.setDefaultTimeZone(ZoneId.of("Asia/Shanghai"));
            
            // 注册自定义转换器
            configuration.addTypeConverter(new MoneyConverter());
            configuration.addTypeConverter(new PhoneNumberConverter());
            
            // 设置命名策略
            configuration.setFieldNamingStrategy(new CamelCaseNamingStrategy());
        };
    }
    
    /**
     * 🔥 自定义 Mapper 后处理器
     */
    @Bean
    public MapperPostProcessor mapperPostProcessor() {
        return new MapperPostProcessor() {
            @Override
            public void postProcessMapper(Object mapper, String mapperName) {
                log.info("Mapper 创建完成: {}", mapperName);
                
                // 可以在这里添加额外的初始化逻辑
                if (mapper instanceof BaseMapper) {
                    ((BaseMapper) mapper).initialize();
                }
            }
        };
    }
    
    /**
     * 🔥 条件化配置 - 仅在特定条件下生效
     */
    @Bean
    @ConditionalOnProperty(prefix = "atlas.mapper", name = "advanced-features", havingValue = "true")
    public AdvancedMapperFeatures advancedMapperFeatures() {
        return new AdvancedMapperFeatures();
    }
    
    /**
     * 🔥 Profile 特定配置
     */
    @Bean
    @Profile("development")
    public MapperDebugger mapperDebugger() {
        return new MapperDebugger();
    }
}

示例 3:健康检查和监控

java 复制代码
/**
 * Atlas Mapper 健康检查指示器
 */
@Component
@ConditionalOnProperty(prefix = "atlas.mapper", name = "health-check", havingValue = "true")
public class AtlasMapperHealthIndicator implements HealthIndicator {
    
    private final MapperRegistry mapperRegistry;
    private final MapperPerformanceMonitor performanceMonitor;
    
    public AtlasMapperHealthIndicator(MapperRegistry mapperRegistry, 
                                     MapperPerformanceMonitor performanceMonitor) {
        this.mapperRegistry = mapperRegistry;
        this.performanceMonitor = performanceMonitor;
    }
    
    @Override
    public Health health() {
        try {
            // 检查 Mapper 注册状态
            int registeredMappers = mapperRegistry.getRegisteredMapperCount();
            
            // 检查性能指标
            PerformanceMetrics metrics = performanceMonitor.getMetrics();
            
            // 构建健康状态
            Health.Builder builder = Health.up()
                    .withDetail("registeredMappers", registeredMappers)
                    .withDetail("totalMappings", metrics.getTotalMappings())
                    .withDetail("averageExecutionTime", metrics.getAverageExecutionTime())
                    .withDetail("errorRate", metrics.getErrorRate());
            
            // 检查错误率
            if (metrics.getErrorRate() > 0.1) {  // 错误率超过 10%
                builder.down().withDetail("reason", "High error rate: " + metrics.getErrorRate());
            }
            
            // 检查平均执行时间
            if (metrics.getAverageExecutionTime() > 1000) {  // 平均执行时间超过 1 秒
                builder.down().withDetail("reason", "High execution time: " + metrics.getAverageExecutionTime() + "ms");
            }
            
            return builder.build();
            
        } catch (Exception e) {
            return Health.down()
                    .withDetail("error", e.getMessage())
                    .build();
        }
    }
}

示例 4:性能监控和指标

java 复制代码
/**
 * Atlas Mapper 性能监控
 */
@Component
@ConditionalOnProperty(prefix = "atlas.mapper", name = "performance-monitoring", havingValue = "true")
public class AtlasMapperPerformanceMonitor {
    
    private final MeterRegistry meterRegistry;
    private final Timer.Sample sample;
    
    public AtlasMapperPerformanceMonitor(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        this.sample = Timer.start(meterRegistry);
    }
    
    /**
     * 记录映射执行时间
     */
    public void recordMappingTime(String mapperName, String methodName, long executionTime) {
        Timer.builder("atlas.mapper.execution.time")
                .tag("mapper", mapperName)
                .tag("method", methodName)
                .register(meterRegistry)
                .record(executionTime, TimeUnit.MILLISECONDS);
    }
    
    /**
     * 记录映射错误
     */
    public void recordMappingError(String mapperName, String methodName, Exception error) {
        Counter.builder("atlas.mapper.errors")
                .tag("mapper", mapperName)
                .tag("method", methodName)
                .tag("error", error.getClass().getSimpleName())
                .register(meterRegistry)
                .increment();
    }
    
    /**
     * 记录映射成功
     */
    public void recordMappingSuccess(String mapperName, String methodName) {
        Counter.builder("atlas.mapper.success")
                .tag("mapper", mapperName)
                .tag("method", methodName)
                .register(meterRegistry)
                .increment();
    }
    
    /**
     * 获取性能指标
     */
    public PerformanceMetrics getMetrics() {
        // 实现指标收集逻辑
        return new PerformanceMetrics();
    }
}

/**
 * 性能指标数据类
 */
@Data
public class PerformanceMetrics {
    private long totalMappings;
    private double averageExecutionTime;
    private double errorRate;
    private Map<String, Long> mapperUsageCount;
    private Map<String, Double> mapperAverageTime;
}

🎬 效果演示:Spring Boot 集成测试

创建集成测试

java 复制代码
/**
 * Spring Boot 集成测试
 */
@SpringBootTest
@TestPropertySource(properties = {
    "atlas.mapper.enabled=true",
    "atlas.mapper.verbose=true",
    "atlas.mapper.performance-monitoring=true"
})
class AtlasMapperIntegrationTest {
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private UserMapper userMapper;
    
    @Autowired
    private AtlasMapperProperties properties;
    
    @Test
    void testMapperAutoConfiguration() {
        // 验证 Mapper 自动注入
        assertThat(userMapper).isNotNull();
        assertThat(userService).isNotNull();
    }
    
    @Test
    void testConfigurationProperties() {
        // 验证配置属性
        assertThat(properties.isEnabled()).isTrue();
        assertThat(properties.isVerbose()).isTrue();
        assertThat(properties.getComponentModel()).isEqualTo("spring");
    }
    
    @Test
    void testMappingFunctionality() {
        // 创建测试数据
        User user = new User();
        user.setId(1L);
        user.setName("张三");
        user.setEmail("zhangsan@example.com");
        user.setCreatedAt(LocalDateTime.now());
        
        // 测试映射功能
        UserDto dto = userMapper.toDto(user);
        
        assertThat(dto).isNotNull();
        assertThat(dto.getId()).isEqualTo(user.getId());
        assertThat(dto.getName()).isEqualTo(user.getName());
        assertThat(dto.getEmail()).isEqualTo(user.getEmail());
    }
    
    @Test
    void testServiceIntegration() {
        // 测试服务层集成
        UserDto userDto = new UserDto();
        userDto.setName("李四");
        userDto.setEmail("lisi@example.com");
        
        // 这里需要 Mock Repository 或使用 @DataJpaTest
        // UserDto result = userService.createUser(userDto);
        // assertThat(result).isNotNull();
    }
}

启动应用测试

bash 复制代码
# 启动应用
mvn spring-boot:run

# 或者使用不同的 Profile
mvn spring-boot:run -Dspring-boot.run.profiles=dev

# 测试 API 端点
curl -X GET http://localhost:8080/api/users
curl -X POST http://localhost:8080/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"张三","email":"zhangsan@example.com"}'

# 查看健康检查
curl http://localhost:8080/actuator/health/atlasMapper

# 查看性能指标
curl http://localhost:8080/actuator/metrics/atlas.mapper.execution.time

❓ 常见问题

Q1: Mapper 没有被自动注入怎么办?

A: 检查以下几个方面:

java 复制代码
// 1. 确保 @Mapper 注解配置正确
@Mapper(componentModel = "spring")  // 必须指定 componentModel
public interface UserMapper {
    // ...
}

// 2. 确保包扫描路径正确
@SpringBootApplication
@ComponentScan(basePackages = {"com.example"})  // 包含 Mapper 所在包
public class Application {
    // ...
}

// 3. 检查配置是否启用
atlas:
  mapper:
    enabled: true  # 确保启用

// 4. 查看生成的实现类
// target/generated-sources/annotations/ 目录下应该有生成的实现类

Q2: 如何自定义 Mapper 的 Bean 名称?

A : 使用 @Component 注解指定名称:

java 复制代码
@Mapper(componentModel = "spring")
@Component("customUserMapper")  // 自定义 Bean 名称
public interface UserMapper {
    // ...
}

// 注入时使用自定义名称
@Autowired
@Qualifier("customUserMapper")
private UserMapper userMapper;

Q3: 如何在不同环境使用不同的映射策略?

A: 使用 Profile 特定配置:

yaml 复制代码
# application-dev.yml
atlas:
  mapper:
    unmapped-target-policy: WARN    # 开发环境警告
    verbose: true

# application-prod.yml  
atlas:
  mapper:
    unmapped-target-policy: IGNORE  # 生产环境忽略
    verbose: false

Q4: 如何监控 Mapper 的性能?

A: 启用性能监控和指标收集:

yaml 复制代码
# 配置
atlas:
  mapper:
    performance-monitoring: true

management:
  endpoints:
    web:
      exposure:
        include: health,metrics,info
  endpoint:
    health:
      show-details: always
java 复制代码
// 自定义性能监控
@Component
public class MapperPerformanceAspect {
    
    @Around("@within(io.github.nemoob.atlas.mapper.Mapper)")
    public Object monitorPerformance(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        try {
            Object result = joinPoint.proceed();
            long executionTime = System.currentTimeMillis() - startTime;
            log.info("Mapper method {} executed in {} ms", 
                    joinPoint.getSignature().getName(), executionTime);
            return result;
        } catch (Exception e) {
            log.error("Mapper method {} failed", joinPoint.getSignature().getName(), e);
            throw e;
        }
    }
}

🎯 本章小结

通过本章学习,你应该掌握了:

  1. 自动配置:理解 Spring Boot 自动配置机制和条件装配
  2. 配置属性:掌握配置文件的使用和自定义配置
  3. 依赖注入:学会在 Spring 容器中使用 Mapper
  4. 监控集成:了解健康检查和性能监控的实现

📖 下一步学习

在下一篇教程中,我们将学习:

  • 单元测试和集成测试的编写
  • Mock 和测试数据的准备
  • 测试覆盖率和质量保证
相关推荐
傻傻虎虎2 小时前
【Docker】容器端口暴露+镜像生成实战
java·docker·容器
练习时长一年2 小时前
搭建langchain4j+SpringBoot的Ai项目
java·spring boot·后端
九术沫2 小时前
装饰器模式在Spring中的案例
java·spring·装饰器模式
Rysxt_3 小时前
Spring Boot 集成 Spring AI OpenAI Starter 教程
java·spring boot·后端·ai
青云交3 小时前
Java 大视界 -- Java 大数据在智能家居场景联动与用户行为模式挖掘中的应用
java·大数据·智能家居·边缘计算·户型适配·行为挖掘·场景联动
AAA修煤气灶刘哥3 小时前
ES 高级玩法大揭秘:从算分骚操作到深度分页踩坑,后端 er 速进!
java·后端·elasticsearch
江团1io03 小时前
深入解析MVCC:多版本并发控制的原理与实现
java·经验分享·mysql
树码小子3 小时前
Java网络编程:(socket API编程:UDP协议的 socket API -- 回显程序的服务器端程序的编写)
java·网络·udp
君宝3 小时前
Linux ALSA架构:PCM_OPEN流程 (二)
java·linux·c++