Spring基础

Spring 基础知识

一、Spring 概述

1.1 Spring 简介

Spring 是一个开源的 Java 开发框架,它提供了一系列功能强大的特性,用于简化企业级应用开发。Spring 的核心特性包括:

  • 依赖注入(DI)
  • 面向切面编程(AOP)
  • 声明式事务
  • 集成其他框架
  • 简化测试

1.2 Spring 核心模块

  • Spring Core:核心容器
  • Spring AOP:面向切面编程
  • Spring DAO:数据访问
  • Spring ORM:对象关系映射
  • Spring Web:Web 开发
  • Spring Context:应用上下文

二、Spring 配置

2.1 Maven 依赖

<dependencies>
    
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-coreartifactId>
        <version>5.3.20version>
    dependency>
    
    
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-contextartifactId>
        <version>5.3.20version>
    dependency>
    
    
    <dependency>
        <groupId>org.springframeworkgroupId>
        <artifactId>spring-aopartifactId>
        <version>5.3.20version>
    dependency>
dependencies>

2.2 XML 配置


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    
    <context:component-scan base-package="com.example"/>
    
    
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/dbname"/>
        <property name="username" value="root"/>
        <property name="password" value="password"/>
    bean>
beans>

2.3 Java 配置

@Configuration
@ComponentScan("com.example")
public class AppConfig {
    
    @Bean
    public DataSource dataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dbname");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        return dataSource;
    }
}

三、依赖注入

3.1 构造器注入

@Service
public class UserService {
    private final UserRepository userRepository;
    
    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

3.2 属性注入

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
}

3.3 Setter 注入

@Service
public class UserService {
    private UserRepository userRepository;
    
    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

四、AOP 编程

4.1 切面定义

@Aspect
@Component
public class LoggingAspect {
    
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getSignature().getName());
    }
    
    @After("execution(* com.example.service.*.*(..))")
    public void afterMethod(JoinPoint joinPoint) {
        System.out.println("After method: " + joinPoint.getSignature().getName());
    }
}

4.2 通知类型

  • @Before:前置通知
  • @After:后置通知
  • @AfterReturning:返回通知
  • @AfterThrowing:异常通知
  • @Around:环绕通知

五、事务管理

5.1 声明式事务

@Service
@Transactional
public class UserService {
    
    @Transactional(rollbackFor = Exception.class)
    public void transferMoney(String from, String to, BigDecimal amount) {
        // 转账逻辑
    }
}

5.2 事务传播行为

  • REQUIRED:默认传播行为
  • REQUIRES_NEW:创建新事务
  • NESTED:嵌套事务
  • SUPPORTS:支持事务
  • NOT_SUPPORTED:不支持事务
  • MANDATORY:强制事务
  • NEVER:禁止事务

六、Spring MVC

6.1 控制器

@Controller
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping("/{id}")
    public ResponseEntity<User> getUser(@PathVariable Long id) {
        return ResponseEntity.ok(userService.findById(id));
    }
    
    @PostMapping
    public ResponseEntity<User> createUser(@RequestBody User user) {
        return ResponseEntity.ok(userService.save(user));
    }
}

6.2 视图解析

@Configuration
public class WebConfig implements WebMvcConfigurer {
    
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

七、数据访问

7.1 JdbcTemplate

@Repository
public class UserRepository {
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    public User findById(Long id) {
        return jdbcTemplate.queryForObject(
            "SELECT * FROM users WHERE id = ?",
            new Object[]{id},
            (rs, rowNum) -> {
                User user = new User();
                user.setId(rs.getLong("id"));
                user.setName(rs.getString("name"));
                return user;
            }
        );
    }
}

7.2 MyBatis 集成

@Mapper
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(@Param("id") Long id);
    
    @Insert("INSERT INTO users(name) VALUES(#{name})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    void insert(User user);
}

八、Spring Security

8.1 安全配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
            .and()
            .logout()
                .permitAll();
    }
}

8.2 用户认证

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("User not found");
        }
        return new org.springframework.security.core.userdetails.User(
            user.getUsername(),
            user.getPassword(),
            getAuthorities(user)
        );
    }
}

九、Spring Boot

9.1 启动类

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

9.2 配置文件

# application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/dbname
    username: root
    password: password
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

server:
  port: 8080

十、测试

10.1 单元测试

@SpringBootTest
class UserServiceTest {
    
    @Autowired
    private UserService userService;
    
    @Test
    void testCreateUser() {
        User user = new User();
        user.setName("Test User");
        User saved = userService.save(user);
        assertNotNull(saved.getId());
        assertEquals("Test User", saved.getName());
    }
}

