Spring Boot Knowledge and Question

本文最后更新于 2 分钟前,文中所描述的信息可能已发生改变。

Spring Boot 3.0+新特性

响应式编程 WebFlux

示例代码:

java
// 传统的Spring MVC(阻塞式)
@RestController
public class TraditionalController {

    @Autowired
    private UserService userService;

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id); // 阻塞调用
    }
}

// Spring WebFlux(响应式)
@RestController
public class ReactiveController {

    @Autowired
    private ReactiveUserService userService;

    @GetMapping("/users/{id}")
    public Mono<User> getUser(@PathVariable Long id) {
        return userService.findById(id); // 非阻塞调用
    }

    @GetMapping("/users")
    public Flux<User> getAllUsers() {
        return userService.findAll()
            .delayElements(Duration.ofMillis(100)); // 背压处理
    }
}

响应式编程的优势:

java
// 高并发处理能力
@Service
public class ReactiveUserService {

    @Autowired
    private ReactiveUserRepository repository;

    public Flux<User> findAll() {
        return repository.findAll()
            .publishOn(Schedulers.parallel()) // 并行处理
            .map(this::enrichUser)           // 数据增强
            .filter(user -> user.isActive()) // 过滤
            .onErrorResume(ex -> {           // 错误处理
                log.error("Error processing user", ex);
                return Flux.empty();
            });
    }

    private User enrichUser(User user) {
        // 异步调用其他服务
        return user;
    }
}

注解

@RestController 和 @Controller 的区别

@RestController 是 Spring4 之后加入的注解,是@ResponseBody 和@Controller 的组合注解,用于返回 json 数据。 @Controller 是 SpringMVC 的注解,用于标识控制器类。

@Autowired 和 @Resource 的区别

@Autowired 是 Spring 的注解,按类型注入,@Resource 是 J2EE 的注解,按名称注入。

示例代码:

java
@Service
public class InjectionDemo {

    // @Autowired:Spring注解,按类型注入
    @Autowired
    private UserService userService1;

    // @Autowired + @Qualifier:指定Bean名称
    @Autowired
    @Qualifier("userServiceImpl")
    private UserService userService2;

    // @Resource:JDK注解,按名称注入
    @Resource(name = "userServiceImpl")
    private UserService userService3;

    // @Resource:如果不指定name,按字段名查找
    @Resource
    private UserService userServiceImpl; // 会查找名为userServiceImpl的Bean
}

注入顺序对比:

@Autowired 注入顺序:

  1. 按类型查找 Bean
  2. 如果有多个,按@Primary 注解
  3. 如果没有@Primary,按@Qualifier 指定
  4. 如果没有@Qualifier,按字段名匹配

@Resource 注入顺序:

  1. 如果指定 name,按 name 查找
  2. 如果没有指定 name,按字段名查找
  3. 如果按名称找不到,按类型查找
  4. 如果按类型找到多个,报错

@AutoWired 执行注入逻辑:

  • 核心由 AutowiredAnnotationBeanPostProcessor 实现,它是一个 BeanPostProcessor。
  • 通过反射获取字段或方法参数的类型,然后从容器中按类型获取对应的 Bean。
  • 如果存在多个类型匹配,还会继续看 @Qualifier 注解或字段名来辅助选择。
  • 如果找不到依赖但字段不是 required=false,就会抛出异常。

@SpringBootApplication

@SpringBootApplication 是 Spring Boot 中一个常用的注解,通常用于主类上,以标识这是一个 Spring Boot 应用。它是一个组合注解,包含了多个其他注解,这使得 Spring Boot 应用的配置更加简单和便捷。

示例代码:

java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
    excludeFilters = {@Filter(
        type = FilterType.CUSTOM,
        classes = {TypeExcludeFilter.class}
    ), @Filter(
        type = FilterType.CUSTOM,
        classes = {AutoConfigurationExcludeFilter.class}
    )}
)
public @interface SpringBootApplication {
    // 指定要排除的自动配置类
    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};

    // 指定要排除的自动配置类名称
    @AliasFor(annotation = EnableAutoConfiguration.class)
    String[] excludeName() default {};

    // 指定要扫描的基础包
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    // 指定要扫描的基础包类
    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};

    // 指定用于生成bean名称的生成器
    @AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    // 指定配置类是否代理其bean方法
    @AliasFor(annotation = Configuration.class)
    boolean proxyBeanMethods() default true;
}

@SpringBootConfiguration

这个注解是 @Configuration 的特化版本,主要用于 Spring Boot 项目中,表明该类是一个配置类,可以用来定义 bean。

示例代码:

