Is AOP in Spring Boot JDK dynamic proxy or Cglib dynamic proxy?

As we all know, the underlying layer of AOP is dynamic agent, and there are two ways to implement dynamic agent in Java:...
1. Spring
2. Spring Boot
3. Practice
4. Summary

As we all know, the underlying layer of AOP is dynamic agent, and there are two ways to implement dynamic agent in Java:

  • Dynamic agent based on JDK
  • Dynamic agent based on Cglib

The biggest difference between the two is that the JDK based dynamic proxy needs the proxy object to have an interface, while the Cglib based dynamic proxy does not need the proxy object to have an interface.

So my friends can't help asking, how is AOP implemented in Spring? Is it a JDK based dynamic agent or a Cglib based dynamic agent?

1. Spring

Let's start with the conclusion. Which dynamic proxy is used in Spring, according to the situation:

  • If the proxy object has an interface, use JDK dynamic proxy, otherwise it is Cglib dynamic proxy.
  • If the proxy object has no interface, it is the Cglib dynamic proxy directly.

Take a look at this statement from official documents:

You can see that even in the latest version of Spring, the above strategy remains unchanged. That is, use JDK if you can use JDK as a dynamic agent, and use Cglib if you can't use JDK as a dynamic agent, that is, JDK is preferred as a dynamic agent.

2. Spring Boot

Spring Boot and spring come down in one continuous line. Is it the same strategy on the issue of dynamic proxy? Sorry, this is really different.

The handling of this problem in Spring Boot takes Spring Boot2.0 as the node, which is different.

Before spring boot 2.0, the automatic configuration code for Aop was as follows (Spring Boot 1.5.22.RELEASE):

@Configuration @ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class }) @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) public class AopAutoConfiguration { @Configuration @EnableAspectJAutoProxy(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = true) public static class JdkDynamicAutoProxyConfiguration { } @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = false) public static class CglibAutoProxyConfiguration { } } Copy code

As you can see, this automation configuration mainly discusses the value of the spring.aop.proxy-target-class property in the application.properties configuration file.

Specifically, the @ ConditionalOnProperty annotation works. SongGe will also say a little about several properties in this annotation:

  • Prefix: prefix of the configuration file.
  • Name: the name of the configuration file. Together with prefix, it forms the configuration key.
  • Having: the expected value of the configuration. If the actual configuration is the same as having, the configuration will take effect. Otherwise, it will not take effect.
  • matchIfMissing: if the developer does not configure it in application.properties, whether this configuration class is effective.

Based on the above introduction, we can easily see that:

  • If the developer sets spring.aop.proxy-target-class to false, the JDK proxy is used.
  • If the developer sets spring.aop.proxy-target-class to true, the Cglib proxy is used.
  • If the developer does not configure the spring.aop.proxy-target-class attribute at the beginning, the JDK proxy is used.

This was the case before Spring Boot 2.0.

Let's take a look at the situation after Spring Boot 2.0 (including Spring Boot 2.0.0.RELEASE):

@Configuration @ConditionalOnClass({ EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class }) @ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true) public class AopAutoConfiguration { @Configuration @EnableAspectJAutoProxy(proxyTargetClass = false) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false) public static class JdkDynamicAutoProxyConfiguration { } @Configuration @EnableAspectJAutoProxy(proxyTargetClass = true) @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true) public static class CglibAutoProxyConfiguration { } } Copy code

You can see that most configurations are the same, but one thing is different, that is, the value of matchIfMissing attribute. As you can see, starting from spring boot 2.0, if the user does not configure anything, the Cglib proxy is used by default.

3. Practice

Finally, we write a simple example to verify our idea.

First, create a Spring Boot project (the latest version of Spring Boot is used in this case, that is, Cglib proxy is used by default), and add three dependencies, as follows:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> Copy code

Next, we create an IUserService interface as follows:

public interface IUserService { void hello(); } Copy code

Then we will create an implementation class of the interface:

@Service public class UserServiceImpl implements IUserService { @Override public void hello() { } } Copy code

Method does not need to be implemented.

Another simple cut:

@EnableAspectJAutoProxy @Aspect @Component public class LogAspect { @Before("execution(* org.javaboy.demo.UserServiceImpl.*(..))") public void before(JoinPoint jp) { System.out.println("jp.getSignature().getName() = " + jp.getSignature().getName()); } } Copy code

Finally, another simple test method is injected into the IUserService instance:

@RestController public class HelloController { @Autowired IUserService iUserService; @GetMapping("/hello") public void hello() { iUserService.hello(); } } Copy code

After running DBUEG, you can see that IUserService is represented through Cglib.

If we want to use JDK to proxy, we only need to add the following configuration in application.properties:

spring.aop.proxy-target-class=false Copy code

After adding, DEBUG again, as shown in the following figure:

As you can see, JDK dynamic proxy has been used.

If Spring Boot 1.5.22.RELEASE is used, even if the configuration is not added in application.properties, the default is JDK agent. I won't test this. My friends can try it by themselves.

4. Summary

To sum up:

  1. For AOP in Spring, JDK dynamic proxy is used if there is an interface, and Cglib dynamic proxy is used if there is no interface.
  2. AOP in Spring Boot is the same as Spring before 2.0; Cglib dynamic agent is preferred after 2.0. If users want to use JDK dynamic agent, they need to configure it manually.    

29 November 2021, 05:25 | Views: 5831

Add new comment

For adding a comment, please log in
or create account

0 comments