乐于分享
好东西不私藏

Spring源码中装饰器模式的运用

Spring源码中装饰器模式的运用

核心洞察:装饰器模式是一种结构型模式,它通过组合的方式动态地给对象添加额外的职责,而无需修改原始类。这种"包装"思想是Spring框架实现AOP、事务、缓存等横切关注点的设计基石。


📋 模式定义与核心哲学

核心定义

装饰器模式(Decorator Pattern) 允许向一个现有的对象动态地添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

设计哲学

  1. 开放封闭原则:对扩展开放,对修改封闭
  2. 组合优于继承:通过组合而非继承来实现功能的扩展
  3. 运行时动态增强:功能的添加可以在运行时进行,更加灵活

生活比喻

咖啡店订单系统

  • 基础咖啡:Espresso(组件)
  • 装饰器:MilkDecoratorSugarDecoratorWhippedCreamDecorator
  • 顾客可以任意组合:Espresso + Milk + Sugar 或 Espresso + WhippedCream
  • 每个装饰器都遵循相同的Coffee接口,但添加了额外功能

🏗️ UML类图与角色解析

classDiagram
    direction TB

    note for Component "被装饰对象的抽象接口\n定义核心功能契约"

    class Component {
        <<interface>>
        +operation() void
    }

    class ConcreteComponent {
        +operation() void
    }

    note for Decorator "装饰器基类\n持有Component引用\n实现相同接口"

    class Decorator {
        -component: Component
        +Decorator(Component)
        +operation() void
    }

    class ConcreteDecoratorA {
        -addedState: String
        +operation() void
        +addedBehavior() void
    }

    class ConcreteDecoratorB {
        +operation() void
    }

    Component <|.. ConcreteComponent : 实现
    Component <|.. Decorator : 实现
    Decorator o-- Component : 包装
    Decorator <|-- ConcreteDecoratorA : 继承
    Decorator <|-- ConcreteDecoratorB : 继承

    %% 方法调用流程
    note for ConcreteDecoratorA "装饰器可以在调用前后添加额外行为"
    ConcreteDecoratorA : +operation() {
    .. 前处理 ..
    component.operation()
    .. 后处理 ..
    }

模式角色详解

角色
职责
Spring中的对应实现
Component(组件)
定义对象的接口,可以动态添加职责
Bean
MethodInvocationHttpServletRequest
ConcreteComponent(具体组件)
定义具体的对象,可以被装饰
具体的ServiceControllerRepository
Decorator(装饰器)
维护对Component对象的引用,并实现相同的接口
BeanPostProcessor
MethodInterceptorFilter
ConcreteDecorator(具体装饰器)
向Component对象添加具体的职责
TransactionInterceptor
CacheInterceptorLoggingFilter

🌟 Spring中的装饰器模式应用

应用1:BeanPostProcessor - Spring IoC的装饰器模式典范

设计洞察

Spring需要在Bean生命周期的特定阶段动态增强Bean的功能,而不修改Bean本身的代码。BeanPostProcessor提供了这种装饰能力。

源码解析

// 🍃 组件接口:普通的Spring Bean
@Component
publicclassUserService{
private String serviceName = "DefaultUserService";

@PostConstruct
publicvoidinit(){
        System.out.println("UserService初始化完成");
    }

public User findUserById(Long id){
// 模拟数据库查询
returnnew User(id, "用户" + id);
    }

publicvoidupdateUser(User user){
        System.out.println("更新用户: " + user.getName());
    }
}

// 🎨 装饰器接口:BeanPostProcessor
publicinterfaceBeanPostProcessor{
/**
     * 在Bean初始化之前执行
     * 可以修改Bean的属性值
     */

@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException 
{
return bean;  // 默认不修改
    }

/**
     * 在Bean初始化之后执行
     * 可以返回包装后的Bean(代理对象)
     */

@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException 
{
return bean;  // 默认不修改
    }
}

// 🌈 具体装饰器1:属性验证装饰器
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)  // 最高优先级
publicclassValidationBeanPostProcessorimplementsBeanPostProcessor{

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException 
{
// 检查Bean是否实现了Validatable接口
if (bean instanceof Validatable) {
            Validatable validatable = (Validatable) bean;
try {
                validatable.validate();  // 执行验证
                System.out.println("✅ Bean验证通过: " + beanName);
            } catch (ValidationException e) {
                System.err.println("❌ Bean验证失败: " + beanName + " - " + e.getMessage());
thrownew BeanInitializationException("Bean验证失败", e);
            }
        }
return bean;
    }
}

