springboot中o.s.aop.framework.Cglib2AopProxy ‘Unable to proxy method警告原因及解决方案
springboot或spring中Cglib2AopProxy警告
在spring或springboot中会出现如下警告:
o.s.aop.framework.Cglib2AopProxy 'Unable to proxy method [public final void org.springframework.jdbc.core.support.JdbcDaoSupport.setDataSource(javax.sql.DataSource)] because it is final: All calls to this method via a proxy will be routed directly to the proxy.'
或如下警告:
WARN org.springframework.aop.framework.Cglib2AopProxy - Unable to proxy method [public final javax.sql.DataSource org.springframework.jdbc.core.support.JdbcDaoSupport.getDataSource()] because it is final: All calls to this method via a proxy will be routed directly to the proxy.
或如下警告:
Final method [public final javax.sql.DataSource org.springframework.jdbc.core.support.JdbcDaoSupport.getDataSource()] cannot get proxied via CGLIB: Calls to this method will NOT be routed to the target instance and might lead to NPEs against uninitialized fields in the proxy instance.
那么导致这样的警告的原因是什么呢?
原因分析
最主要的原因就是在注入依赖时采用了具体的实现类,而不是接口。如下代码所示:
@Service @Transactional public class UserServiceImpl implements UserService { } @Controller public class UserController { @Autowired UserServiceImpl userService; // Here a problem: we declared field as concrete class UserServiceImpl instead of interface UserService }
在UserController中注入的是UserService的具体实现而不是UserService这个接口。
在这种情况下,Spring会采用CGLib进行动态代理,而不是JDK动态代理。因此就会报出上面的异常信息。
解决方案及建议
针对此问题的解决方案很简单,就是注入的时候选择接口而非实现类。
使用CGLIB的局限性在于,建议不要在目标类中定义final的方法,因为无法覆盖final方法(CGLIB在运行时会创建目标类的子类),但是使用JDK的动态代理,没有此限制。
在来看看Spring AOP官方的问题的建议:
Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice).
If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created.
明确支出优先使用JDK动态代理。默认情况下,如果目标对象有接口实现,则采用JDK动态代理;如果目标对象没有实现任何接口,则采用CGLIB代理。
当然,针对此日志信息还有一些粗暴的解决方案,禁用CGLIB代理:
spring.aop.proxy-target-class=false
上面为spring boot中配置,在spring中可在xml文件中配置如下:
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false"/> <aop:config proxy-target-class="false"> <cache:annotation-driven proxy-target-class="false"/>
同时,还有掩耳盗铃的做法,就是关闭对应的日志输出,比如在log4j的配置文件中配置如下:
log.logger.org.springframework.aop.framework.Cglib2AopProxy = ERROR
原文链接:《SPRINGBOOT中O.S.AOP.FRAMEWORK.CGLIB2AOPPROXY ‘UNABLE TO PROXY METHOD警告原因及解决方案》
关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台
除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接
本文链接:https://choupangxia.com/2019/11/06/spring-cglib2aopproxy/