Spring Boot 在Controller使用@Transactional注解导致@RequestMapping失效

来源:互联网 发布:淘宝开店成功率 编辑:程序博客网 时间:2024/06/10 00:59

笔者在基于 Spring Boot 开发服务框架时,想要在 Controller 层使用 @Transactional 注解引入 Spring 的事务管理,但是却遇上了很奇葩的问题。

例如以下代码,给 Controller 类的add方法加上@Transactional,这个 Controller 类使用 @RestController 注解,类名上也配置了 @RequestMapping,

    @RequestMapping(KiEntityActionName.ACTION_ADD + URL_EXTENSION)    @Transactional(            value = KiDataSourceConfig.TRADE_TX_MANAGER,            timeout = 30,            isolation = Isolation.READ_COMMITTED,            propagation = Propagation.REQUIRED,            readOnly = false,            rollbackFor = Exception.class)    @Override    public Object add() {        Map<String, Object> params = new HashMap<>();        params.put("sellerId", 12);        params.put("buyerId", 2);        Object rtnData = this.bizService.execute(KiEntityActionEnum.ADD, params);        return rtnData;    }
然后启动应用程序,在控制台输出信息里,属于该类的所有 RequestMapping 全都不见了,正常应该出现如下信息,可以看到 "Mapped ****** " 等内容,表示使用@ReqeustMapping 配置的URL地址映射,但是该问题的奇葩之外在于,给任意方法加上 @Transactional 后,所有的映射就全部注入失败了,给整个类加上 @Transactional 也是同样问题,交换注解的顺序也没有用。

2017-11-21 17:32:00.431  INFO 3953 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@5f058f00: startup date [Tue Nov 21 17:31:58 CST 2017]; root of context hierarchy2017-11-21 17:32:00.487  INFO 3953 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/example/add.service]}" onto public java.lang.Object com.emulian.kiff.controller.KiExampleController.add()2017-11-21 17:32:00.487  INFO 3953 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/example/one.service]}" onto public java.lang.Object com.emulian.kiff.controller.KiExampleController.one()2017-11-21 17:32:00.488  INFO 3953 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/example/hello.service]}" onto public java.lang.String com.emulian.kiff.controller.KiExampleController.hello()2017-11-21 17:32:00.488  INFO 3953 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/example/lst.service]}" onto public java.lang.Object com.emulian.kiff
一开始没有意识到是 @Transactional 注解的问题,找了很长时间错误原因。

后来笔者重新创建了一个 Controller 类进行问题复现,最终发现原来是上面的 Controller 类实现了笔者定义的另一个接口,类定义如下

@RestController@RequestMapping(KiBizEntityName.ENTITY_EXAMPLE)public class KiExampleController extends KiControllerAbstract implements KiControllerInterface {}
也就是比一般定义的 Controller 多了一个 implements 的声明(继承抽像类不影响),这个时候虽然不影响 @RequestMapping 的注入,但是类内如果再增加 @Transactional 的话,整个类的所有注入就全部失效了,应该是 Spring 注入代理使用了 JDK 默认代理的原因。

解决方法

笔者又引入了 cglib 和 asm 两个依赖,并且在程序入口处增加了 @EnableAsync 注解,代码如下。引入 cglib 后 @RequestMapping 和 @Transactional 均可以正常使用,抛出异常后事务可以回滚。

@EnableTransactionManagement@SpringBootApplication/** * This @SpringBootApplication is a convenience annotation that adds all of the following: * @Configuration tags the class as a source of bean definitions for the application context. * @EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings. * @EnableWebMvc Normally you would add @EnableWebMvc for a Spring MVC app, but Spring Boot adds it automatically when it sees spring-webmvc on the classpath. This flags the application as a web application and activates key behaviors such as setting up a DispatcherServlet. * @ComponentScan tells Spring to look for other components, configurations, and services in the hello package, allowing it to find the controllers. * */@EnableAsync(proxyTargetClass = true)public class KiApplication {    public static void main(String[] args) throws Exception {        SpringApplication.run(KiApplication.class, args);    }}
其实笔者增加 @EnableAsync 注解 也是因为看到如下的错误信息,配置注解的 proxyTargetClass=true 从而强制使用 cglib 来实现注入
***************************APPLICATION FAILED TO START***************************Description:The bean 'kiExampleBizService' could not be injected as a '*.*.kiff.service.biz.KiExampleBizService' because it is a JDK dynamic proxy that implements:    *.*.kiff.interfaces.service.biz.KiBizServiceInterfaceAction:Consider injecting the bean as one of its interfaces or forcing the use of CGLib-based proxies by setting proxyTargetClass=true on @EnableAsync and/or @EnableCaching.Process finished with exit code 1

最后附上 Maven 依赖定义

         <dependency>            <groupId>cglib</groupId>            <artifactId>cglib</artifactId>            <version>3.2.4</version>        </dependency>        <dependency>            <groupId>asm</groupId>            <artifactId>asm</artifactId>            <version>5.1</version>        </dependency>

此外 Spring 使用 4.3.12.RELEASE,Maven项目直接继承(parent) spring-boot-starter-web, 版本 1.5.8.RELEASE,并增加 spring-tx,数据源依赖 druid,版本为 1.1.5,Java 8编译




阅读全文
0 0