java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}

@EnableAutoConfiguration

这个注解启用 Spring Boot 的自动配置机制,根据项目中的依赖和配置自动配置 Spring 应用。

示例代码:

java
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
    // 排除某些自动配置类
    Class<?>[] exclude() default {};

    // 排除某些自动配置类的名称
    String[] excludeName() default {};
}

@ComponentScan

这个注解用于组件扫描,扫描主类所在包及其子包中的组件。

示例代码:

java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    // 要扫描的基础包
    @AliasFor("basePackages")
    String[] value() default {};

    // 要扫描的基础包
    @AliasFor("value")
    String[] basePackages() default {};

    // 要扫描的基础包类
    Class<?>[] basePackageClasses() default {};

    // 指定用于生成bean名称的生成器
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    // 其他属性省略...
}

AOP

AOP 是什么?

答:AOP(Aspect-Oriented Programming,面向切面编程) 能够将那些与业务无关, 却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来, 便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。


Spring AOP 是如何实现的?

切面定义:

java
@Aspect
@Component
public class LoggingAspect {

    // 切点表达式
    @Pointcut("execution(* com.example.service.*.*(..))")
    public void serviceLayer() {}

    // 前置通知
    @Before("serviceLayer()")
    public void logBefore(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("方法执行前: " + methodName + ", 参数: " + Arrays.toString(args));
    }

    // 后置通知
    @After("serviceLayer()")
    public void logAfter(JoinPoint joinPoint) {
        System.out.println("方法执行后: " + joinPoint.getSignature().getName());
    }

    // 返回通知
    @AfterReturning(pointcut = "serviceLayer()", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("方法返回: " + joinPoint.getSignature().getName() + ", 结果: " + result);
    }

    // 异常通知
    @AfterThrowing(pointcut = "serviceLayer()", throwing = "ex")
    public void logAfterThrowing(JoinPoint joinPoint, Exception ex) {
        System.out.println("方法异常: " + joinPoint.getSignature().getName() + ", 异常: " + ex.getMessage());
    }

    // 环绕通知
    @Around("serviceLayer()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();

        System.out.println("环绕通知 - 开始: " + joinPoint.getSignature().getName());

        try {
            Object result = joinPoint.proceed(); // 执行目标方法

            long endTime = System.currentTimeMillis();
            System.out.println("环绕通知 - 结束: " + joinPoint.getSignature().getName() +
                ", 耗时: " + (endTime - startTime) + "ms");

            return result;
        } catch (Exception ex) {
            System.out.println("环绕通知 - 异常: " + ex.getMessage());
            throw ex;
        }
    }
}

切点表达式详解:

java
// 1. execution表达式
@Pointcut("execution(public * com.example.service.*.*(..))")
// 修饰符 返回类型 包名.类名.方法名(参数)

// 2. within表达式
@Pointcut("within(com.example.service.*)")
// 匹配包内的所有方法

// 3. this和target
@Pointcut("this(com.example.service.UserService)")
// this:代理对象是指定类型
// target:目标对象是指定类型

// 4. args表达式
@Pointcut("args(java.lang.String,..)")
// 匹配参数类型

// 5. @annotation表达式
@Pointcut("@annotation(com.example.annotation.Log)")
// 匹配有指定注解的方法

动态代理

JDK 动态代理和 CGLIB 有什么区别?

JDK 动态代理实现:

java
// 1. 目标接口
public interface UserService {
    void saveUser(String username);
    User findUser(Long id);
}

// 2. 目标实现类
@Service
public class UserServiceImpl implements UserService {
    @Override
    public void saveUser(String username) {
        System.out.println("保存用户: " + username);
    }

    @Override
    public User findUser(Long id) {
        System.out.println("查找用户: " + id);
        return new User(id, "user" + id);
    }
}

// 3. JDK动态代理
public class JdkProxyDemo {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();

        UserService proxy = (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("JDK代理 - 方法执行前: " + method.getName());
                    Object result = method.invoke(target, args);
                    System.out.println("JDK代理 - 方法执行后: " + method.getName());
                    return result;
                }
            }
        );

        proxy.saveUser("张三");
    }
}

CGLIB 代理实现:

java
// 1. 目标类(不需要接口)
@Service
public class OrderService {
    public void createOrder(String orderNo) {
        System.out.println("创建订单: " + orderNo);
    }
}

// 2. CGLIB代理
public class CglibProxyDemo {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(OrderService.class);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("CGLIB代理 - 方法执行前: " + method.getName());
                Object result = proxy.invokeSuper(obj, args);
                System.out.println("CGLIB代理 - 方法执行后: " + method.getName());
                return result;
            }
        });

        OrderService proxy = (OrderService) enhancer.create();
        proxy.createOrder("ORDER001");
    }
}

