记录一下报错:
今天想做事务控制,在启动器类上加了**@EnableTransactionManagemen**t来开启事务,并在service层方法上加上了 @Transactional(rollbackFor = Exception.class),如何启动启动器类,就报如下错误了,第一次碰到
版本:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
2023-03-16 15:13:56.330 WARN 1244 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'excelDemo': Unsatisfied dependency expressed through field 'resoucefileService'; nested exception is org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'resoucefileServiceImpl' is expected to be of type 'com.example.demo.service.impl.ResoucefileServiceImpl' but was actually of type 'com.sun.proxy.$Proxy96'
2023-03-16 15:13:56.333 INFO 1244 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2023-03-16 15:13:56.343 INFO 1244 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2023-03-16 15:13:56.346 ERROR 1244 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'resoucefileServiceImpl' could not be injected as a 'com.example.demo.service.impl.ResoucefileServiceImpl' because it is a JDK dynamic proxy that implements:
com.example.demo.service.IResoucefileService
Action:
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
翻译一下:
上下文初始化期间遇到异常 -
取消刷新尝试:org.springframework.beans.factory.UnsatisfiedDependency异常:创建名为“excelDemo”的Bean时出错:通过字段“resoucefileService”表示的不满意依赖项;嵌套异常是org.springframework.beans.factory.BeanNotOfRequiredTypeException:名为“resoucefileServiceImpl”的Bean应该属于“com.example.demo.service.impl.ResoucefileServiceImpl”类型,但实际上“com.sun.proxy.$Proxy 96”类型。
描述:
bean ‘resoucefileServiceImpl’ 无法作为’com.example.demo.service.impl.ResoucefileServiceImpl’ 注入,因为它是一个 JDK动态代理,它实现了: com.example.demo.service.IResoucefileService行动:
考虑将 Bean 注入为其接口之一,或者通过在@EnableAsync和/或@EnableCaching上设置
proxyTargetClass=true 来强制使用基于 CGLib 的代理。
解决方法(强制使用CGLIB的代理)
(一)
(二)
解决方法(使用接口注入)
原因分析
我用的是@Transaction注解,底层是基于jdk的代理方式
jdk代理需要使用接口,而我用的实现类,所以报错了
这样就会产生冲突,所以需要强制Springboot使用cglib的代理方式来生成。
@Transaction使用JDK动态代理,而Springboot默认使用cglib动态代理。
JDK动态代理:这是Java提供的一种动态代理机制,它利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前通过调用InvocationHandler来处理。这种代理方式要求目标对象必须实现一个接口,因此,如果目标对象实现了接口,Spring框架会默认采用JDK的动态代理实现AOP(面向切面编程)。
cglib动态代理:与JDK动态代理不同,cglib利用asm开源包对代理对象类的class文件进行加载,通过修改其字节码生成子类来处理。这种代理方式不需要目标对象实现接口,如果目标对象没有实现接口,必须采用CGLIB库。Spring框架会在JDK动态代理和CGLIB之间自动转换,当目标对象没有实现接口时,Spring会自动选择使用CGLIB进行代理。
在Spring框架中,@Transaction注解通常用于声明事务边界,由于它依赖于接口定义的方法来进行事务管理,因此更适合使用JDK动态代理。而Springboot作为Spring框架的扩展,虽然默认情况下可能会根据目标对象是否实现接口来选择使用JDK动态代理或CGLIB动态代理,但在某些情况下,比如当目标对象没有实现接口时,Springboot会默认使用cglib动态代理来确保AOP的正常工作