使用自定义注解和@Aspect实现责任链模式的组件增强的详细代码

 更新时间:2023年05月21日 09:25:59   作者:程序员的思考与落地  
责任链模式是一种行为设计模式,其作用是将请求的发送者和接收者解耦,从而可以灵活地组织和处理请求,本文讲给大家介绍如何使用自定义注解和@Aspect实现责任链模式的组件增强,文中有详细的代码示例供大家参考,感兴趣的同学可以借鉴一下

责任链模式

责任链模式是一种行为设计模式,其作用是将请求的发送者和接收者解耦,从而可以灵活地组织和处理请求。它通过将请求沿着一个由多个处理器组成的链路进行传递和处理,直到有一个处理器能够处理该请求或者链路的末端。

该模式的主要作用是:

  • 解耦请求发送者和接收者:责任链模式将发送者和接收者解耦,发送者无需知道具体是哪个接收者来处理请求,接收者也无需知道请求的发送者是谁,从而提高系统的灵活性和可维护性。

  • 动态组织和处理请求:责任链模式可以动态地组织和处理请求,可以根据实际情况灵活地调整链路上的处理器顺序和数量,实现不同的业务逻辑和处理策略。

  • 避免请求的硬编码:责任链模式通过配置和链路的方式来处理请求,避免了请求的硬编码,使得系统更易于扩展和维护。

应用场景:

  • 请求的处理涉及多个环节或多个对象:当一个请求需要经过多个处理环节或者多个对象来处理时,可以使用责任链模式。例如,请求的处理需要经过验证、日志记录、缓存等多个处理器进行处理。

  • 动态选择处理器:当处理器的选择和顺序需要根据实际情况进行动态调整时,可以使用责任链模式。例如,根据请求的类型或者优先级来动态选择处理器。

  • 需要对请求进行过滤或拦截的场景:当需要对请求进行过滤、拦截或者根据条件决定是否进行处理时,可以使用责任链模式。例如,对请求进行权限验证、安全检查、数据校验等操作。

  • 减少耦合,提高系统的灵活性和可维护性:当需要降低发送者和接收者之间的耦合度,以及提高系统的灵活性和可维护性时,可以考虑使用责任链模式。

总之,责任链模式适用于处理请求链路较长、处理器之间松耦合、需要动态组织和处理请求的场景。它可以帮助我们实现更灵活、可扩展和可维护的系统设计。

实践案例

下面结合自定义注解和@Aspect,我们可以实现对组件的增强,使其具备责任链模式的功能。

首先,我们需要定义一个自定义注解,用于标识需要应用责任链模式的方法或类。可以定义如下注解:

package com.example.demo.design.chain;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyChain {}

接下来,我们使用@Aspect注解创建一个切面类,在切面类中实现责任链模式的逻辑。可以定义如下切面类

package com.example.demo.design.chain;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;

@Aspect
@Component
public class ChainHandlerAspect implements InitializingBean {
    @Autowired
    // 注入所有实现ChainHandler接口的责任链处理器
    private List<ChainHandler> chainHandlers;

    // 责任链的头节点
    private ChainHandler chainHandler;

    @Around("@annotation(com.example.demo.design.chain.MyChain)")
    public Object checkParam(ProceedingJoinPoint pjp) throws Throwable {
        Object[] args = pjp.getArgs(); // 获取方法的所有参数
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        Class<?>[] parameterTypes = method.getParameterTypes(); // 获取方法的参数类型列表

        for (int i = 0; i < parameterTypes.length; i++) {
            if (parameterTypes[i].getName().equals("java.lang.String")) {
                chainHandler.handle(new Request((String) args[0]));
            }
        }
        return pjp.proceed();
    }

    /**
     * 构建处理器链
     */
    private ChainHandler buildHandlerChain() {
        ChainHandler headChainHandler = null;
        ChainHandler currentChainHandler = null;
        for (ChainHandler chainHandler : chainHandlers) {
            if (headChainHandler == null) {
                headChainHandler = chainHandler;
                currentChainHandler = headChainHandler;
            } else {
                currentChainHandler.setNextHandler(chainHandler);
                currentChainHandler = chainHandler;
            }
        }
        return headChainHandler;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        // 构建责任链
        chainHandler = this.buildHandlerChain();
    }
}

责任链相关组件

处理器接口

package com.example.demo.design.chain;

public interface ChainHandler {
    void handle(Request request);

    void setNextHandler(ChainHandler handler);
}

处理器实现类

package com.example.demo.design.chain;

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(1)
public class FirstHandler implements ChainHandler {
    private ChainHandler nextHandler;

    @Override
    public void handle(Request request) {
        // 处理请求
        System.out.println("FirstHandler handling request " + request);

        // 将请求传递给下一个处理器
        if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }

    @Override
    public void setNextHandler(ChainHandler handler) {
        this.nextHandler = handler;
    }
}
package com.example.demo.design.chain;

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(2)
public class SecondHandler implements ChainHandler {
    private ChainHandler nextHandler;

    @Override
    public void handle(Request request) {
        // 处理请求
        System.out.println("SecondHandler handling request " + request);

        // 将请求传递给下一个处理器
        if (nextHandler != null) {
            nextHandler.handle(request);
        }
    }

    @Override
    public void setNextHandler(ChainHandler handler) {
        this.nextHandler = handler;
    }
}
package com.example.demo.design.chain;

import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(3)
public class ThirdHandler implements ChainHandler {
    private ChainHandler nextHandler;

    @Override
    public void handle(Request request) {
        // 处理请求
        System.out.println("ThirdHandler handling request " + request);
    }

