zoukankan      html  css  js  c++  java
  • Spring同一个类中注解方法互相调用的问题

        在使用Spring时,很多初学者不了解Spring对象注入的机制和面向切面编程的原理,很容易犯一些错误。下面就是初学者最容易犯的错误。举例如下:

    @Component

    public class TestClass {
        private Random random = new Random();
        @Cacheable("cache1")
        public String getData(String key){
            System.out.println("load data from file, key = " + key);
            return  key + key;
        }
        @Scheduled(fixedDelay = 100)
        public void task(){
            int rand = random.nextInt(100);
            String strParam = String.format("%d", rand);
            String str = getData(strParam);
            System.out.println("result is " + str);
        }
    }

        这里TestClass类里同时启用了Scheduled注解和@Cacheable注解。如果在外面其他类中调用getData(...)时,缓存机制会生效,但是在task函数内部调用getData(...)时,缓存机制不会生效。网上有人把这归纳为:不能在同一个类中互相调用注解过的方法,否则注解失效。

        为什么会有这样的差别呢?背后的原因就是Spring的对象注入机制。

        当外部通过@Autowired注解得到一个TestClass对象时,其实得到的是一个Spring包装过的代理对象。如下图所示。 

        当调用Obj.getData时,实际调用的是Spring的Proxy对象中的getData方法,该方法内置了Cache机制,在Cache检查后就会调用实际的TestClass对象中的getData方法。

        同理通过@Scheduled注解表示这是一个任务调度时,Spring Proxy对象中会初始化对应的调度线程池等工作,当触发调度条件时,再调用实际的TestClass对象。

        但是当在实际的TestClass对象中再调用getData时,不会触发Cache机制,因为此时不是调用的SpringCacheProxy对象,而是一个实际的TestClass对象,所以不会触发Cache机制。

        如果大家深入去读Spring完成注入和AOP编程实现的原理,可以发现动态代理是很重要的一个技术。目前Spring的动态代理主要是通过CGLib来实现的。后面我会再写CGLib的实现思路。

        那么我们该如何避免出现上述问题呢?

        首先我们应该牢记一个原则:同一个类中的注解方法互相调用时,注解机制可能是无效的。

        对于上述示例,我们可以把其拆分为两个类来实现,一个类完成任务调度、一个类完成Cache机制。这样在任务调度中调用的是Spring实现了Cache机制的代理类,可以确保其Cache机制生效。

  • 相关阅读:
    RedisUtil
    CSS基础知识点笔记
    fdgfgfgfgf
    PerfMon Metrics Collector插件的Disks I/O使用总结
    Jmeter使用笔记之html报告扩展(一)
    Jmeter使用笔记之意料之外的
    Jmeter使用笔记之函数
    Jmeter使用笔记之组件的作用域
    css 初始化文件 全面
    vue-grid-layout 使用以及各项参数作用
  • 原文地址:https://www.cnblogs.com/shuzl/p/5304762.html
Copyright © 2011-2022 走看看