Cglib is the default for Spring5 AOP. I first heard it in a wechat group:

Really? Refer to the document

When I first saw it, I was skeptical.

Everyone knows that prior to Spring5 AOP used JDK dynamic proxies by default. Is Spring5 really a change? So I opened the Spring Framework 5.x document and double-checked:

The document address: docs. Spring. IO/spring/docs…

A quick translation. Spring AOP defaults to using JDK dynamic proxies, or CGLIB proxies if the object does not implement an interface. Of course, you can force the CGLIB proxy.

What? Wrong document? !

After I sent the official document to the group, I received this student’s reply:

SpringBoot 2.x code example

To prove the document wrong, the student also wrote a DEMO. Below, I will reproduce this DEMO program:

Operating environment: SpringBoot 2.2.0.RELEASE, built-in Spring Framework 5.2.0.RELEASE Add spring-boot-starter-AOP dependency to automatically assemble Spring AOP.

public interface UserService {
    void work(a);
}

@Service
public class UserServiceImpl implements UserService {

    @Override
    public void work(a) {
        System.out.println("Get to work... coding..."); }}Copy the code
@Component
@Aspect
public class UserServiceAspect {
    @Before("execution(* com.me.aop.UserService.work(..) )")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("UserServiceAspect..... ()"); }}Copy the code

UserServiceImpl implements the UserService interface and uses UserServiceAspect to pre-enforce interception of the UserService#work method.

The results show that the CGLIB proxy is used instead of the JDK dynamic proxy.

Could it really be a document error? !

@enableAspectJAutoProxy source code comment

In the Spring Framework, the @enableAspectJAutoProxy annotation is used to enable Spring AOP-related functionality.

Spring Framework 5.2.0.RELEASE @enableAspectJAutoProxy

In Spring Framework 5.2.0.release, the default value of proxyTargetClass is false, and the JDK dynamic proxy is used by default.

Are the documentation and source code comments incorrect? !

@enableAspectJAutoProxy proxyTargetClass invalid?

Next, I tried using @enableAspectJAutoProxy to force the use of JDK dynamic proxies.

Operating environment: SpringBoot 2.2.0.RELEASE, built-in Spring Framework 5.2.0.RELEASE

By running discovery, the CGLIB agent is used again. Is @enableAspectJAutoProxy’s proxyTargetClass setting invalid?

Spring Framework 5.x

Get your head together

  1. Some say Spring5 is starting to use CGLIB by default
  2. Spring Framework 5.x documentation and@EnableAspectJAutoProxyThe source code notes that the default is to use JDK dynamic proxies
  3. Program run results show that even if inherited interface, setproxyTargetClassforfalseThe program still uses the CGLIB proxy

Wait a minute. Are we missing something?

The sample application uses SpringBoot to run, so what if instead of SpringBoot, you just use the Spring Framework?

Runtime environment: Spring Framework 5.2.0.release. The UserServiceImpl and UserServiceAspect classes are the same as above and will not be described here.

The results show that in version 5.x of the Spring Framework, AOP defaults to JDK dynamic proxies if the class implements an interface.

Reorganize your thoughts

  1. Spring5 AOP still uses JDK dynamic proxies by default, official documentation and source code annotations are correct.
  2. In SpringBoot 2.x, AOP uses Cglib by default and cannot passproxyTargetClassModify.
  3. Is there any change in SpringBoot 2.x?

Revisited SpringBoot 2. X

As a result, the above analysis is most likely due to SpringBoot2.x, which has changed the relevant configuration of Spring AOP. Do a round of source code analysis to see what’s going on inside.

Source code analysis

Source code analysis, find the entry is very important. So where’s the entrance this time?

@SpringBootApplication is a composite annotation that uses @EnableAutoConfiguration to do a lot of auto-assembly.

EnableAutoConfiguration is also a composite annotation marked @import on this annotation. Detailed usage about @ Import annotations, see the previous articles: mp.weixin.qq.com/s/7arh4sVH1…

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
Copy the code