10.2 集成测试

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerTest {
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    void testGetUser() {
        ResponseEntity<User> response = restTemplate.getForEntity(
            "/api/users/1",
            User.class
        );
        assertEquals(HttpStatus.OK, response.getStatusCode());
    }
}

十一、Spring Cloud

11.1 服务注册与发现

// 服务提供者
@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}

// 服务消费者
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
}

11.2 负载均衡

@Configuration
public class LoadBalancerConfig {
    
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

@Service
public class UserService {
    @Autowired
    private RestTemplate restTemplate;
    
    public User getUser(Long id) {
        return restTemplate.getForObject(
            "http://user-service/api/users/{id}",
            User.class,
            id
        );
    }
}

11.3 熔断降级

@Service
public class UserService {
    
    @HystrixCommand(fallbackMethod = "getUserFallback")
    public User getUser(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("User not found"));
    }
    
    public User getUserFallback(Long id) {
        return new User(id, "Fallback User");
    }
}

十二、Spring Data JPA

12.1 实体定义

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false)
    private String name;
    
    @Column(unique = true)
    private String email;
    
    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<Order> orders;
    
    // getters and setters
}

12.2 Repository接口

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByNameContaining(String name);
    
    Optional<User> findByEmail(String email);
    
    @Query("SELECT u FROM User u WHERE u.age > :age")
    List<User> findUsersOlderThan(@Param("age") int age);
}

12.3 服务层实现

@Service
@Transactional
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User createUser(User user) {
        return userRepository.save(user);
    }
    
    public List<User> findUsersByName(String name) {
        return userRepository.findByNameContaining(name);
    }
    
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

十三、Spring缓存

13.1 缓存配置

@Configuration
@EnableCaching
public class CacheConfig {
    
    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Arrays.asList(
            new ConcurrentMapCache("users"),
            new ConcurrentMapCache("products")
        ));
        return cacheManager;
    }
}

13.2 缓存使用

@Service
public class UserService {
    
    @Cacheable(value = "users", key = "#id")
    public User getUser(Long id) {
        return userRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("User not found"));
    }
    
    @CacheEvict(value = "users", key = "#user.id")
    public User updateUser(User user) {
        return userRepository.save(user);
    }
    
    @CachePut(value = "users", key = "#user.id")
    public User createUser(User user) {
        return userRepository.save(user);
    }
}

13.3 Redis缓存

@Configuration
@EnableCaching
public class RedisConfig {
    
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

十四、Spring WebFlux

14.1 响应式控制器

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserService userService;
    
    @GetMapping
    public Flux<User> getAllUsers() {
        return userService.findAll();
    }
    
    @GetMapping("/{id}")
    public Mono<User> getUser(@PathVariable Long id) {
        return userService.findById(id);
    }
    
    @PostMapping
    public Mono<User> createUser(@RequestBody User user) {
        return userService.save(user);
    }
}

14.2 响应式服务

@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public Flux<User> findAll() {
        return userRepository.findAll();
    }
    
    public Mono<User> findById(Long id) {
        return userRepository.findById(id);
    }
    
    public Mono<User> save(User user) {
        return userRepository.save(user);
    }
}

十五、Spring Batch

15.1 批处理作业

@Configuration
public class BatchConfig {
    
    @Bean
    public Job importUserJob(JobBuilderFactory jobs, StepBuilderFactory steps) {
        return jobs.get("importUserJob")
            .start(steps.get("step1")
                .<User, User>chunk(10)
                .reader(reader())
                .processor(processor())
                .writer(writer())
                .build())
            .build();
    }
    
    @Bean
    public ItemReader<User> reader() {
        return new FlatFileItemReaderBuilder<User>()
            .name("userReader")
            .delimited()
            .names(new String[]{"id", "name", "email"})
            .fieldSetMapper(new BeanWrapperFieldSetMapper<User>() {{
                setTargetType(User.class);
            }})
            .build();
    }
}

15.2 任务调度

@Configuration
@EnableScheduling
public class SchedulingConfig {
    
    @Scheduled(cron = "0 0 1 * * ?")
    public void scheduledTask() {
        // 执行定时任务
    }
    
    @Scheduled(fixedRate = 5000)
    public void fixedRateTask() {
        // 每5秒执行一次
    }
}

十六、Spring Data MongoDB

16.1 配置MongoDB

# application.yml
spring:
  data:
    mongodb:
      host: localhost
      port: 27017
      database: mydb
      username: user
      password: password
      authentication-database: admin

16.2 实体定义

@Document(collection = "users")
public class User {
    @Id
    private String id;
    
    @Field("user_name")
    private String name;
    
    @Indexed(unique = true)
    private String email;
    
    @DBRef
    private List<Order> orders;
    
    @CreatedDate
    private Date createdAt;
    
    @LastModifiedDate
    private Date updatedAt;
    
