Springboot内部类加注解失效的原因分析和解决方案

5 篇文章 0 订阅
1 篇文章 0 订阅

内部类注解失效原因

spring AOP 使用Java动态代理和 cglib 代理 来创建AOP代理,没有接口的类 使用cglib 代理。关于 spring aop 的java动态代理原理,请看这片博客:利用java 的动态代理模拟spring的AOP.
熟悉一下 aop 的原理注意看m.invoke(target, args); 部分(我们讨论的问题实际上就是m中调用同类的其他方法)。

我们知道当方法被代理时,其实是 动态生成了一个代理对象,代理对象去执行 invoke方法,在调用被代理对象的方法的时候执行了一些其他的动作。

所以当在被代理对象的方法中调用被代理对象的其他方法时。其实是没有用代理调用,是用了被代理对象本身调用的。

例如买票的例子:
当我门调用buyTrainTicket(Ticket ticket)方法时,spring 的动态代理已经帮我们动态生成了一个代理的对象,暂且我就叫他 $TicketService1。

所以调用buyTrainTicket(Ticket ticket) 方法实际上是代理对象 T i c k e t S e r v i c e 1 调 用 的 。 TicketService1调用的。 TicketService1TicketService1.buyTrainTicket(Ticket ticket)

但是在buyTrainTicket 方法内调用同一个类的另外一个注解方法sendMessage()时,实际上是this.sendMessage() 这个this 指的是TicketService 对象,并不是$TicketService1 代理对象,没有走代理。所以 注解失效。

————————————————
版权声明:本文为CSDN博主「双斜杠少年」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012373815/article/details/77345655

解决方案

方案一:新建获取代理对象的工具类SpringUtil,用该类调用方法

新建获取代理对象的工具类SpringUtil

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        if (SpringUtil.applicationContext == null) {
            SpringUtil.applicationContext = applicationContext;
        }
    }

    //获取applicationContext
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    //通过name获取 Bean.
    public static Object getBean(String name){
        return getApplicationContext().getBean(name);
    }

    //通过class获取Bean.
    public static <T> T getBean(Class<T> clazz){
        return getApplicationContext().getBean(clazz);
    }

    //通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name,Class<T> clazz){
        return getApplicationContext().getBean(name, clazz);
    }

}

修改范例

public class TicketService{
    //买火车票
    @Transactional
    public void buyTrainTicket(Ticket ticket){
        System.out.println("买到了火车票");
        try {

//通过代理对象去调用sendMessage()方法          
SpringUtil.getBean(this.getClass()).sendMessage();
        } catch (Exception  e) {
            logger.warn("发送消息异常");
        }
    }

    @Transactional
    public void sendMessage(){
        System.out.println("消息存入数据库");
        System.out.println("执行发送消息动作");
    }
}
————————————————
版权声明:本文为CSDN博主「双斜杠少年」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012373815/article/details/77345655

方案二:直接在类内部注入自身代理对象

@Lazy
@Autowired
private UserServiceImpl self;
 
@Transactional 
    public void hello(){
        System.out.println("开始hello"); 
        try {
             //通过注入的自身父类代理对象去调用saveUser()方法
            self.saveUser()
        } catch(Exception e) {
            logger.error("发送消息异常");
        }
    }
 
    @Transactional
    public void saveUser(){
        User user = new User();
        user.setName("zhangsan");
        System.out.println("将用户存入数据库");
    }

备注:为什么要用@Lazy?

Spring IoC (ApplicationContext) 容器一般都会在启动的时候实例化所有单实例 bean 。如果我们想要 Spring 在启动的时候延迟加载 bean,即在调用某个 bean 的时候再去初始化,那么就可以使用 @Lazy 注解。

发现需要B,查询字段b的所有注解,发现有@lazy注解,那么就不直接创建B了,而是使用动态代理创建一个代理类B1。

原因里说到是缺少代理对象,这里强制创建了代理对象,注解也自然就生效了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值