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 is based on Spring Boot2 0 is a node, which is different.
In spring boot2 Before 0, the automation 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 { } }
As you can see, this automation configuration is mainly about application Spring. In the properties configuration file aop. The value of the proxy target class} attribute.
What works specifically is the @ ConditionalOnProperty annotation. 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 is not in application Properties, then whether this configuration class takes effect.
Based on the above introduction, we can easily see that:
-
If the developer sets up spring aop. If proxy target class {is false, JDK proxy is used.
-
If the developer sets up spring aop. If proxy target class {is true, Cglib proxy is used.
-
If the developer didn't configure spring at the beginning aop. If the proxy target class {attribute is selected, 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 { } }
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, from spring boot2 From 0, if the user does not configure anything, the Cglib agent 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>
Next, we create an IUserService interface as follows:
public interface IUserService { void hello(); }
Then we will create an implementation class of the interface:
@Service public class UserServiceImpl implements IUserService { @Override public void hello() { } }
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()); } }
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(); } }
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 to properties:
spring.aop.proxy-target-class=false
After adding, DEBUG again, as shown in the following figure:
As you can see, JDK dynamic proxy has been used.
If you use spring boot 1.5 22. Release this version, even if it is not in application Add the configuration in properties. By default, it is also a JDK agent. I won't test this. Partners can try it by themselves.
4. Summary
To sum up:
-
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.
-
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.