    // getters and setters
}

16.3 Repository接口

@Repository
public interface UserRepository extends MongoRepository<User, String> {
    // 基本CRUD方法由MongoRepository提供
    
    // 自定义查询方法
    List<User> findByNameContaining(String name);
    
    Optional<User> findByEmail(String email);
    
    @Query("{ 'age': { $gt: ?0 } }")
    List<User> findUsersOlderThan(int age);
    
    // 使用@Aggregation注解进行聚合查询
    @Aggregation(pipeline = {
        "{ $match: { age: { $gt: ?0 } } }",
        "{ $group: { _id: '$city', count: { $sum: 1 } } }"
    })
    List<CityCount> countUsersByCity(int age);
}

16.4 服务层实现

@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User createUser(User user) {
        return userRepository.save(user);
    }
    
    public List<User> findUsersByName(String name) {
        return userRepository.findByNameContaining(name);
    }
    
    public void deleteUser(String id) {
        userRepository.deleteById(id);
    }
    
    // 使用MongoTemplate进行复杂查询
    @Autowired
    private MongoTemplate mongoTemplate;
    
    public List<User> findUsersByComplexQuery() {
        Criteria criteria = new Criteria();
        criteria.and("age").gt(18)
               .and("city").in("Beijing", "Shanghai");
        
        Query query = new Query(criteria);
        query.with(Sort.by(Sort.Direction.DESC, "createdAt"));
        
        return mongoTemplate.find(query, User.class);
    }
}

16.5 索引管理

@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
    
    @Override
    protected void configureClientMongoSettings(MongoClientSettings.Builder builder) {
        builder.applyConnectionString(new ConnectionString("mongodb://localhost:27017/mydb"));
    }
    
    @Override
    public Collection<String> getMappingBasePackages() {
        return Collections.singleton("com.example");
    }
    
    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongoClient(), getDatabaseName());
    }
}

16.6 事务支持

@Service
@Transactional
public class OrderService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private OrderRepository orderRepository;
    
    public void createOrder(String userId, Order order) {
        User user = userRepository.findById(userId)
            .orElseThrow(() -> new RuntimeException("User not found"));
            
        order.setUserId(userId);
        orderRepository.save(order);
        
        user.getOrders().add(order);
        userRepository.save(user);
    }
}

16.7 变更流监听

@Component
public class UserChangeStreamListener {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    @PostConstruct
    public void startChangeStream() {
        ChangeStreamOptions options = ChangeStreamOptions.builder()
            .returnFullUpdateDocument(true)
            .build();
            
        mongoTemplate.changeStream(
            User.class,
            options,
            event -> {
                System.out.println("Change detected: " + event.getOperationType());
                System.out.println("Document: " + event.getBody());
            }
        ).subscribe();
    }
}

16.8 地理空间查询

@Document(collection = "locations")
public class Location {
    @Id
    private String id;
    
    private String name;
    
    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
    private Point location;
    
    // getters and setters
}

@Repository
public interface LocationRepository extends MongoRepository<Location, String> {
    List<Location> findByLocationNear(Point location, Distance distance);
    
    @Query("{ location: { $near: { $geometry: ?0, $maxDistance: ?1 } } }")
    List<Location> findNearbyLocations(Point location, double maxDistance);
}

16.9 聚合管道示例

@Service
public class UserAnalyticsService {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    public List<UserAnalytics> getUserAnalytics() {
        Aggregation aggregation = Aggregation.newAggregation(
            // 匹配条件
            Aggregation.match(Criteria.where("age").gt(18)),
            
            // 分组统计
            Aggregation.group("city")
                .count().as("userCount")
                .avg("age").as("averageAge")
                .sum("orders").as("totalOrders"),
            
            // 排序
            Aggregation.sort(Sort.Direction.DESC, "userCount"),
            
            // 限制结果
            Aggregation.limit(10)
        );
        
        return mongoTemplate.aggregate(
            aggregation,
            "users",
            UserAnalytics.class
        ).getMappedResults();
    }
    
    // 复杂聚合示例
    public List<OrderAnalytics> getOrderAnalytics() {
        Aggregation aggregation = Aggregation.newAggregation(
            // 展开订单数组
            Aggregation.unwind("orders"),
            
            // 按用户分组
            Aggregation.group("_id")
                .push("orders").as("userOrders"),
            
            // 计算订单统计
            Aggregation.project()
                .and("userId").as("_id")
                .and("userOrders").as("orders")
                .and(ArithmeticOperators.Average.avgOf("orders.amount")).as("averageOrderAmount")
                .and(ArithmeticOperators.Sum.sumOf("orders.amount")).as("totalOrderAmount")
        );
        
        return mongoTemplate.aggregate(
            aggregation,
            "users",
            OrderAnalytics.class
        ).getMappedResults();
    }
}