// 🌈 具体装饰器2:性能监控装饰器
@Component
@Order(Ordered.LOWEST_PRECEDENCE)  // 最低优先级
publicclassMonitoringBeanPostProcessorimplementsBeanPostProcessor{

@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException 
{
// 只为Service层的Bean创建监控代理
        Class<?> beanClass = bean.getClass();
if (beanClass.isAnnotationPresent(Service.class) || 
beanClass.isAnnotationPresent(Component.class)) 
{

// 创建JDK动态代理(装饰Bean)
return Proxy.newProxyInstance(
                beanClass.getClassLoader(),
                beanClass.getInterfaces(),
new MonitoringInvocationHandler(bean, beanName)
            );
        }
return bean;
    }

// 监控调用处理器
privatestaticclassMonitoringInvocationHandlerimplementsInvocationHandler{
privatefinal Object target;
privatefinal String beanName;
privatefinal Map<String, MethodMetrics> metrics = new ConcurrentHashMap<>();

publicMonitoringInvocationHandler(Object target, String beanName){
this.target = target;
this.beanName = beanName;
        }

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable 
{
            String methodKey = method.getName();
long startTime = System.currentTimeMillis();

try {
// 调用原始方法
                Object result = method.invoke(target, args);
                recordSuccess(methodKey, startTime);
return result;
            } catch (InvocationTargetException e) {
                recordFailure(methodKey, startTime, e.getTargetException());
throw e.getTargetException();
            } finally {
// 定期输出监控报告
if (System.currentTimeMillis() % 10000 < 100) {  // 每10秒输出一次
                    outputMetricsReport();
                }
            }
        }

privatevoidrecordSuccess(String methodName, long startTime){
            MethodMetrics metric = metrics.computeIfAbsent(
                methodName, k -> new MethodMetrics());
            metric.incrementSuccess();
            metric.recordDuration(System.currentTimeMillis() - startTime);
        }

privatevoidoutputMetricsReport(){
            System.out.println("=== 监控报告 ===");
            metrics.forEach((method, metric) -> {
                System.out.printf("%s.%s: 调用%d次, 平均耗时%.2fms%n"
                    beanName, method, metric.getTotalCount(), metric.getAverageDuration());
            });
        }
    }
}

// 🌈 具体装饰器3:审计日志装饰器
@Component
publicclassAuditLogBeanPostProcessorimplementsBeanPostProcessor{

privatefinal ThreadLocal<AuditContext> auditContext = new ThreadLocal<>();

@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException 
{
// 为Repository添加审计日志
if (bean.getClass().isAnnotationPresent(Repository.class)) {
return Enhancer.create(
                bean.getClass(),
new AuditLogMethodInterceptor(bean, beanName)
            );
        }
return bean;
    }

privatestaticclassAuditLogMethodInterceptorimplementsMethodInterceptor{
privatefinal Object target;
privatefinal String beanName;

publicAuditLogMethodInterceptor(Object target, String beanName){
this.target = target;
this.beanName = beanName;
        }

@Override
public Object intercept(Object obj, Method method, Object[] args, 
                                MethodProxy proxy)
throws Throwable 
{
            String auditMessage = String.format(
"审计日志 - 类: %s, 方法: %s, 参数: %s"
                beanName, method.getName(), Arrays.toString(args)
            );

            AuditLogger.log(auditMessage);
long startTime = System.currentTimeMillis();

try {
                Object result = method.invoke(target, args);
                AuditLogger.log(String.format("方法执行成功, 耗时: %dms"
                    System.currentTimeMillis() - startTime));
return result;
            } catch (Exception e) {
                AuditLogger.log(String.format("方法执行失败: %s", e.getMessage()));
throw e;
            }
        }
    }
}

装饰器链执行流程

// Spring容器中的BeanPostProcessor执行顺序
publicabstractclassAbstractAutowireCapableBeanFactory{

protected Object initializeBean(String beanName, Object bean, 
                                   @Nullable RootBeanDefinition mbd)
{
// 1. 应用BeanPostProcessors的before初始化方法
        Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
        }

// 2. 调用Bean的初始化方法
try {
            invokeInitMethods(beanName, wrappedBean, mbd);
        } catch (Throwable ex) {
thrownew BeanCreationException("初始化失败", ex);
        }

// 3. 应用BeanPostProcessors的after初始化方法
if (mbd == null || !mbd.isSynthetic()) {
            wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
        }

return wrappedBean;
    }

// 装饰器链:按顺序执行所有BeanPostProcessor
public Object applyBeanPostProcessorsBeforeInitialization(Object bean, String beanName)
throws BeansException 
{
        Object result = bean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
            Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;  // 某个处理器返回null,停止链
            }
            result = current;  // 每个处理器可能返回包装后的对象
        }
return result;
    }
}

使用示例

@Configuration
publicclassBeanPostProcessorConfig{

@Bean
publicstatic ValidationBeanPostProcessor validationBeanPostProcessor(){
returnnew ValidationBeanPostProcessor();
    }

@Bean
publicstatic MonitoringBeanPostProcessor monitoringBeanPostProcessor(){
returnnew MonitoringBeanPostProcessor();
    }

@Bean
publicstatic AuditLogBeanPostProcessor auditLogBeanPostProcessor(){
returnnew AuditLogBeanPostProcessor();
    }

// 注意:BeanPostProcessor的@Bean方法必须是static的
// 否则会导致过早初始化,影响其他Bean的装饰
}

// 测试装饰器效果
@SpringBootTest
classBeanPostProcessorTest{

@Autowired
private UserService userService;  // 已经被多个装饰器包装

@Test
voidtestDecoratedBean(){
// 这个userService实际上是被包装过的:
// 1. 经过了ValidationBeanPostProcessor的验证
// 2. 被MonitoringBeanPostProcessor包装了性能监控
// 3. 如果是Repository,还被AuditLogBeanPostProcessor包装了审计日志

        User user = userService.findUserById(1L);
        assertNotNull(user);

// 调用会被监控和记录
        userService.updateUser(user);
    }
}

应用2:Spring AOP - 方法级别的装饰器模式

设计洞察

Spring AOP通过动态代理实现方法级别的装饰,可以在方法调用前后添加横切关注点(日志、事务、安全等)。

源码解析