两种代理方式对比:

特性JDK 动态代理CGLIB 代理
支持对象类型只能代理接口可以代理类,无需接口
性能较好(方法调用)稍差(字节码生成)
依赖JDK 原生,无需额外依赖需引入 CGLIB 库
限制目标类必须实现接口不能代理 final 类和 final 方法
功能扩展性功能有限功能更强

事务传播

Spring 事务的传播机制有哪些?什么时候用哪种?

七种传播机制:

java
@Service
public class TransactionService {

    // REQUIRED:默认,如果有事务就加入,没有就新建
    @Transactional(propagation = Propagation.REQUIRED)
    public void required() {
        // 业务逻辑
    }

    // REQUIRES_NEW:总是新建事务,挂起当前事务
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void requiresNew() {
        // 独立事务,不受外部事务影响
    }

    // SUPPORTS:有事务就加入,没有就非事务执行
    @Transactional(propagation = Propagation.SUPPORTS)
    public void supports() {
        // 支持事务但不强制
    }

    // NOT_SUPPORTED:总是非事务执行,挂起当前事务
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void notSupported() {
        // 强制非事务执行
    }

    // MANDATORY:必须在事务中执行,否则抛异常
    @Transactional(propagation = Propagation.MANDATORY)
    public void mandatory() {
        // 必须有事务
    }

    // NEVER:必须非事务执行,有事务就抛异常
    @Transactional(propagation = Propagation.NEVER)
    public void never() {
        // 绝不能有事务
    }

    // NESTED:嵌套事务,基于Savepoint实现
    @Transactional(propagation = Propagation.NESTED)
    public void nested() {
        // 嵌套事务,可以独立回滚
    }
}

实际应用场景:

java
@Service
public class OrderService {

    @Autowired
    private PaymentService paymentService;

    @Autowired
    private LogService logService;

    @Transactional
    public void createOrder(Order order) {
        // 1. 保存订单
        saveOrder(order);
        // 2. 处理支付(独立事务)
        paymentService.processPayment(order.getPayment());
        // 3. 记录日志(不影响主事务)
        logService.logOrderCreation(order);
    }
}

@Service
public class PaymentService {

    // 支付使用独立事务,失败不影响订单创建
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void processPayment(Payment payment) {
        // 支付逻辑
        if (payment.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new PaymentException("支付金额无效");
        }
        // 调用第三方支付
    }
}

@Service
public class LogService {

    // 日志记录不需要事务
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void logOrderCreation(Order order) {
        // 记录日志,即使失败也不影响业务
        try {
            // 写入日志
        } catch (Exception e) {
            // 忽略日志异常
        }
    }
}

IOC

IOC 是什么?

答:IoC(Inversion of Control,控制反转) 是 Spring 中一个非常非常重要的概念,它不是什么技术,而是一种解耦的设计思想。 IoC 的主要目的是借助于“第三方”(Spring 中的 IoC 容器) 实现具有依赖关系的对象之间的解耦(IOC 容器管理对象,你只管使用即可),从而降低代码之间的耦合度。


Spring Bean 的生命周期,每个阶段都做什么?

Spring 启动时会先解析配置或注解,生成 BeanDefinition 并注册。之后通过反射创建实例,执行依赖注入,再调用生命周期回调,比如 BeanPostProcessor、InitializingBean、@PostConstruct 等。初始化完成后放入一级缓存用于单例复用,整个过程由 BeanFactory 或 ApplicationContext 接口统一管理。

加载流程:

  1. 定位 Bean(Resource 定位) 启动扫描类,扫描配置文件或注解类,定位到 Bean 的定义(XML、注解、JavaConfig 都支持)。
  2. 解析 Bean(BeanDefinition 解析) 将配置转换为 BeanDefinition,存入 BeanFactory 的缓存中。
  3. 实例化 Bean(Constructor or Factory Method) 通过反射创建对象实例,但此时还未注入属性。
  4. 依赖注入 populateBean() 根据 @Autowired、@Value 等注解或 XML 设置,注入所需属性。
  5. Bean 的生命周期回调
    • 调用 Aware 接口(如 BeanNameAware、ApplicationContextAware)
    • 调用 BeanPostProcessor#postProcessBeforeInitialization
    • 调用 @PostConstruct 或 InitializingBean#afterPropertiesSet
    • 调用 BeanPostProcessor#postProcessAfterInitialization
  6. 初始化完成,放入一级缓存 可以被外部依赖使用的 Bean 才会进入一级缓存,供单例复用。
  7. 销毁阶段(可选) 如果实现了 DisposableBean 或配置了 @PreDestroy,会在销毁时调用。