16.10 批量操作

@Service
public class UserBatchService {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    // 批量插入
    public void batchInsert(List<User> users) {
        mongoTemplate.insertAll(users);
    }
    
    // 批量更新
    public void batchUpdate(List<User> users) {
        BulkOperations bulkOps = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, User.class);
        
        for (User user : users) {
            Update update = new Update()
                .set("name", user.getName())
                .set("email", user.getEmail())
                .set("updatedAt", new Date());
                
            bulkOps.updateOne(
                Query.query(Criteria.where("_id").is(user.getId())),
                update
            );
        }
        
        bulkOps.execute();
    }
    
    // 批量删除
    public void batchDelete(List<String> userIds) {
        mongoTemplate.remove(
            Query.query(Criteria.where("_id").in(userIds)),
            User.class
        );
    }
    
    // 批量查找
    public List<User> batchFind(List<String> userIds) {
        return mongoTemplate.find(
            Query.query(Criteria.where("_id").in(userIds)),
            User.class
        );
    }
}

16.11 全文搜索

@Document(collection = "articles")
public class Article {
    @Id
    private String id;
    
    private String title;
    
    @TextIndexed(weight = 2)
    private String content;
    
    @TextIndexed(weight = 1)
    private List<String> tags;
    
    // getters and setters
}

@Service
public class ArticleSearchService {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    // 全文搜索
    public List<Article> searchArticles(String keyword) {
        TextCriteria criteria = TextCriteria.forDefaultLanguage()
            .matching(keyword)
            .caseSensitive(false);
            
        return mongoTemplate.find(
            Query.query(criteria),
            Article.class
        );
    }
    
    // 高级全文搜索
    public List<Article> advancedSearch(String keyword, int page, int size) {
        TextCriteria criteria = TextCriteria.forDefaultLanguage()
            .matching(keyword)
            .caseSensitive(false);
            
        Query query = Query.query(criteria)
            .with(Sort.by(Sort.Direction.DESC, "score"))
            .skip(page * size)
            .limit(size);
            
        return mongoTemplate.find(query, Article.class);
    }
}

16.12 性能优化建议

16.12.1 索引优化
@Document(collection = "users")
public class User {
    @Indexed(background = true)
    private String email;
    
    @CompoundIndex(name = "age_city_idx", def = "{'age': 1, 'city': 1}")
    private Integer age;
    private String city;
    
    // 部分索引
    @Indexed(partialFilter = "{'status': 'active'}")
    private String status;
}
16.12.2 查询优化
@Service
public class UserQueryService {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    // 使用投影减少数据传输
    public List<UserDTO> findUserDTOs() {
        return mongoTemplate.find(
            Query.query(new Criteria()),
            UserDTO.class,
            "users"
        );
    }
    
    // 使用游标处理大量数据
    public void processLargeDataSet() {
        try (CloseableIterator<User> iterator = mongoTemplate.stream(
            Query.query(new Criteria()),
            User.class
        )) {
            while (iterator.hasNext()) {
                User user = iterator.next();
                // 处理用户数据
            }
        }
    }
    
    // 使用批量操作
    public void bulkUpdateUsers(List<User> users) {
        BulkOperations bulkOps = mongoTemplate.bulkOps(
            BulkOperations.BulkMode.UNORDERED,
            User.class
        );
        
        for (User user : users) {
            Update update = new Update()
                .set("lastLogin", new Date());
            bulkOps.updateOne(
                Query.query(Criteria.where("_id").is(user.getId())),
                update
            );
        }
        
        bulkOps.execute();
    }
}
16.12.3 连接池优化
# application.yml
spring:
  data:
    mongodb:
      host: localhost
      port: 27017
      database: mydb
      # 连接池配置
      connection-pool:
        max-size: 100
        min-size: 10
        max-wait-time: 5000
        max-connection-life-time: 60000
        max-connection-idle-time: 30000

16.12.4 监控与诊断
@Configuration
public class MongoMetricsConfig {
    
    @Bean
    public MongoMetricsCollector mongoMetricsCollector() {
        return new MongoMetricsCollector();
    }
    
    @Bean
    public MongoEventListener<MongoCommandEvent> mongoEventListener(
            MongoMetricsCollector metricsCollector) {
        return new MongoEventListener<MongoCommandEvent>() {
            @Override
            public void onApplicationEvent(MongoCommandEvent event) {
                metricsCollector.recordCommand(event);
            }
        };
    }
}

十七、Spring AMQP

17.1 RabbitMQ配置

# application.yml
spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: guest
    password: guest
    listener:
      simple:
        acknowledge-mode: manual
        prefetch: 1