// 🍃 组件:被代理的目标对象
@Service
publicclassOrderServiceImplimplementsOrderService{

@Override
@Transactional
public Order createOrder(OrderRequest request){
// 业务逻辑
        Order order = new Order();
        order.setId(UUID.randomUUID().toString());
        order.setAmount(request.getAmount());
        order.setStatus(OrderStatus.CREATED);

// 保存到数据库
        orderRepository.save(order);

// 发送事件
        applicationEventPublisher.publishEvent(new OrderCreatedEvent(this, order));

return order;
    }

@Override
@Cacheable(value = "orders", key = "#orderId")
public Order getOrder(String orderId){
return orderRepository.findById(orderId)
            .orElseThrow(() -> new OrderNotFoundException("订单不存在"));
    }

@Override
@CacheEvict(value = "orders", key = "#orderId")
publicvoidcancelOrder(String orderId){
        Order order = getOrder(orderId);
        order.setStatus(OrderStatus.CANCELLED);
        orderRepository.save(order);
    }
}

// 🎨 装饰器接口:MethodInterceptor
publicinterfaceMethodInterceptorextendsInterceptor{
/**
     * 实现此方法以在方法调用前后添加额外行为
     * @param invocation 方法调用信息
     * @return 方法调用结果
     * @throws Throwable 可能抛出的异常
     */

Object invoke(MethodInvocation invocation)throws Throwable;
}

// 🌈 具体装饰器1:事务拦截器
@Component
publicclassTransactionInterceptorimplementsMethodInterceptorOrdered{

privatefinal PlatformTransactionManager transactionManager;
privatefinal TransactionAttributeSource transactionAttributeSource;

publicTransactionInterceptor(PlatformTransactionManager transactionManager,
                                 TransactionAttributeSource transactionAttributeSource)
{
this.transactionManager = transactionManager;
this.transactionAttributeSource = transactionAttributeSource;
    }

@Override
public Object invoke(MethodInvocation invocation)throws Throwable {
// 获取事务属性(@Transactional注解的信息)
        Method method = invocation.getMethod();
        Class<?> targetClass = invocation.getThis() != null ? 
            invocation.getThis().getClass() : null;
        TransactionAttribute txAttr = transactionAttributeSource
            .getTransactionAttribute(method, targetClass);

// 如果没有@Transactional注解,直接执行方法
if (txAttr == null) {
return invocation.proceed();
        }

// 确定事务管理器
        PlatformTransactionManager tm = determineTransactionManager(txAttr);

// 创建事务
        TransactionStatus status = tm.getTransaction(txAttr);

try {
// 执行被装饰的方法
            Object result = invocation.proceed();

// 提交事务
            tm.commit(status);
return result;

        } catch (Throwable ex) {
// 根据异常类型决定是回滚还是提交
            completeTransactionAfterThrowing(status, txAttr, ex);
throw ex;
        }
    }

@Override
publicintgetOrder(){
return Ordered.HIGHEST_PRECEDENCE + 1;  // 高优先级
    }
}

// 🌈 具体装饰器2:缓存拦截器
@Component
publicclassCacheInterceptorimplementsMethodInterceptorOrdered{

privatefinal CacheManager cacheManager;
privatefinal KeyGenerator keyGenerator;

publicCacheInterceptor(CacheManager cacheManager, KeyGenerator keyGenerator){
this.cacheManager = cacheManager;
this.keyGenerator = keyGenerator;
    }

@Override
public Object invoke(MethodInvocation invocation)throws Throwable {
// 获取缓存注解
        Method method = invocation.getMethod();
        Cacheable cacheable = method.getAnnotation(Cacheable.class);
        CacheEvict cacheEvict = method.getAnnotation(CacheEvict.class);

if (cacheable != null) {
return handleCacheable(invocation, cacheable);
        } elseif (cacheEvict != null) {
return handleCacheEvict(invocation, cacheEvict);
        } else {
return invocation.proceed();
        }
    }

private Object handleCacheable(MethodInvocation invocation, Cacheable cacheable)
throws Throwable 
{
// 生成缓存key
        Object key = keyGenerator.generate(invocation.getThis(), 
                                          invocation.getMethod(), 
                                          invocation.getArguments());

// 获取缓存
        Cache cache = cacheManager.getCache(cacheable.value());
        ValueWrapper cachedValue = cache.get(key);

if (cachedValue != null) {
// 缓存命中,直接返回
            System.out.println("缓存命中: " + cacheable.value() + " - " + key);
return cachedValue.get();
        }

// 缓存未命中,执行方法
        Object result = invocation.proceed();

// 将结果放入缓存
if (result != null) {
            cache.put(key, result);
            System.out.println("缓存写入: " + cacheable.value() + " - " + key);
        }

return result;
    }

@Override
publicintgetOrder(){
return Ordered.LOWEST_PRECEDENCE - 1;  // 低优先级
    }
}

// 🌈 具体装饰器3:性能监控拦截器
@Component
publicclassPerformanceMonitorInterceptorimplementsMethodInterceptor{

privatestaticfinal Logger logger = LoggerFactory
        .getLogger(PerformanceMonitorInterceptor.class);

@Override
public Object invoke(MethodInvocation invocation)throws Throwable {
        String className = invocation.getMethod().getDeclaringClass().getSimpleName();
        String methodName = invocation.getMethod().getName();
        String fullMethodName = className + "." + methodName;

long startTime = System.currentTimeMillis();
        logger.info("开始执行: {}", fullMethodName);

try {
            Object result = invocation.proceed();
long duration = System.currentTimeMillis() - startTime;

if (duration > 1000) {  // 超过1秒记录警告
                logger.warn("方法执行缓慢: {} 耗时 {}ms", fullMethodName, duration);
            } else {
                logger.info("方法执行完成: {} 耗时 {}ms", fullMethodName, duration);
            }

return result;
        } catch (Exception e) {
            logger.error("方法执行异常: {} - {}", fullMethodName, e.getMessage(), e);
throw e;
        }
    }
}

