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机制生效。

  • 相关阅读:
    11.11 ntsysv:管理开机服务
    11.13 ethtool:查询网卡参数
    11.14 mii-tool:管理网络接口的状态
    11.15 dmidecode:查询系统硬件信息
    11.16-18 lsci、ipcs、ipcrm:清除ipc相关信息
    Devops 导论
    * SPOJ PGCD Primes in GCD Table (需要自己推线性筛函数,好题)
    SPOJ
    HDU 1695 莫比乌斯反演
    HDU 1800 hash 找出现最多次数的字符串的次数
  • 原文地址:https://www.cnblogs.com/shuzl/p/5304762.html
Copyright © 2011-2022 走看看