17.2 消息发送

@Service
public class MessageService {
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    public void sendMessage(String message) {
        rabbitTemplate.convertAndSend(
            "exchange.name",
            "routing.key",
            message,
            message -> {
                message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                return message;
            }
        );
    }
}

17.3 消息接收

@Component
public class MessageListener {
    
    @RabbitListener(queues = "queue.name")
    public void handleMessage(Message message, Channel channel) {
        try {
            // 处理消息
            processMessage(message);
            // 确认消息
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            try {
                // 消息处理失败,重新入队
                channel.basicNack(
                    message.getMessageProperties().getDeliveryTag(),
                    false,
                    true
                );
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}

十八、Spring Integration

18.1 集成配置

@Configuration
@EnableIntegration
public class IntegrationConfig {
    
    @Bean
    public MessageChannel inputChannel() {
        return new DirectChannel();
    }
    
    @Bean
    public MessageChannel outputChannel() {
        return new DirectChannel();
    }
    
    @Bean
    public IntegrationFlow fileFlow() {
        return IntegrationFlows
            .from(Files.inboundAdapter(new File("/input"))
                .autoCreateDirectory(true)
                .patternFilter("*.txt"))
            .channel(inputChannel())
            .handle(Files.outboundAdapter(new File("/output"))
                .autoCreateDirectory(true)
                .fileExistsMode(FileExistsMode.REPLACE))
            .get();
    }
}

18.2 消息转换

@Configuration
public class MessageTransformConfig {
    
    @Bean
    public MessageTransformer transformer() {
        return new GenericTransformer<Message<?>, Message<?>>() {
            @Override
            public Message<?> transform(Message<?> message) {
                // 消息转换逻辑
                return MessageBuilder
                    .withPayload(message.getPayload())
                    .copyHeaders(message.getHeaders())
                    .build();
            }
        };
    }
}

十九、MongoDB高级配置

19.1 分片集群配置

# application.yml
spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017/mydb
      sharding:
        enabled: true
        shard-key: { "userId": 1 }
        chunksize: 64
      cluster:
        nodes:
          - mongodb://shard1:27017
          - mongodb://shard2:27017
          - mongodb://shard3:27017
        config-server: mongodb://config-server:27019

19.2 备份与恢复

@Service
public class BackupService {
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    public void backupDatabase(String backupPath) {
        MongoClient mongoClient = mongoTemplate.getMongoClient();
        MongoDatabase database = mongoClient.getDatabase("mydb");
        
        // 创建备份
        ProcessBuilder processBuilder = new ProcessBuilder(
            "mongodump",
            "--uri=mongodb://localhost:27017/mydb",
            "--out=" + backupPath
        );
        
        try {
            Process process = processBuilder.start();
            process.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public void restoreDatabase(String backupPath) {
        ProcessBuilder processBuilder = new ProcessBuilder(
            "mongorestore",
            "--uri=mongodb://localhost:27017/mydb",
            backupPath
        );
        
        try {
            Process process = processBuilder.start();
            process.waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

19.3 安全配置

@Configuration
public class MongoSecurityConfig {
    
    @Bean
    public MongoClient mongoClient() {
        MongoCredential credential = MongoCredential.createCredential(
            "user",
            "admin",
            "password".toCharArray()
        );
        
        ServerAddress serverAddress = new ServerAddress("localhost", 27017);
        
        return MongoClients.create(MongoClientSettings.builder()
            .credential(credential)
            .applyToClusterSettings(builder -> 
                builder.hosts(Arrays.asList(serverAddress)))
            .applyConnectionString(new ConnectionString(
                "mongodb://localhost:27017/mydb?authSource=admin"))
            .build());
    }
    
    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        return new MongoTemplate(mongoClient(), "mydb");
    }
}

19.4 监控告警

@Configuration
public class MongoMonitoringConfig {
    
    @Bean
    public MongoEventListener<MongoCommandEvent> mongoEventListener() {
        return new MongoEventListener<MongoCommandEvent>() {
            @Override
            public void onApplicationEvent(MongoCommandEvent event) {
                // 监控慢查询
                if (event.getDuration() > 1000) {
                    alertSlowQuery(event);
                }
                
                // 监控错误
                if (event.getException() != null) {
                    alertError(event);
                }
            }
        };
    }
    
    private void alertSlowQuery(MongoCommandEvent event) {
        // 发送告警通知
        System.out.println("Slow query detected: " + event.getCommand());
    }
    
    private void alertError(MongoCommandEvent event) {
        // 发送错误通知
        System.out.println("Error detected: " + event.getException());
    }
}

19.5 性能优化

@Configuration
public class MongoPerformanceConfig {
    
    @Bean
    public MongoClient mongoClient() {
        return MongoClients.create(MongoClientSettings.builder()
            .applyConnectionString(new ConnectionString(
                "mongodb://localhost:27017/mydb"))
            .applyToConnectionPoolSettings(builder -> builder
                .maxSize(100)
                .minSize(10)
                .maxWaitTime(5000, TimeUnit.MILLISECONDS))
            .applyToSocketSettings(builder -> builder
                .connectTimeout(5000, TimeUnit.MILLISECONDS)
                .readTimeout(5000, TimeUnit.MILLISECONDS))
            .build());
    }
    
    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        MongoTemplate template = new MongoTemplate(mongoClient(), "mydb");
        
        // 设置批量写入
        template.setWriteConcern(WriteConcern.MAJORITY);
        
        // 设置读取偏好
        template.setReadPreference(ReadPreference.secondaryPreferred());
        
        return template;
    }
}

二十、Spring WebSocket

20.1 WebSocket配置

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
    
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        // 设置消息代理的前缀
        config.enableSimpleBroker("/topic", "/queue");
        // 设置客户端发送消息的前缀
        config.setApplicationDestinationPrefixes("/app");
    }
    
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 注册STOMP协议的节点,并指定使用SockJS协议
        registry.addEndpoint("/ws")
               .setAllowedOrigins("*")
               .withSockJS();
    }
}

20.2 WebSocket控制器

@Controller
public class WebSocketController {
    
    @MessageMapping("/chat.send")
    @SendTo("/topic/messages")
    public ChatMessage send(ChatMessage message) {
        return message;
    }
    
    @MessageMapping("/chat.private")
    @SendToUser("/queue/private")
    public ChatMessage privateMessage(ChatMessage message) {
        return message;
    }
    
    @SubscribeMapping("/topic/status")
    public String handleSubscribe() {
        return "Connected successfully!";
    }
}

20.3 消息实体

public class ChatMessage {
    private String sender;
    private String content;
    private String timestamp;
    
    // getters and setters
}

20.4 客户端实现

// 连接WebSocket
const socket = new SockJS('/ws');
const stompClient = Stomp.over(socket);

// 连接配置
const connectHeaders = {
    'Auth-Token': 'your-auth-token'
};

// 建立连接
stompClient.connect(connectHeaders, 
    // 连接成功回调
    function(frame) {
        console.log('Connected: ' + frame);
        
        // 订阅公共消息
        stompClient.subscribe('/topic/messages', function(message) {
            showMessage(JSON.parse(message.body));
        });
        
        // 订阅私人消息
        stompClient.subscribe('/user/queue/private', function(message) {
            showPrivateMessage(JSON.parse(message.body));
        });
    },
    // 连接错误回调
    function(error) {
        console.log('STOMP error: ' + error);
    }
);

// 发送消息
function sendMessage() {
    const message = {
        sender: username,
        content: messageInput.value,
        timestamp: new Date().toISOString()
    };
    
    stompClient.send("/app/chat.send", {}, JSON.stringify(message));
}

// 发送私人消息
function sendPrivateMessage() {
    const message = {
        sender: username,
        content: privateMessageInput.value,
        recipient: recipientUsername,
        timestamp: new Date().toISOString()
    };
    
    stompClient.send("/app/chat.private", {}, JSON.stringify(message));
}

20.5 安全配置

@Configuration
@EnableWebSocketSecurity
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    
    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
            .simpDestMatchers("/app/**").authenticated()
            .simpDestMatchers("/topic/**").authenticated()
            .anyMessage().authenticated();
    }
    
    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
}

20.6 心跳检测

@Configuration
public class WebSocketHeartbeatConfig {
    