AutoConfigurationImportSelector DeferredImportSelector interface is realized.

In the Spring Framework 4.x version, this is an empty interface that simply inherits the ImportSelector interface. In 5.x, we extended the DeferredImportSelector interface and added a getImportGroup method:

The AutoConfigurationGroup class is returned in this method. This is an inner class of AutoConfigurationImportSelector, he realized DeferredImportSelector. Group interface.

In SpringBoot 2 x version, is through AutoConfigurationImportSelector. AutoConfigurationGroup# process method to import automatic configuration class.

Through the breakpoint debugging can be seen, and AOP related automatic configuration is through org. Springframework. Boot. Autoconfigure. AOP) AopAutoConfiguration to configure.

The truth

This is where the truth comes out. In SpringBoot2.x, AOP is automatically assembled through AopAutoConfiguration.

By default, there is definitely no spring.aop.proxy-target-class configuration item. In SpringBoot 2.x, Cglib is used by default.

How do I modify AOP implementations in SpringBoot 2.x

In SpringBoot 2.x, if you need to modify the implementation of AOP, you need to use spring. Aop.proxy-target-class configuration items to modify.

# configure spring. Aop. proxy-target-class=false with spring. Aop. proxy-target-class in the application.properties fileCopy the code

The spring-configuration-metadata.json file can also be used to configure metadata. When using application.properties or application.yml files, IDEA reads these file information to provide code hints; the SpringBoot framework does not read this configuration file itself.

How about SringBoot 1.5.x

As you can see, the JDK dynamic proxy is still used by default in SpringBoot 1.5.x.

SpringBoot 2.x why Cglib is used by default

Why does SpringBoot 2.x use Cglib by default to implement AOP? What are the benefits of that? The author found some information from the Internet. Let’s look at an issue first.

Spring Boot issue #5423

Use @EnableTransactionManagement(proxyTargetClass = true) #5423

Github.com/spring-proj…

In this issue, the question is thrown:

Translation: we should use the @ EnableTransactionManagement (proxyTargetClass = true) to prevent people don’t hate the agency problems when using interface.

What is this “nasty proxy problem when you don’t use an interface”? Think about it for a minute.

Annoying agency problems

Suppose we have a UserServiceImpl and UserService class, and we need to use UserService in the UserContoller. It is common practice in Spring to write code like this:

@Autowired
UserService userService;
Copy the code

In this case, neither the JDK dynamic proxy nor CGLIB will be a problem.

But what if your code looks like this:

@Autowired
UserServiceImpl userService;
Copy the code

If we were using JDK dynamic proxy, we would get an error at startup:

Because JDK dynamic proxies are interface-based, proxy-generated objects can only be assigned to interface variables.

CGLIB doesn’t have that problem. Because CGLIB is implemented by generating subclasses, proxy objects are either assigned to interfaces or implementation classes, both of which are the parent classes of proxy objects.

With this in mind, SpringBoot changed its default implementation of AOP to CGLIB in version 2.x.

For more details, please refer to the above issue.

conclusion

  1. Spring 5.x AOP still uses JDK dynamic proxies by default.
  2. Starting with SpringBoot 2.x, CGLIB is used by default to address type conversion exceptions that can result from using JDK dynamic proxies.
  3. In SpringBoot 2.x, the JDK dynamic proxy can be used by default through configuration itemsspring.aop.proxy-target-class=falseTo modify it,proxyTargetClassThe configuration is invalid.

read

Issue: Default CGLib proxy setting default cannot be overridden by using core framework annotations (@EnableTransactionManagement, @EnableAspectJAutoProxy) #12194

Github.com/spring-proj…

This issue also talk about the questions about proxyTargetClass setting failure, discuss the content include: @ EnableAspectJAutoProxy, @ EnableCaching and @ EnableTransactionManagement. Interested readers can check out the issue on their own.


Welcome to pay attention to personal public account, learn and grow together: