Category: Troubleshouting

Always use interfaces for dependency injection

I working on a big legacy project that uses Spring IoC. And when it started I see in console warning messages like:

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.

Here a sample code:

@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

}

As I found it happens when fields autowired as concrete class instead of injection by interface.

According to Spring AOP documentation:

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.

Thus since userService injected by concrete class UserServiceImpl instead of interface UserService, so Spriong IoC tries to create a proxy class via CGLIB bytecode magic that shows this error message.

Also this CGLIB magic proxying may be disabled by configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <ehcache:annotation-driven cache-manager="genericCacheManager" proxy-target-class="false"/>
    <tx:annotation-driven proxy-target-class="false"/>
    <aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>

In this case this exception will be thrown during runtime:

Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy56 implementing com.eample.services.UserService,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.eample.services.UserServiceImpl] for property ‘userService’: no matching editors or conversion strategy found

To fix this we just need to use autowiring by interface and this is in common simple refactoring.

Please vote for this feature request to make IntellijIdea helpful in this New inspection: Use dependency injection by interface instead of concrete class

See also:
Spring: Why do we autowire the interface and not the implemented class?
Why always have single implementaion interfaces in service and dao layers?

Реклама