The bean could not be injected as a ‘Type’ because it is a JDK dynamic proxy that implements: reactor.fn.Consumer

While the other answer will solve this issue, I think it will be more appropriate for me to explain why applying proxyTargetClass = true will fix this.

First of all, Spring, as a framework, utilizes proxying in order to supply the bean with some extended functionality, such as declarative transactions via @Transactional, or caching by the means of @Cacheable, etc. There are, in general, 2 ways(*) Spring can create proxy on top of your bean:

  1. JDK dynamic proxying
  2. CGLib proxying

Official documentation on this, in case you are interested.

Spring can create JDK dynamic proxy of the bean (in case proxying is required for this bean of course) if original class of the bean implements at least one interface. So spring basically create another implementation of this interface at runtime with some additional logic on top of original class.

What is the problem: if the bean is proxied by the means of JDK dynamic proxying , then you cannot inject this bean via its original class. Something like this:

@SpringBootApplication
@EnableTransactionManagement(proxyTargetClass = false)
public class StackoverflowApplication {

    @Autowired private SomeService service;

    public static void main(String[] args) {
        SpringApplication.run(StackoverflowApplication.class, args);
    }
}

@Service
class SomeService implements SomeInterface {
    
    @Override
    @Transactional
    public void handle() { }
}

interface SomeInterface {
    void handle();
}

won’t work. Why? Well, because @Transactional tells Spring that it needs to create proxy of SomeService at runtime, and within @EnableTransactionManagement I specifically asked Spring to make it by the means of JDK dynamic proxy – Spring will succeed, since JDK dynamic proxy can be created, but the problem is at runtime there is not bean of type SomeService, there is only a bean of type SomeInterface (by the way, if you inject service here not by the class, but by the interface – it will work, I assume you understand the reason by reading explanation above).

Solution: by applying @EnableTransactionManagement(proxyTargetClass = true) (notice true value here) you force spring to create CGLIB proxy (this rule is applicable only for beans that utilize declarative transaction management, i.e. via annotations). In case of CGLIB proxying, Spring will try to extend the original class, and add additional functionality at runtime in the generated child class. And in this case injection by class will work – because the bean extends class SomeService, so

@Autowired
private SomeService someService;

will work perfectly fine. But, in general, if possible, inject bean by interface, not by class. In this case both CGLIB and JDK dynamic proxy will work. So, be aware of proxying mechanisms spring can use. Hope it helped, have a nice day.

Leave a Comment

Hata!: SQLSTATE[HY000] [1045] Access denied for user 'divattrend_liink'@'localhost' (using password: YES)