AOP代理创建过程

// AOP代理工厂:创建装饰器链
publicclassProxyFactoryextendsProxyCreatorSupport{

public Object getProxy(){
return createAopProxy().getProxy();
    }

protectedfinalsynchronized AopProxy createAopProxy(){
if (!isActive()) {
            activate();
        }

// 获取所有Advisor(装饰器链)
        List<Advisor> advisors = getAdvisors();

// 根据条件选择JDK动态代理或CGLIB代理
if (isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces()) {
            Class<?> targetClass = getTargetClass();
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
returnnew JdkDynamicAopProxy(this);
            }
returnnew ObjenesisCglibAopProxy(this);
        } else {
returnnew JdkDynamicAopProxy(this);
        }
    }
}

// 装饰器链的执行
publicclassReflectiveMethodInvocationimplementsProxyMethodInvocation{

privatefinal Object proxy;
privatefinal Object target;
privatefinal Method method;
privatefinal Object[] arguments;
privatefinal List<Object> interceptorsAndDynamicMethodMatchers;
privateint currentInterceptorIndex = -1;

@Override
public Object proceed()throws Throwable {
// 如果已经执行到装饰器链的末尾,执行原始方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
        }

// 获取下一个装饰器
        Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

// 执行装饰器
if (interceptorOrInterceptionAdvice instanceof MethodInterceptor) {
            MethodInterceptor mi = (MethodInterceptor) interceptorOrInterceptionAdvice;
return mi.invoke(this);  // 递归调用
        } else {
// 动态方法匹配器
return invokeJoinpoint();
        }
    }
}

配置与使用

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
@EnableTransactionManagement
@EnableCaching
publicclassAopConfig{

@Bean
public TransactionInterceptor transactionInterceptor(
            PlatformTransactionManager transactionManager)
{
returnnew TransactionInterceptor(transactionManager, 
new AnnotationTransactionAttributeSource());
    }

@Bean
public CacheInterceptor cacheInterceptor(
            CacheManager cacheManager, KeyGenerator keyGenerator)
{
returnnew CacheInterceptor(cacheManager, keyGenerator);
    }

@Bean
public PerformanceMonitorInterceptor performanceMonitorInterceptor(){
returnnew PerformanceMonitorInterceptor();
    }

@Bean
public Advisor transactionAdvisor(TransactionInterceptor interceptor){
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");

        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);
        advisor.setOrder(Ordered.HIGHEST_PRECEDENCE);

return advisor;
    }

@Bean
public Advisor cacheAdvisor(CacheInterceptor interceptor){
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("@annotation(org.springframework.cache.annotation.Cacheable) || " +
"@annotation(org.springframework.cache.annotation.CacheEvict)");

        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);
        advisor.setOrder(Ordered.LOWEST_PRECEDENCE);

return advisor;
    }

@Bean
public Advisor performanceAdvisor(PerformanceMonitorInterceptor interceptor){
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* com.example.service.*.*(..))");

        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        advisor.setPointcut(pointcut);
        advisor.setAdvice(interceptor);

return advisor;
    }
}

应用3:Servlet Filter Chain - Web请求的装饰器链

设计洞察

Servlet Filter是HTTP请求处理管道中的装饰器,每个Filter都可以在请求到达Servlet之前和响应返回客户端之后添加处理逻辑。

源码解析

// 🍃 组件:HttpServletRequest/HttpServletResponse
publicinterfaceHttpServletRequest{
// 原始请求接口
}

publicinterfaceHttpServletResponse{
// 原始响应接口
}

// 🎨 装饰器接口:Filter
publicinterfaceFilter{
voidinit(FilterConfig filterConfig)throws ServletException;

voiddoFilter(ServletRequest request, ServletResponse response, 
                  FilterChain chain)
throws IOException, ServletException
;

voiddestroy();
}

// 🌈 具体装饰器1:认证过滤器
@Component
@Order(1)  // 最先执行
publicclassAuthenticationFilterextendsOncePerRequestFilter{

privatefinal AuthenticationService authService;
privatefinal JwtTokenProvider tokenProvider;

publicAuthenticationFilter(AuthenticationService authService, 
                               JwtTokenProvider tokenProvider)
{
this.authService = authService;
this.tokenProvider = tokenProvider;
    }

@Override
protectedvoiddoFilterInternal(HttpServletRequest request,
                                   HttpServletResponse response,
                                   FilterChain filterChain)

throws ServletException, IOException 
{

// 1. 从请求中提取Token
        String token = extractToken(request);

if (token == null) {
// 无Token,继续下一个过滤器(可能是公开接口)
            filterChain.doFilter(request, response);
return;
        }

// 2. 验证Token
if (!tokenProvider.validateToken(token)) {
            sendError(response, HttpStatus.UNAUTHORIZED, "Token无效或已过期");
return;
        }

// 3. 获取用户信息
        String username = tokenProvider.getUsernameFromToken(token);
        UserDetails userDetails = authService.loadUserByUsername(username);

if (userDetails == null) {
            sendError(response, HttpStatus.UNAUTHORIZED, "用户不存在");
return;
        }

// 4. 设置认证信息到SecurityContext
        UsernamePasswordAuthenticationToken authentication = 
new UsernamePasswordAuthenticationToken(userDetails, null
                userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);

// 5. 继续过滤器链
        filterChain.doFilter(request, response);

// 6. 请求处理完成后清理(后处理)
        SecurityContextHolder.clearContext();
    }

private String extractToken(HttpServletRequest request){
        String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
        }
returnnull;
    }
}

