• 【转】Controller中为什么不能写@Transactional


    Controller中为什么不能写@Transactional
    原文链接:http://sunbingbing.cn/controller中为什么不能写transactional/

    1.背景

    Controller指SpringMVC项目中用于定义接口信息的类,该类一般会被@Controller或@RestController等SpringMVC相关注解标记;
    @Transactional指spring-tx包中定义的事务注解,被该注解标记的方法或类将成为一个整体,“同进同退”;
    在开发过程中,注解是我们的神兵利器,但如果不恰当的使用将会造成严重的问题。

    2.问题

    • 在Controller层的接口定义处添加@Transactional
    • 对Controller层进行统一代理,添加公共校验等拦截
    • 添加过@Transactional的Controller接口失效,请求返回404

    3.解决方案
    方案一:调整@Transactional到service层
    方案二:添加cglib依赖,指定强制使用cglib代理

    4.问题分析

    • 从@Transactional入手分析;Spring在扫描bean 的时候,发现某些类或方法上添加了事务注解,就会生成该类的代理类,并赋予代理类事务的相关逻辑,从而达到事务效果;我们在实际调用中,调用的是对应的代理类而非其本身。

    • 从Controller层代理入手分析;通过相关工具类例如BeanNameAutoProxyCreater对controller进行统一代理,并插入统一的校验逻辑,达到快速开发的目的;同样的在实际调用中,我们调用到的也是其对应的代理类而非其本身。

    *从代理方面入手分析;SpringAOP部分主要使用JDK动态代理或cglib代理;默认情况下,如果被代理的目标对象实现了至少一个接口,则会使用jdk动态代理,否则会通过cglib创建代理类,但也可以通过设置强制使用cglib进行代理操作。

    *结合以上分析,404的Controller被代理了两次,因controller没有实现接口,所以第一次代理一定是cglib代理;因设置强制使用cglib代理可解决404问题反推,第二次代理一定是jdk动态代理;结合以上推测,第二次jdk动态代理时可能导致@RequestMapping等注解失效,最终造成404问题。

    5.相关问题
    本次问题的引发原因是对现有工程新增统一验证逻辑导致,同步发现的问题还有Controller中的自动注入失败,导致执行service中逻辑时报404;原因时Controller中方法为private,private的方法不会被代理,导致引用的service属性没有完成注入。

    6.开发规范

    • Controller中不要添加@Transactional等注解,该类注解一律放到service中;
    • Controller中被定义为接口的方法不要定义为private

    7.加buffer

    public static void main(String[] args){
        //生成代理类的class文件到工程根目录
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
      //生成cglib代理的class文件到指定目录
    System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"e:\cglib");
        SpringApplication.run(Application.class);
    }
    
  • 相关阅读:
    HDU 2276
    HDU 2254
    HDU 1536 & 1944
    HDU 1538
    HDU 2177
    HDU 2176
    HDU 1209
    HDU 1254
    c++ 11 default delete
    ssh免密登录
  • 原文地址:https://www.cnblogs.com/pipicai96/p/13953923.html
Copyright © 2020-2023  润新知