    @Bean
    public TaskScheduler messageBrokerTaskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(1);
        scheduler.setThreadNamePrefix("ws-heartbeat-thread-");
        scheduler.setErrorHandler(t -> 
            System.err.println("Heartbeat error: " + t.getMessage()));
        return scheduler;
    }
    
    @Bean
    public WebSocketHandler webSocketHandler() {
        return new WebSocketHandler() {
            @Override
            public void afterConnectionEstablished(WebSocketSession session) {
                // 连接建立后的处理
            }
            
            @Override
            public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
                // 处理消息
            }
            
            @Override
            public void handleTransportError(WebSocketSession session, Throwable exception) {
                // 处理传输错误
            }
            
            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
                // 连接关闭后的处理
            }
            
            @Override
            public boolean supportsPartialMessages() {
                return false;
            }
        };
    }
}

20.7 消息拦截器

@Component
public class WebSocketChannelInterceptor implements ChannelInterceptor {
    
    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        
        if (StompCommand.CONNECT.equals(accessor.getCommand())) {
            // 处理连接请求
            String token = accessor.getFirstNativeHeader("Auth-Token");
            if (token != null && validateToken(token)) {
                accessor.setUser(new UserPrincipal(token));
            }
        }
        
        return message;
    }
    
    private boolean validateToken(String token) {
        // 实现token验证逻辑
        return true;
    }
}