// 🌈 具体装饰器2:日志过滤器
@Component
@Order(2)
publicclassRequestLoggingFilterextendsOncePerRequestFilter{

privatestaticfinal Logger logger = LoggerFactory
        .getLogger(RequestLoggingFilter.class);

@Override
protectedvoiddoFilterInternal(HttpServletRequest request,
                                   HttpServletResponse response,
                                   FilterChain filterChain)

throws ServletException, IOException 
{

long startTime = System.currentTimeMillis();
        String requestId = UUID.randomUUID().toString();

// 包装请求和响应以便多次读取
        ContentCachingRequestWrapper wrappedRequest = 
new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper wrappedResponse = 
new ContentCachingResponseWrapper(response);

// 记录请求开始
        logRequestStart(wrappedRequest, requestId);

try {
// 继续过滤器链
            filterChain.doFilter(wrappedRequest, wrappedResponse);

// 记录请求完成
long duration = System.currentTimeMillis() - startTime;
            logRequestComplete(wrappedRequest, wrappedResponse, requestId, duration);

        } finally {
// 确保响应内容被复制回原始响应
            wrappedResponse.copyBodyToResponse();
        }
    }

privatevoidlogRequestStart(HttpServletRequest request, String requestId){
        MDC.put("requestId", requestId);

        logger.info("请求开始: {} {}, 客户端IP: {}, User-Agent: {}"
            request.getMethod(), request.getRequestURI(),
            request.getRemoteAddr(), request.getHeader("User-Agent"));

// 记录请求体(如果是可读的内容类型)
        String contentType = request.getContentType();
if (contentType != null && contentType.contains("application/json")) {
            String requestBody = getRequestBody(request);
if (StringUtils.hasText(requestBody)) {
                logger.debug("请求体: {}", requestBody);
            }
        }
    }
}

// 🌈 具体装饰器3:响应压缩过滤器
@Component
@Order(Ordered.LOWEST_PRECEDENCE)  // 最后执行
publicclassGzipCompressionFilterextendsOncePerRequestFilter{

@Override
protectedvoiddoFilterInternal(HttpServletRequest request,
                                   HttpServletResponse response,
                                   FilterChain filterChain)

throws ServletException, IOException 
{

// 检查客户端是否支持gzip
        String acceptEncoding = request.getHeader("Accept-Encoding");
boolean supportsGzip = acceptEncoding != null && 
            (acceptEncoding.contains("gzip") || acceptEncoding.contains("deflate"));

if (!supportsGzip) {
// 客户端不支持压缩,直接继续
            filterChain.doFilter(request, response);
return;
        }

// 包装响应以支持压缩
        GzipResponseWrapper gzipResponse = new GzipResponseWrapper(response);

try {
            filterChain.doFilter(request, gzipResponse);
        } finally {
            gzipResponse.finish();
        }
    }

// 压缩包装器
privatestaticclassGzipResponseWrapperextendsHttpServletResponseWrapper{
private GZIPOutputStream gzipOutputStream;
private ServletOutputStream servletOutputStream;
private PrintWriter printWriter;

publicGzipResponseWrapper(HttpServletResponse response)throws IOException {
super(response);
            response.setHeader("Content-Encoding""gzip");
        }

@Override
public ServletOutputStream getOutputStream()throws IOException {
if (this.servletOutputStream == null) {
this.servletOutputStream = new FilterServletOutputStream(
new GZIPOutputStream(super.getOutputStream())
                );
            }
returnthis.servletOutputStream;
        }

publicvoidfinish()throws IOException {
if (this.gzipOutputStream != null) {
this.gzipOutputStream.finish();
            }
        }
    }
}

Filter Chain执行机制

// Spring的FilterChain实现
publicclassFilterChainProxyextendsGenericFilterBean{

private List<SecurityFilterChain> filterChains;

@Override
publicvoiddoFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain)
throws IOException, ServletException 
{

// 获取当前请求匹配的过滤器链
        List<Filter> filters = getFilters(request);

if (filters == null || filters.size() == 0) {
// 无过滤器,直接继续
            chain.doFilter(request, response);
return;
        }

// 创建虚拟过滤器链
        VirtualFilterChain virtualFilterChain = 
new VirtualFilterChain(chain, filters);

// 执行过滤器链
        virtualFilterChain.doFilter(request, response);
    }

// 虚拟过滤器链:按顺序执行所有过滤器
privatestaticclassVirtualFilterChainimplementsFilterChain{
privatefinal FilterChain originalChain;
privatefinal List<Filter> additionalFilters;
privateint currentPosition = 0;

publicVirtualFilterChain(FilterChain chain, List<Filter> additionalFilters){
this.originalChain = chain;
this.additionalFilters = additionalFilters;
        }

@Override
publicvoiddoFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException 
{

if (this.currentPosition == this.additionalFilters.size()) {
// 所有过滤器执行完毕,执行原始链
this.originalChain.doFilter(request, response);
            } else {
// 执行下一个过滤器
this.currentPosition++;
                Filter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
                nextFilter.doFilter(request, response, this);
            }
        }
    }
}

⚖️ 装饰器模式与其他模式的对比

装饰器 vs 代理模式

维度
🎨 装饰器模式 (Decorator)
🎭 代理模式 (Proxy)
设计目的增强功能
:动态添加新职责
控制访问
:控制对原始对象的访问
关注点
对象的功能增强
对象的访问控制和生命周期管理
关系类型
装饰器和组件是同一类型(is-a)
代理和真实对象是不同对象
创建时机
运行时动态创建
编译时或运行时创建
透明性
对客户端半透明,知道被装饰
对客户端透明,不知道代理存在
Spring示例BeanPostProcessor
MethodInterceptor
ProxyFactory
JdkDynamicAopProxy
典型应用
日志、缓存、事务、性能监控
远程代理、虚拟代理、保护代理