    @Override
    public void setNextHandler(ChainHandler handler) {
        this.nextHandler = handler;
    }
}

以上代码是类同的,通过@Order注解指定了处理器的执行顺序,数字越小,优先级越高。

setNextHandler方法用于设置下一个处理器,接收一个ChainHandler对象作为参数,并将其保存在nextHandler字段中。

Request类

package com.example.demo.design.chain;

public class Request {
    private String data;

    public Request(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Request{" +
                "data='" + data + ''' +
                '}';
    }
}

业务代码组件

package com.example.demo.design.chain;

import org.springframework.stereotype.Component;

@Component
public class BizComponent {
    @MyChain
    public void process(String data) {
        System.out.println(data);
    }
}

@MyChain注解用于标记需要应用责任链模式的方法或类。

启动类

package com.example.demo.design.chain;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@EnableAspectJAutoProxy
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(com.example.demo.design.chain.Application.class, args);
    }
}

@EnableAspectJAutoProxy注解用于启用AspectJ自动代理功能,使得Spring能够识别和应用切面。

package com.example.demo.design.chain;

import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
@Data
public class ComponentRunner implements CommandLineRunner {

    @Autowired
    private BizComponent bizComponent;

    @Override
    public void run(String... args) throws Exception {
        // 执行某个方法(带Chain注解)
        bizComponent.process("Hello world!");
    }
}

该组件类的执行逻辑是在应用程序启动后自动执行的,可以根据实际需求,在run方法中编写适当的业务逻辑和处理流程。

主要是为了模拟发起请求,可以使用Controller访问的方式。

**执行效果 **

我们可以看到,在执行bizComponent.process("Hello world!")之前,我们已经被注解@MyChain进行增强处理了,所以会经过责任链进行前置处理。

总结

通过这种方式,我们可以灵活地扩展和定制责任链的处理逻辑,通过注解和AOP的方式将责任链与业务组件进行解耦,实现组件的增强和复用。

责任链模式的应用场景很广泛,例如在Web开发中,可以使用责任链模式来处理请求的拦截、验证、日志记录等操作;在工作流引擎中,可以使用责任链模式来实现任务的处理和流转;在事件驱动系统中,可以使用责任链模式来处理事件的触发和传递等等。

通过结合自定义注解和Spring的AOP功能,我们可以更加方便地应用责任链模式,并在开发过程中获得更高的可扩展性和灵活性。这种组件增强的方式使得责任链模式的实现更加简洁、可读性更高,同时也提升了代码的可维护性和可测试性。

总而言之,使用自定义注解和@Aspect实现责任链模式的组件增强,是一种强大的编程技巧,能够有效地将责任链的逻辑与业务组件解耦,提供了一种灵活且可扩展的方式来处理请求和逻辑链的处理。这种结合注解和AOP的方式,使得责任链模式的应用更加简单、优雅,为我们的开发工作带来了便利和效益。

以上就是使用自定义注解和@Aspect实现责任链模式的组件增强的详细代码的详细内容,更多关于自定义注解和@Aspect实现组件增强的资料请关注脚本之家其它相关文章!

相关文章

  • Netty实战源码解析NIO编程

    Netty实战源码解析NIO编程

    这篇文章主要为大家介绍了Netty实战源码解析NIO编程的核心组件及关系详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Java多线程编程中使用DateFormat类

    Java多线程编程中使用DateFormat类

    这篇文章主要介绍了Java多线程编程中使用DateFormat类,文中介绍了三种相关的并发使用方法,需要的朋友可以参考下
    2015-07-07
  • Java解决通信过程的中文乱码的问题

    Java解决通信过程的中文乱码的问题

    这篇文章主要介绍了 Java解决通信过程的中文乱码的问题的相关资料,需要的朋友可以参考下
    2017-01-01
  • 避免Java中的内存泄漏的三种方法

    避免Java中的内存泄漏的三种方法

    在Java开发中,内存泄漏(Memory Leak)是一个常见但令人头疼的问题,本文将深入探讨什么是内存泄漏、常见的泄漏原因、如何识别和避免内存泄漏,以及通过代码示例展示如何优化Java程序以减少内存泄漏的发生,需要的朋友可以参考下
    2024-07-07
  • 解决IDEA JSP没有代码提示问题的几种方法

    解决IDEA JSP没有代码提示问题的几种方法

    这篇文章主要介绍了解决IDEA JSP没有代码提示问题的几种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • 使用JWT作为Spring Security OAuth2的token存储问题

    使用JWT作为Spring Security OAuth2的token存储问题

    这篇文章主要介绍了使用JWT作为Spring Security OAuth2的token存储,大家经常使用的方法有两种一种是使用JWT作为Token传递,一种是使用Redis存储Token,资源服务器本地访问Redis校验Token,需要的朋友可以参考下
    2021-12-12
  • Spring Cloud Gateway重试机制的实现

    Spring Cloud Gateway重试机制的实现

    这篇文章主要介绍了Spring Cloud Gateway重试机制的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-03-03
  • SpringMVC中controller返回json数据的方法

    SpringMVC中controller返回json数据的方法

    这篇文章主要为大家详细介绍了SpringMVC中controller返回json数据的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • SpringBoot读取excel表格的示例代码

    SpringBoot读取excel表格的示例代码

    这篇文章主要介绍了SpringBoot读取excel表格的示例代码,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Maven下 mybatis-generator使用

    Maven下 mybatis-generator使用

    这篇文章主要介绍了Maven下 mybatis-generator使用 ,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-09-09

最新评论