20.8 集群支持

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketClusterConfig implements WebSocketMessageBrokerConfigurer {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic", "/queue")
              .setApplicationDestinationPrefixes("/app");
    }
    
    @Bean
    public MessageBrokerRegistry messageBrokerRegistry() {
        MessageBrokerRegistry registry = new MessageBrokerRegistry();
        registry.enableSimpleBroker("/topic", "/queue")
               .setApplicationDestinationPrefixes("/app");
        return registry;
    }
    
    @Bean
    public RedisMessageBrokerRegistry redisMessageBrokerRegistry() {
        RedisMessageBrokerRegistry registry = new RedisMessageBrokerRegistry(redisTemplate);
        registry.enableSimpleBroker("/topic", "/queue")
               .setApplicationDestinationPrefixes("/app");
        return registry;
    }
}

20.9 性能优化

@Configuration
public class WebSocketPerformanceConfig {
    
    @Bean
    public WebSocketHandler webSocketHandler() {
        return new WebSocketHandler() {
            private final ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
            
            @Override
            public void afterConnectionEstablished(WebSocketSession session) {
                sessions.put(session.getId(), session);
            }
            
            @Override
            public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
                // 使用线程池处理消息
                CompletableFuture.runAsync(() -> {
                    try {
                        processMessage(session, message);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }
            
            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
                sessions.remove(session.getId());
            }
            
            private void processMessage(WebSocketSession session, WebSocketMessage<?> message) {
                // 实现消息处理逻辑
            }
        };
    }
    
    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("ws-handler-");
        executor.initialize();
        return executor;
    }
}

20.10 断线重连机制

@Configuration
public class WebSocketReconnectConfig {
    
    @Bean
    public WebSocketHandler webSocketHandler() {
        return new WebSocketHandler() {
            private final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
            private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
            
            @Override
            public void afterConnectionEstablished(WebSocketSession session) {
                sessions.put(session.getId(), session);
                scheduleHeartbeat(session);
            }
            
            @Override
            public void handleTransportError(WebSocketSession session, Throwable exception) {
                handleReconnect(session);
            }
            
            private void scheduleHeartbeat(WebSocketSession session) {
                scheduler.scheduleAtFixedRate(() -> {
                    try {
                        if (session.isOpen()) {
                            session.sendMessage(new PingMessage());
                        }
                    } catch (Exception e) {
                        handleReconnect(session);
                    }
                }, 0, 30, TimeUnit.SECONDS);
            }
            
            private void handleReconnect(WebSocketSession session) {
                try {
                    if (!session.isOpen()) {
                        // 清理旧会话
                        cleanupSession(session);
                        // 创建新会话
                        createNewSession(session);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            
            private void cleanupSession(WebSocketSession session) {
                sessions.remove(session.getId());
                scheduler.shutdown();
            }
            
            private void createNewSession(WebSocketSession session) {
                // 实现新会话创建逻辑
            }
        };
    }
}

20.11 消息压缩

@Configuration
public class WebSocketCompressionConfig {
    
    @Bean
    public WebSocketHandler webSocketHandler() {
        return new WebSocketHandler() {
            @Override
            public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
                if (message instanceof TextMessage) {
                    TextMessage textMessage = (TextMessage) message;
                    String compressed = compressMessage(textMessage.getPayload());
                    session.sendMessage(new TextMessage(compressed));
                }
            }
            
            private String compressMessage(String message) {
                try {
                    byte[] input = message.getBytes(StandardCharsets.UTF_8);
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    GZIPOutputStream gzipOutputStream = new GZIPOutputStream(outputStream);
                    gzipOutputStream.write(input);
                    gzipOutputStream.close();
                    return Base64.getEncoder().encodeToString(outputStream.toByteArray());
                } catch (IOException e) {
                    e.printStackTrace();
                    return message;
                }
            }
        };
    }
}

20.12 消息持久化

@Configuration
public class WebSocketPersistenceConfig {
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Bean
    public WebSocketHandler webSocketHandler() {
        return new WebSocketHandler() {
            private static final String MESSAGE_KEY_PREFIX = "ws:message:";
            private static final String SESSION_KEY_PREFIX = "ws:session:";
            
            @Override
            public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
                // 持久化消息
                persistMessage(session, message);
                // 处理消息
                processMessage(session, message);
            }
            
            private void persistMessage(WebSocketSession session, WebSocketMessage<?> message) {
                String messageKey = MESSAGE_KEY_PREFIX + session.getId() + ":" + System.currentTimeMillis();
                String sessionKey = SESSION_KEY_PREFIX + session.getId();
                
                // 存储消息
                redisTemplate.opsForValue().set(messageKey, message);
                
                // 更新会话消息列表
                redisTemplate.opsForList().rightPush(sessionKey, messageKey);
                
                // 设置过期时间
                redisTemplate.expire(messageKey, 24, TimeUnit.HOURS);
                redisTemplate.expire(sessionKey, 24, TimeUnit.HOURS);
            }
            
            // 消息恢复
            public void restoreMessages(WebSocketSession session) {
                String sessionKey = SESSION_KEY_PREFIX + session.getId();
                List<String> messageKeys = redisTemplate.opsForList().range(sessionKey, 0, -1);
                
                if (messageKeys != null) {
                    for (String messageKey : messageKeys) {
                        WebSocketMessage<?> message = (WebSocketMessage<?>) redisTemplate.opsForValue().get(messageKey);
                        if (message != null) {
                            session.sendMessage(message);
                        }
                    }
                }
            }
        };
    }
}

20.13 性能监控

@Configuration
public class WebSocketMonitoringConfig {
    
