SpringBoot 自定义注解的增强使用方式,动态调用指定方法

摘要:我们平常使用自定义注解大多数都是配合AOP来使用的,本文给大家带来其他的使用方式,可做到无侵入式动态调用指定的方法;更复杂的使用方式自己挖掘。

案例简要说明

按照前端传入的参数,后端动态调用打印方法来执行实际的逻辑

编码

定义注解

less 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Print {

    String value();

}

扫描注解的方法

CommandLineRunner是在服务启动完成后再执行任务,该案例是调用不传参的方法,如果传参则需要定义好,否则反射调用会报错。

typescript 复制代码
@Slf4j
@Component
public class PrintContextHandler implements CommandLineRunner {

    @Autowired
    private ApplicationContext applicationContext;

    private Map<String,Runnable> printMethodMap = new HashMap<>();

    @Override
    public void run(String... args) throws Exception {
        Map<String, Object> beans = applicationContext.getBeansWithAnnotation(Component.class);
        beans.putAll(applicationContext.getBeansWithAnnotation(Service.class));
        for (Object bean : beans.values()) {
            Method[] methods = bean.getClass().getDeclaredMethods();
            for (Method method : methods) {
                Print print = AnnotationUtils.findAnnotation(method, Print.class);
                if (print != null) {
                    Runnable runnable = new Runnable() {
                        @Override
                        public void run() {
                            try{
                                method.invoke(bean);
                            }catch (Exception ex){
                                log.error("print执行失败",ex);
                            }
                        }
                    };
                    printMethodMap.put(print.value(), runnable);
                }
            }
        }

    }

    /**
     * 执行
     * @param key
     * @return
     */
    public Object doPrint(String key){
        Runnable runnable = printMethodMap.get(key);
        if(null != runnable){
            runnable.run();
        }
        return "SUCCESS";
    }



}

定义注解的方法

typescript 复制代码
@Slf4j
@Service
public class InPrintService {

    @Print(value = "inPrint01")
    public String inPrint01(){
        log.info("inPrint01");
        return "inPrint01";
    }

    @Print(value = "inPrint02")
    public String inPrint02(){
        log.info("inPrint02,param1=");
        return "inPrint02";
    }
}
  • 方法2
less 复制代码
@Slf4j
@Service
public class OutPrintService {

    @Print(value = "outPrint01")
    public String outPrint01(){
        log.info("outPrint01");
        return "outPrint01";
    }

}

控制器

less 复制代码
@RequestMapping(value = "print")
@RestController
public class PrintController {

    @Autowired
    private PrintContextHandler printContextHandler;

    @GetMapping(value = "testPrintAnno")
    public Object testPrintAnno(String key){
        return printContextHandler.doPrint(key);
    }

}

测试结果

相关推荐
野生程序员y9 分钟前
spring容器的bean是单例还是多例的?线程安全吗?
java·后端·spring
星辰大海的精灵25 分钟前
Java 线程池的工作原理及实践
java·后端·架构
满分观察网友z28 分钟前
从选择困难到最优策略:我如何用DP搞定“鱼和熊掌兼得”的排程难题(1751. 最多可以参加的会议数目 II)
后端·算法
我命由我1234533 分钟前
Spring Boot - Spring Boot 集成 MyBatis 分页实现 手写 SQL 分页
java·spring boot·后端·sql·spring·java-ee·mybatis
天天摸鱼的java工程师1 小时前
每天导入100万数据导致数据库死锁?
java·后端·面试
Xxtaoaooo1 小时前
手撕Spring底层系列之:IOC、AOP
java·后端·spring·spring框架·底层源码剖析
Penge6661 小时前
Lucene 索引文件结构
后端
胡gh1 小时前
线程与进程:从零开始理解它们的区别与联系
前端·javascript·后端
满分观察网友z1 小时前
从“最短响应路径”到二叉树最小深度:一个Bug引发的BFS探险之旅(111. 二叉树的最小深度)
后端·算法
LaoZhangAI2 小时前
Sora Image API完全指南2025,平替gpt-image-1 API
前端·后端