完整生命周期:

java
@Component
public class LifecycleBean implements BeanNameAware, BeanFactoryAware,
    ApplicationContextAware, InitializingBean, DisposableBean {

    private String beanName;
    private BeanFactory beanFactory;
    private ApplicationContext applicationContext;

    // 1. 构造器
    public LifecycleBean() {
        System.out.println("1. 构造器执行");
    }

    // 2. 设置属性
    @Value("${app.name:default}")
    private String appName;

    // 3. Aware接口回调
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("3. setBeanName: " + name);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        System.out.println("3. setBeanFactory");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        System.out.println("3. setApplicationContext");
    }

    // 4. BeanPostProcessor前置处理
    // 由框架调用,这里只是说明

    // 5. InitializingBean接口
    @Override
    public void afterPropertiesSet() {
        System.out.println("5. afterPropertiesSet");
    }

    // 6. 自定义初始化方法
    @PostConstruct
    public void customInit() {
        System.out.println("6. @PostConstruct");
    }

    // 7. BeanPostProcessor后置处理
    // 由框架调用,这里只是说明

    // 8. Bean可以使用了
    public void doSomething() {
        System.out.println("8. Bean正在工作...");
    }

    // 9. DisposableBean接口
    @Override
    public void destroy() {
        System.out.println("9. destroy");
    }

    // 10. 自定义销毁方法
    @PreDestroy
    public void customDestroy() {
        System.out.println("10. @PreDestroy");
    }
}

自定义 BeanPostProcessor:

java
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        if (bean instanceof LifecycleBean) {
            System.out.println("4. BeanPostProcessor前置处理: " + beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        if (bean instanceof LifecycleBean) {
            System.out.println("7. BeanPostProcessor后置处理: " + beanName);
        }
        return bean;
    }
}

三级缓存

Spring 是如何解决循环依赖的?三级缓存是什么?

循环依赖场景:

java
@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB;

    public void methodA() {
        serviceB.methodB();
    }
}

@Service
public class ServiceB {
    @Autowired
    private ServiceA serviceA;

    public void methodB() {
        serviceA.methodA();
    }
}

三级缓存机制:

java
public class DefaultSingletonBeanRegistry {

    // 一级缓存:完成初始化的单例Bean
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    // 二级缓存:完成实例化但未初始化的Bean
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

    // 三级缓存:单例Bean的工厂
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
        // 1. 从一级缓存获取
        Object singletonObject = this.singletonObjects.get(beanName);

        if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
            synchronized (this.singletonObjects) {
                // 2. 从二级缓存获取
                singletonObject = this.earlySingletonObjects.get(beanName);

                if (singletonObject == null && allowEarlyReference) {
                    // 3. 从三级缓存获取
                    ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {
                        singletonObject = singletonFactory.getObject();
                        // 放入二级缓存
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        // 从三级缓存移除
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }
        return singletonObject;
    }
}

解决过程详解:

  1. 创建 ServiceA

    • 实例化 ServiceA(构造器)
    • 将 ServiceA 的 ObjectFactory 放入三级缓存
    • 填充 ServiceA 的属性(发现需要 ServiceB)
  2. 创建 ServiceB

    • 实例化 ServiceB(构造器)
    • 将 ServiceB 的 ObjectFactory 放入三级缓存
    • 填充 ServiceB 的属性(发现需要 ServiceA)
  3. 获取 ServiceA

    • 从三级缓存获取 ServiceA 的 ObjectFactory
    • 调用 ObjectFactory.getObject()获取 ServiceA 实例
    • 将 ServiceA 放入二级缓存,从三级缓存移除
  4. ServiceB 初始化完成

    • ServiceB 获得 ServiceA 的引用
    • ServiceB 初始化完成,放入一级缓存
  5. ServiceA 初始化完成

    • ServiceA 获得 ServiceB 的引用
    • ServiceA 初始化完成,放入一级缓存

Spring MVC

说说 Spring MVC 的请求处理流程,DispatcherServlet 是如何工作的?

完整流程:

客户端请求 → DispatcherServlet → HandlerMapping → Handler → HandlerAdapter → Controller → ModelAndView → ViewResolver → View → 响应

源码分析:

java
public class DispatcherServlet extends FrameworkServlet {

    @Override
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            // 1. 检查是否为文件上传请求
            processedRequest = checkMultipart(request);