    @Bean
    public WebSocketHandler webSocketHandler() {
        return new WebSocketHandler() {
            private final Counter messageCounter = new Counter();
            private final Timer messageLatencyTimer = new Timer();
            private final Gauge activeConnectionsGauge = new Gauge();
            
            @Override
            public void afterConnectionEstablished(WebSocketSession session) {
                activeConnectionsGauge.increment();
            }
            
            @Override
            public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
                messageCounter.increment();
                long startTime = System.currentTimeMillis();
                
                try {
                    processMessage(session, message);
                } finally {
                    long latency = System.currentTimeMillis() - startTime;
                    messageLatencyTimer.record(latency);
                }
            }
            
            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
                activeConnectionsGauge.decrement();
            }
            
            // 性能指标导出
            @Scheduled(fixedRate = 60000)
            public void exportMetrics() {
                Metrics metrics = new Metrics();
                metrics.setMessageCount(messageCounter.getCount());
                metrics.setAverageLatency(messageLatencyTimer.getAverage());
                metrics.setActiveConnections(activeConnectionsGauge.getValue());
                
                // 导出到监控系统
                exportToMonitoringSystem(metrics);
            }
            
            private void exportToMonitoringSystem(Metrics metrics) {
                // 实现指标导出逻辑
            }
        };
    }
}

20.14 消息限流

@Configuration
public class WebSocketRateLimitConfig {
    
    @Bean
    public WebSocketHandler webSocketHandler() {
        return new WebSocketHandler() {
            private final Map<String, RateLimiter> rateLimiters = new ConcurrentHashMap<>();
            
            @Override
            public void afterConnectionEstablished(WebSocketSession session) {
                // 为每个会话创建限流器
                rateLimiters.put(session.getId(), RateLimiter.create(10.0)); // 每秒10条消息
            }
            
            @Override
            public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
                RateLimiter limiter = rateLimiters.get(session.getId());
                if (limiter != null && limiter.tryAcquire()) {
                    processMessage(session, message);
                } else {
                    // 发送限流提示
                    session.sendMessage(new TextMessage("Rate limit exceeded"));
                }
            }
            
            @Override
            public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) {
                rateLimiters.remove(session.getId());
            }
        };
    }
}

20.15 消息过滤

@Configuration
public class WebSocketFilterConfig {
    
    @Bean
    public WebSocketHandler webSocketHandler() {
        return new WebSocketHandler() {
            private final List<MessageFilter> filters = Arrays.asList(
                new XssFilter(),
                new ProfanityFilter(),
                new LengthFilter()
            );
            
            @Override
            public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
                if (message instanceof TextMessage) {
                    TextMessage textMessage = (TextMessage) message;
                    String content = textMessage.getPayload();
                    
                    // 应用过滤器链
                    for (MessageFilter filter : filters) {
                        if (!filter.filter(content)) {
                            session.sendMessage(new TextMessage("Message filtered"));
                            return;
                        }
                    }
                    
                    processMessage(session, message);
                }
            }
        };
    }
}

参考资料

  • Spring 官方文档
  • Spring Boot 官方文档
  • Spring Security 官方文档
  • Spring Cloud 官方文档
  • Spring Data JPA 官方文档
  • Spring WebFlux 官方文档
  • Spring Batch 官方文档
  • Spring Data MongoDB 官方文档
  • Spring AMQP 官方文档
  • Spring Integration 官方文档
  • Spring WebSocket 官方文档

你可能感兴趣的:(Java,spring,java,后端)