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警告原因及解决方案

springboot中o.s.aop.framework.Cglib2AopProxy ‘Unable to proxy method警告原因及解决方案插图


springboot中o.s.aop.framework.Cglib2AopProxy ‘Unable to proxy method警告原因及解决方案插图(1)

关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台

除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接

本文链接:https://www.choupangxia.com/2019/11/06/spring-cglib2aopproxy/