1
头图

Symptom

  • The following SpringBoot projects fail to start at startup. (SpringBoot 1.5.7-RELEASE)
 package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@SpringBootApplication
@EnableTransactionManagement
public class DemoApplication {

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

}
 package com.example.demo.controller;

import com.example.demo.service.DemoServiceImpl;
import javax.annotation.Resource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class DemoController {

    @Resource
    private DemoServiceImpl demoService;

    @RequestMapping("/test")
    public String test() {

        return demoService.demo();
    }

}
 package com.example.demo.service;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service("demoService")
public class DemoServiceImpl implements DemoService{

    @Override
    @Transactional
    public String demo() {
        return "DemoServiceImpl";
    }
}

package com.example.demo.service;

public interface DemoService {

    String demo();

}

error message

 ***************************
APPLICATION FAILED TO START
***************************

Description:

The bean 'demoService' could not be injected as a 'com.example.demo.service.DemoServiceImpl' because it is a JDK dynamic proxy that implements:
    com.example.demo.service.DemoService


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.

if only to solve

  • If you don't delve into the cause, you just need to fix the exception. Then there are the following ways. Just complete any of them.

1. Modify the EnableTransactionManagement annotation parameters

 DemoApplication 上的注解 @EnableTransactionManagement 变成 @EnableTransactionManagement(proxyTargetClass = false)

2. Add configuration in application.properties configuration file

 spring.aop.proxy-target-class=true

3. Change to use its interface when injecting beans (most recommended)

 @Resource
private DemoServiceImpl demoService;

Change it to:

 @Resource
private DemoService demoService;

4. Upgrade SpringBoot version to above 2.0.0

  • This is actually not very recommended, because there may be many changes. But because some default settings of SpringBoot will be mentioned later, they are still written here.

Cause Analysis

some pre-knowledge

  • AOP's dynamic proxy includes JDK dynamic proxy and CGLIB.
  • JDK dynamic proxy requires that the proxy class implements at least one interface. CGLIB does not.

Analysis of the problem

  • Spring creates a proxy when we decorate a method in the DemoServiceImpl class with @Transactional 67ff81d9cd70804b5d42f83c2bb2d1c2---. And in our SpringBoot version (1.5.7), the default is jdk proxy, so the real type of bean is the interface type of DemoServiceImpl DemoService , so when we use
 @Resource
private DemoServiceImpl demoService;

When it comes to inject, it cannot find a bean of type DemoServiceImpl .

Rationale for the solution

1. Modify the EnableTransactionManagement annotation parameters

  • In this way, the method of dynamic proxy is forced to be designated as CGLIB, so the problem of only interface type bean is avoided.

2. Add configuration in application.properties configuration file

  • Ditto.

3. Change to use its interface when injecting beans

  • This method @Resource also uses the type of interface, so you can inject beans normally, and this method is recommended to solve the problem. If there are multiple implementation classes for the interface, you can consider using the name parameter in the annotation to control it.

4. Upgrade SpringBoot version to above 2.0.0

  • In fact, most people should not do this. The main purpose of listing here is to illustrate that after SpringBoot 2.0.0, the dynamic proxy has changed from the default jdk proxy to CGLIB, so upgrading the SpringBoot version can solve this problem.

reference material


羊都是我吃的
1.4k 声望2.9k 粉丝

将来的你,一定会感谢现在拼命努力的自己。