装饰器 vs 适配器模式

维度
🎨 装饰器模式
🔌 适配器模式
目的增强功能
,不改变接口
转换接口
,使不兼容的接口协同工作
接口变化
保持接口不变
改变接口以适应客户端
对象关系
装饰对象和被装饰对象是相同类型
适配器和被适配对象是不同类型
设计阶段
设计时考虑的功能扩展
集成现有系统时的补救措施

装饰器 vs 责任链模式

维度
🎨 装饰器模式
⛓️ 责任链模式
结构
嵌套包装,内层调用外层
线性传递,处理器依次尝试处理
执行顺序
固定的包装顺序
可变的处理顺序
停止条件
必须到达最内层原始对象
任一处理器处理完成即可停止
典型应用
Filter链、AOP拦截器链
审批流程、异常处理链

📊 Spring装饰器模式应用全景

应用场景
装饰器接口
具体装饰器实现
装饰功能
执行时机
Bean生命周期BeanPostProcessorAutowiredAnnotationBeanPostProcessor
自动注入依赖
Bean初始化前后
AOP增强MethodInterceptorTransactionInterceptor
事务管理
方法调用前后
缓存管理MethodInterceptorCacheInterceptor
缓存读取/写入
方法调用前后
Servlet处理FilterAuthenticationFilter
身份认证
请求到达Servlet前后
响应处理ResponseBodyAdviceResponseWrapperAdvice
响应包装/加密
响应返回前
消息处理MessageListenerAdapterMessagingInterceptor
消息转换/验证
消息处理前后
事件处理ApplicationListenerTransactionalEventListener
事务事件处理
事件发布后

🎯 装饰器模式的优势与最佳实践

设计优势

  1. 开闭原则:无需修改现有代码即可添加新功能
  2. 单一职责:每个装饰器只关注一个横切关注点
  3. 运行时灵活性:装饰器可以在运行时动态组合
  4. 避免类爆炸:相比继承,组合方式更加灵活
  5. 可逆性:装饰器可以按需添加或移除

最佳实践

  1. 保持装饰器轻量级:每个装饰器应只负责单一功能
  2. 注意装饰顺序:某些装饰器有执行顺序要求(如事务装饰器应在最外层)
  3. 避免循环装饰:防止装饰器相互包装导致无限递归
  4. 考虑性能影响:过多的装饰器会影响性能,需合理设计
  5. 提供配置选项:允许通过配置启用/禁用特定装饰器

Spring中的最佳实践

// 1. 合理设置装饰器顺序
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)  // 高优先级装饰器
publicclassValidationDecoratorimplementsBeanPostProcessor{ }

@Component
@Order(Ordered.LOWEST_PRECEDENCE)   // 低优先级装饰器
publicclassLoggingDecoratorimplementsBeanPostProcessor{ }

// 2. 使用条件装饰
@Component
@ConditionalOnProperty(name = "app.feature.caching", havingValue = "true")
publicclassCachingDecoratorimplementsBeanPostProcessor{ }

// 3. 避免过早初始化
@Configuration
publicclassDecoratorConfig{

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)  // 标记为基础设施Bean
publicstatic MyBeanPostProcessor myBeanPostProcessor(){
returnnew MyBeanPostProcessor();  // 静态方法避免循环依赖
    }
}

// 4. 使用组合装饰器
@Component
publicclassCompositeDecoratorimplementsBeanPostProcessor{

privatefinal List<BeanPostProcessor> decorators;

publicCompositeDecorator(List<BeanPostProcessor> decorators){
this.decorators = decorators.stream()
            .filter(decorator -> decorator != this)  // 排除自身
            .collect(Collectors.toList());
    }

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName){
        Object result = bean;
for (BeanPostProcessor decorator : decorators) {
            result = decorator.postProcessBeforeInitialization(result, beanName);
        }
return result;
    }
}

🚨 常见陷阱与解决方案

陷阱1:装饰器顺序问题

// ❌ 错误:事务装饰器在内层,日志在外层
// 如果事务回滚,日志仍然会记录"操作成功"
@Order(1)
publicclassLoggingDecoratorimplementsMethodInterceptor{
public Object invoke(MethodInvocation invocation)throws Throwable {
        logger.info("开始执行");
try {
            Object result = invocation.proceed();
            logger.info("执行成功");  // 事务回滚时这里仍然会执行!
return result;
        } catch (Exception e) {
            logger.error("执行失败", e);
throw e;
        }
    }
}

@Order(2)  // 顺序错误
publicclassTransactionDecoratorimplementsMethodInterceptor{
public Object invoke(MethodInvocation invocation)throws Throwable {
        TransactionStatus status = transactionManager.begin();
try {
return invocation.proceed();
        } catch (Exception e) {
            transactionManager.rollback(status);  // 回滚事务
throw e;
        }
    }
}

// ✅ 正确:事务装饰器在外层,日志在内层
@Order(1)  // 高优先级,先执行
publicclassTransactionDecoratorimplementsMethodInterceptor{
public Object invoke(MethodInvocation invocation)throws Throwable {
        TransactionStatus status = transactionManager.begin();
try {
return invocation.proceed();  // 调用内层的日志装饰器
        } catch (Exception e) {
            transactionManager.rollback(status);
throw e;
        }
    }
}

