学习目标

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

  • 理解 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:

<!-- 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:

# 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 的自动配置实现:

/**
 * 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:配置属性类

/**
 * 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 主类

/**
 * 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 接口

/**
 * 用户映射器 - 自动注册为 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 中注入使用

/**
 * 用户服务类 - 注入 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 控制器

/**
 * 用户控制器
 */
@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:多环境配置

# 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:自定义配置器

/**
 * 自定义 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:健康检查和监控

/**
 * 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:性能监控和指标

/**
 * 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 集成测试

创建集成测试

/**
 * 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("[email protected]");
        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("[email protected]");
        
        // 这里需要 Mock Repository 或使用 @DataJpaTest
        // UserDto result = userService.createUser(userDto);
        // assertThat(result).isNotNull();
    }
}

启动应用测试

# 启动应用
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":"[email protected]"}'

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

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

常见问题

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

A: 检查以下几个方面:

// 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 注解指定名称:

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

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

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

A: 使用 Profile 特定配置:

# 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: 启用性能监控和指标收集:

# 配置
atlas:
  mapper:
    performance-monitoring: true

management:
  endpoints:
    web:
      exposure:
        include: health,metrics,info
  endpoint:
    health:
      show-details: always
// 自定义性能监控
@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 和测试数据的准备
  • 测试覆盖率和质量保证
本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]