            // 2. 根据请求找到对应的Handler
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 3. 根据Handler找到对应的HandlerAdapter
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // 4. 执行拦截器的preHandle方法
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // 5. 执行Handler(Controller方法)
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            // 6. 设置默认视图名
            applyDefaultViewName(processedRequest, mv);

            // 7. 执行拦截器的postHandle方法
            mappedHandler.applyPostHandle(processedRequest, response, mv);

        } catch (Exception ex) {
            dispatchException = ex;
        }

        // 8. 处理结果(渲染视图或处理异常)
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    }
}

参数解析与数据绑定

参数解析器:

java
@RestController
public class ParameterController {

    // 1. 路径变量
    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);
    }

    // 2. 请求参数
    @GetMapping("/users")
    public List<User> getUsers(@RequestParam(defaultValue = "0") int page,
                              @RequestParam(defaultValue = "10") int size) {
        return userService.findUsers(page, size);
    }

    // 3. 请求体
    @PostMapping("/users")
    public User createUser(@RequestBody @Valid User user) {
        return userService.save(user);
    }

    // 4. 请求头
    @GetMapping("/info")
    public String getInfo(@RequestHeader("User-Agent") String userAgent) {
        return "User-Agent: " + userAgent;
    }

    // 5. Cookie
    @GetMapping("/session")
    public String getSession(@CookieValue("JSESSIONID") String sessionId) {
        return "Session ID: " + sessionId;
    }

    // 6. 自定义参数解析
    @GetMapping("/current-user")
    public User getCurrentUser(@CurrentUser User user) {
        return user;
    }
}

// 自定义参数解析器
@Component
public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(CurrentUser.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                 NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
        // 从请求中解析当前用户
        String token = webRequest.getHeader("Authorization");
        return parseUserFromToken(token);
    }

    private User parseUserFromToken(String token) {
        // 解析token获取用户信息
        return new User();
    }
}

### 异常处理机制

全局异常处理:

java
@ControllerAdvice
public class GlobalExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    // 1. 处理参数校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) {
        List<String> errors = ex.getBindingResult()
            .getFieldErrors()
            .stream()
            .map(error -> error.getField() + ": " + error.getDefaultMessage())
            .collect(Collectors.toList());

        ErrorResponse errorResponse = new ErrorResponse("参数校验失败", errors);
        return ResponseEntity.badRequest().body(errorResponse);
    }

    // 2. 处理业务异常
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException ex) {
        logger.warn("业务异常: {}", ex.getMessage());
        ErrorResponse errorResponse = new ErrorResponse(ex.getMessage(), ex.getCode());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse);
    }

    // 3. 处理系统异常
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseEntity<ErrorResponse> handleSystemException(Exception ex) {
        logger.error("系统异常", ex);
        ErrorResponse errorResponse = new ErrorResponse("系统内部错误", "SYSTEM_ERROR");
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
    }

    // 4. 处理404异常
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public ResponseEntity<ErrorResponse> handleNotFoundException(NoHandlerFoundException ex) {
        ErrorResponse errorResponse = new ErrorResponse("请求的资源不存在", "NOT_FOUND");
        return ResponseEntity.notFound().build();
    }
}

// 错误响应实体
public class ErrorResponse {
    private String message;
    private String code;
    private List<String> details;
    private long timestamp;

    // 构造器、getter、setter
}

设计模式

单例设计模式 (Singleton Pattern)

详见 helltractor blog 中单例模式

工厂设计模式 (Factory Pattern)

Spring 中的 BeanFactory 和 ApplicationContext 就是工厂模式的体现,它们用来创建和管理对象。

  • BeanFactory:延迟注入(使用到某个 bean 的时候才会注入),相比于 ApplicationContext 来说会占用更少的内存,程序启动速度更快。
  • ApplicationContext:容器启动的时候,不管你用没用到,一次性创建所有 bean 。BeanFactory 仅提供了最基本的依赖注入支持, ApplicationContext 扩展了 BeanFactory ,除了有 BeanFactory 的功能还有额外更多功能,所以一般开发人员使用 ApplicationContext 会更多。

代理设计模式 (Proxy Pattern)

TODO

适配器设计模式 (Adapter Pattern)

TODO

装饰器设计模式 (Decorator Pattern)

如 python 中的装饰器@cache,@lru_cache 等,可以在不改变原有代码的情况下,增加新的功能。

观察者设计模式 (Observer Pattern)

TODO

模板方法设计模式 (Template Method Pattern)

如 jdbcTemplate,hibernateTemplate 之类,使用时只需要继承模板类,实现部分方法即可。

参考

材料计算常用资源