@Order(2)  // 低优先级,后执行
publicclassLoggingDecoratorimplementsMethodInterceptor{
public Object invoke(MethodInvocation invocation)throws Throwable {
        logger.info("开始执行");
try {
            Object result = invocation.proceed();  // 调用原始方法
            logger.info("执行成功");
return result;
        } catch (Exception e) {
            logger.error("执行失败", e);
throw e;
        }
    }
}

陷阱2:装饰器循环依赖

// ❌ 错误:装饰器相互依赖导致循环
@Component
publicclassDecoratorAimplementsBeanPostProcessor{
@Autowired
private DecoratorB decoratorB;  // 循环依赖!

@Override
public Object postProcessAfterInitialization(Object bean, String beanName){
// 使用decoratorB...
return bean;
    }
}

@Component
publicclassDecoratorBimplementsBeanPostProcessor{
@Autowired
private DecoratorA decoratorA;  // 循环依赖!

@Override
public Object postProcessAfterInitialization(Object bean, String beanName){
// 使用decoratorA...
return bean;
    }
}

// ✅ 正确:避免装饰器间的直接依赖
@Component
publicclassDecoratorAimplementsBeanPostProcessor{
// 不直接依赖其他装饰器
@Override
public Object postProcessAfterInitialization(Object bean, String beanName){
// 独立处理
return processA(bean);
    }
}

@Component
publicclassDecoratorBimplementsBeanPostProcessor{
// 不直接依赖其他装饰器
@Override
public Object postProcessAfterInitialization(Object bean, String beanName){
// 独立处理
return processB(bean);
    }
}

// 通过组合器管理执行顺序
@Component
publicclassDecoratorOrchestrator{
privatefinal List<BeanPostProcessor> decorators;

publicDecoratorOrchestrator(List<BeanPostProcessor> decorators){
// 按Order排序
this.decorators = decorators.stream()
            .sorted(AnnotationAwareOrderComparator.INSTANCE)
            .collect(Collectors.toList());
    }
}

🛠️ 实战练习

练习1:实现可配置的装饰器链

// 任务:创建一个可动态配置的装饰器框架
// 要求:
// 1. 支持通过配置文件启用/禁用特定装饰器
// 2. 支持自定义装饰器执行顺序
// 3. 支持装饰器条件执行(基于Bean类型、方法注解等)

@Configuration
@EnableConfigurationProperties(DecoratorProperties.class)
publicclassConfigurableDecoratorConfig
{

@Bean
public ConfigurableBeanPostProcessor configurableBeanPostProcessor(
            DecoratorProperties properties,
            List<Decorator> availableDecorators)
{

// 1. 根据配置筛选启用的装饰器
        List<Decorator> enabledDecorators = availableDecorators.stream()
            .filter(decorator -> isDecoratorEnabled(properties, decorator))
            .collect(Collectors.toList());

// 2. 按配置排序
        enabledDecorators.sort(Comparator.comparingInt(
            decorator -> getDecoratorOrder(properties, decorator)));

returnnew ConfigurableBeanPostProcessor(enabledDecorators);
    }

privatebooleanisDecoratorEnabled(DecoratorProperties properties, Decorator decorator){
        String decoratorName = decorator.getClass().getSimpleName();
return properties.getEnabledDecorators().contains(decoratorName);
    }
}

// 配置类
@ConfigurationProperties(prefix = "app.decorators")
@Data
publicclassDecoratorProperties{
private List<String> enabledDecorators = Arrays.asList(
"ValidationDecorator""LoggingDecorator""CachingDecorator");

private Map<String, Integer> decoratorOrders = new HashMap<>();

publicDecoratorProperties(){
        decoratorOrders.put("ValidationDecorator"100);
        decoratorOrders.put("TransactionDecorator"200);
        decoratorOrders.put("CachingDecorator"300);
        decoratorOrders.put("LoggingDecorator"400);
    }
}

// 配置文件 application.yml
app:
  decorators:
    enabled-decorators:
      - ValidationDecorator
      - TransactionDecorator
      - CachingDecorator
    decorator-orders:
      ValidationDecorator: 100
      TransactionDecorator: 200
      CachingDecorator: 300

练习2:装饰器性能监控

// 任务:监控装饰器的性能影响
// 要求:
// 1. 记录每个装饰器的执行时间
// 2. 统计装饰器命中率
// 3. 支持性能报告输出

@Component
publicclassDecoratorMetricsCollector{

privatefinal Map<String, DecoratorMetrics> metricsMap = new ConcurrentHashMap<>();

publicvoidrecordExecution(String decoratorName, long duration, boolean success){
        DecoratorMetrics metrics = metricsMap.computeIfAbsent(
            decoratorName, k -> new DecoratorMetrics());

        metrics.recordExecution(duration, success);
    }

public DecoratorReport generateReport(){
        DecoratorReport report = new DecoratorReport();

        metricsMap.forEach((decoratorName, metrics) -> {
            DecoratorStats stats = new DecoratorStats();
            stats.setTotalExecutions(metrics.getTotalExecutions());
            stats.setSuccessCount(metrics.getSuccessCount());
            stats.setAverageDuration(metrics.getAverageDuration());
            stats.setP95Duration(metrics.getPercentileDuration(95));
            stats.setP99Duration(metrics.getPercentileDuration(99));

            report.addDecoratorStats(decoratorName, stats);
        });

return report;
    }

// 装饰器包装器:自动收集指标
publicstaticclassMonitoringDecoratorWrapperimplementsBeanPostProcessor{

privatefinal BeanPostProcessor delegate;
privatefinal DecoratorMetricsCollector metricsCollector;

publicMonitoringDecoratorWrapper(BeanPostProcessor delegate,
                                         DecoratorMetricsCollector metricsCollector)
{
this.delegate = delegate;
this.metricsCollector = metricsCollector;
        }

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName){
long startTime = System.nanoTime();
try {
                Object result = delegate.postProcessBeforeInitialization(bean, beanName);
long duration = System.nanoTime() - startTime;
                metricsCollector.recordExecution(delegate.getClass().getSimpleName(), 
                    duration, true);
return result;
            } catch (Exception e) {
long duration = System.nanoTime() - startTime;
                metricsCollector.recordExecution(delegate.getClass().getSimpleName(), 
                    duration, false);
throw e;
            }
        }
    }
}

📈 性能优化建议

1. 懒加载装饰器

@Component
publicclassLazyDecoratorimplementsBeanPostProcessorSmartInitializingSingleton{

privatevolatileboolean initialized = false;
privatefinal Object lock = new Object();

@Override
public Object postProcessAfterInitialization(Object bean, String beanName){
if (!initialized) {
synchronized (lock) {
if (!initialized) {
// 延迟初始化装饰器资源
                    initializeDecorator();
                    initialized = true;
                }
            }
        }

// 执行装饰逻辑
return decorate(bean);
    }

@Override
publicvoidafterSingletonsInstantiated(){
// 所有单例Bean初始化完成后执行
        preWarmDecoratorCache();
    }
}

2. 装饰器缓存

@Component
publicclassCachingDecoratorimplementsBeanPostProcessor{

privatefinal CacheManager cacheManager;
privatefinal Map<Class<?>, Boolean> decoratorCache = new ConcurrentHashMap<>();

@Override
public Object postProcessAfterInitialization(Object bean, String beanName){
        Class<?> beanClass = bean.getClass();

// 检查缓存
        Boolean shouldDecorate = decoratorCache.get(beanClass);
if (shouldDecorate == null) {
// 计算是否需要装饰(可能较耗时)
            shouldDecorate = shouldDecorate(bean);
            decoratorCache.put(beanClass, shouldDecorate);
        }

if (shouldDecorate) {
return doDecorate(bean);
        }

return bean;
    }
}

3. 并行装饰

@Component
publicclassParallelDecoratorimplementsBeanPostProcessor{

privatefinal ExecutorService executor = Executors.newFixedThreadPool(
        Runtime.getRuntime().availableProcessors());

@Override
public Object postProcessAfterInitialization(Object bean, String beanName){
        List<Callable<Object>> tasks = createDecorationTasks(bean);

try {
// 并行执行独立的装饰任务
            List<Future<Object>> futures = executor.invokeAll(tasks);

// 合并装饰结果
            Object result = bean;
for (Future<Object> future : futures) {
                result = future.get();
            }
return result;
        } catch (InterruptedException | ExecutionException e) {
thrownew BeanCreationException("装饰器执行失败", e);
        }
    }
}

🎯 关键要点总结

  1. 动态增强:装饰器模式允许在运行时动态添加功能
  2. 开闭原则:无需修改现有代码即可扩展功能
  3. 组合优于继承:通过组合实现功能的灵活叠加
  4. 透明包装:装饰器和被装饰对象实现相同接口
  5. Spring应用BeanPostProcessor、AOP拦截器、Servlet Filter都是装饰器模式的实现
  6. 装饰器链:多个装饰器可以形成链式调用,注意执行顺序
  7. 性能考量:合理设计装饰器,避免过度装饰影响性能

📚 扩展学习资源

推荐阅读

  1. Spring官方文档

    • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanPostProcessor.html
    • https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/aopalliance/intercept/MethodInterceptor.html
    • https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop
  2. 设计模式进阶

    • 《设计模式:可复用面向对象软件的基础》- 装饰器模式章节
    • 《Head First设计模式》- 装饰对象章节
    • 《Effective Java》- 组合优于继承原则
  3. 相关设计模式

    • 代理模式(控制访问)
    • 适配器模式(接口转换)
    • 责任链模式(处理链传递)

实践项目建议

  1. 自定义注解处理器:实现类似@Transactional的自定义注解装饰器
  2. 插件化系统:基于装饰器模式实现可插拔的功能模块
  3. 中间件开发:实现类似Filter的请求处理装饰器链
  4. 监控系统:为应用添加可配置的性能监控装饰器

🚀 下一步:外观模式

掌握了装饰器模式的动态增强能力后,接下来可以学习外观模式,它关注如何为复杂的子系统提供统一的简化接口

👉 12.外观模式 (Facade Pattern) - Spring案例:为复杂的子系统提供一个统一的接口,使子系统更易于使用。

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-05-14 14:44:38 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/593961.html
  2. 运行时间 : 0.184370s [ 吞吐率:5.42req/s ] 内存消耗:4,946.00kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=91e9b99383005b500c82c37348f8eedd
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000619s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000780s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000341s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.002127s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000777s ]
  6. SELECT * FROM `set` [ RunTime:0.000271s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000792s ]
  8. SELECT * FROM `article` WHERE `id` = 593961 LIMIT 1 [ RunTime:0.000748s ]
  9. UPDATE `article` SET `lasttime` = 1778741078 WHERE `id` = 593961 [ RunTime:0.039849s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000482s ]
  11. SELECT * FROM `article` WHERE `id` < 593961 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000675s ]
  12. SELECT * FROM `article` WHERE `id` > 593961 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.036362s ]
  13. SELECT * FROM `article` WHERE `id` < 593961 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.000965s ]
  14. SELECT * FROM `article` WHERE `id` < 593961 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001348s ]
  15. SELECT * FROM `article` WHERE `id` < 593961 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.003513s ]
0.188357s