Article directory
Does Spring5 AOP use Cglib by default? The first time I heard this statement was in a WeChat group:
real or fake? Check out the documentation
When I first saw this statement, I was skeptical.
We all know that the AOP version before Spring5 uses JDK dynamic proxy by default. Is it true that the Spring5 version has been modified? So I opened the Spring Framework 5.x document and confirmed it again:
Document address: https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/core.html#aop
Simply translate. Spring AOP uses JDK dynamic proxy by default, and CGLIB proxy if the object does not implement the interface. Of course, it is also possible to force the use of CGLIB proxies.
What? Documentation wrong? !
After I sent the official document to the group, I received a reply from this classmate:
SpringBoot 2.x code sample
In order to prove that the document was written wrong, this student also wrote a DEMO. Next, let me reproduce this DEMO program:
Operating environment: SpringBoot 2.2.0.RELEASE version, the built-in Spring Framework version is 5.2.0.RELEASE version. At the same time, add spring-boot-starter-aop dependency to automatically assemble Spring AOP.
public interface UserService {
void work();
}
@Service
public class UserServiceImpl implements UserService {
@Override
public void work() {
System.out.println("开始干活...coding...");
}
}
@Component
@Aspect
public class UserServiceAspect {
@Before("execution(* com.me.aop.UserService.work(..))")
public void logBefore(JoinPoint joinPoint) {
System.out.println("UserServiceAspect.....()");
}
}
UserServiceImpl
The interface is implemented UserService
, and the pre-enhanced interception of the method UserServiceAspect
is used at the same time.UserService#work
Judging from the running results, the CGLIB proxy is indeed used here instead of the JDK dynamic proxy.
Is it really a typo in the documentation? !
@EnableAspectJAutoProxy source code annotation
In the Spring Framework, @EnableAspectJAutoProxy
annotations are used to enable Spring AOP-related functions.
The source code of the Spring Framework 5.2.0.RELEASE version @EnableAspectJAutoProxy
annotation is as follows:
Through the source code annotation, we can learn that: in the Spring Framework 5.2.0.RELEASE version, proxyTargetClass
the default value is still false, and the JDK dynamic proxy is still used by default.
Are the documentation and source code comments wrong? !
The proxyTargetClass of @EnableAspectJAutoProxy is invalid?
Next, I tried @EnableAspectJAutoProxy
to force the use of the JDK dynamic proxy with
Operating environment: SpringBoot 2.2.0.RELEASE version, the built-in Spring Framework version is 5.2.0.RELEASE version.
By running the discovery, the CGLIB proxy is still used. Is the proxyTargetClass setting of @EnableAspectJAutoProxy invalid?
Spring Framework 5.x
Organize your thoughts
- Some people say that Spring 5 starts AOP and uses CGLIB by default.
- Both the Spring Framework 5.x documentation and
@EnableAspectJAutoProxy
source code comments say that the default is to use JDK dynamic proxy - The result of the program running shows that even if the interface is inherited and set
proxyTargetClass
tofalse
, the program still uses the CGLIB proxy
Wait a minute, are we missing something?
The sample program is run using SpringBoot, so what if you only use Spring Framework instead of SpringBoot?
Operating environment: Spring Framework 5.2.0.RELEASE version. The UserServiceImpl and
UserServiceAspect classes are the same as above, so I won't repeat them here.
The running results show that: In the Spring Framework 5.x version, if the class implements the interface, AOP still uses the JDK dynamic proxy by default.
Rearrange ideas
- Spring5 AOP still uses JDK dynamic proxy by default, and the official documents and source code comments are correct.
- In SpringBoot 2.x version, AOP uses cglib by default and cannot be modified through proxyTargetClass.
- Did the SpringBoot 2.x version make some changes?
Explore SpringBoot 2.x again
As a result of the above analysis, it is very likely that in the SpringBoot2.x version, the relevant configuration of Spring AOP has been modified. Then come to a wave of source code analysis to see what is going on inside.
Source code analysis
For source code analysis, it is very important to find the right entry. Where is the entrance this time?
@SpringBootApplication
is a composite annotation that uses @EnableAutoConfiguration
a lot of autowiring.
EnableAutoConfiguration
Also a composite annotation, on which the annotation is flagged @Import
. For @Import
detailed usage of annotations, please refer to the author's previous article: https://mp.weixin.qq.com/s/7arh4sVH1mlHE0GVVbZ84Q
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
AutoConfigurationImportSelector
Implemented DeferredImportSelector
the interface.
In the Spring Framework 4.x version, this is an empty interface, it just inherits ImportSelector
the interface. In the 5.x version, DeferredImportSelector
the interface is extended and a method is added getImportGroup
: the class
is returned in this method AutoConfigurationGroup
. This is AutoConfigurationImportSelector
an inner class in , which implements DeferredImportSelector.Group
the interface.
In the SpringBoot 2.x version, AutoConfigurationImportSelector.AutoConfigurationGroup#process
the automatic configuration class is imported through the method.
Through breakpoint debugging, we can see that the automatic configuration related to AOP is org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
configured through .
the truth came out
Seeing this, it can be said that the truth is revealed. In the SpringBoot2.x version, AopAutoConfiguration
AOP is automatically assembled through.
By default, there is definitely no spring.aop.proxy-target-class
such configuration item. At this time, Cglib will be used by default in SpringBoot 2.x version.
How to modify AOP implementation in SpringBoot 2.x
We can also know through the source code that if you need to modify the AOP implementation in SpringBoot 2.x, you need to spring.aop.proxy-target-class
modify it through this configuration item.
#在application.properties文件中通过spring.aop.proxy-target-class来配置
spring.aop.proxy-target-class=false
Here is also a mention spring-configuration-metadata.json
of the role of the file: when using application.properties
or application.yml
files, IDEA provides code hints by reading the information of these files, and the SpringBoot framework itself will not read this configuration file.
What about SpringBoot 1.5.x
It can be seen that in the SpringBoot 1.5.x version, the JDK dynamic proxy is still used by default.
Why SpringBoot 2.x uses Cglib by default
Why does SpringBoot 2.x use Cglib to implement AOP by default? What are the benefits of doing so? The author found some information from the Internet, let's look at an issue first.
Spring Boot issue #5423
Use @EnableTransactionManagement(proxyTargetClass = true) #5423
https://github.com/spring-projects/spring-boot/issues/5423
In this issue, such a question is thrown:
To translate: we should use @EnableTransactionManagement(proxyTargetClass =
true) to prevent nasty proxy issues when people don't use the interface.
What is this "nasty proxy problem when not using an interface"? Think for a minute.
nasty proxy problem
Suppose, we have a UserServiceImpl
and UserService
class, which needs to UserContoller
be used in this time UserService
. In Spring, it is usually customary to write code like this:
@Autowired
UserService userService;
In this case, neither the JDK dynamic proxy nor CGLIB will cause problems.
But what if your code looks like this:
@Autowired
UserServiceImpl userService;
At this time, if we use the JDK dynamic proxy, an error will be reported at startup:
because the JDK dynamic proxy is based on the interface, the objects generated by the proxy can only be assigned to interface variables.
CGLIB does not have this problem. Because CGLIB is realized by generating subclasses, whether the proxy object is assigned to the interface or the implementation class, both are the parent class of the proxy object.
For this reason, SpringBoot changed the default implementation of AOP to CGLIB in version 2.x.
For more details, readers can refer to the above issue by themselves.
Summarize
- AOP in Spring 5.x still uses JDK dynamic proxy by default.
- Starting from SpringBoot 2.x, CGLIB is used by default in order to solve the type conversion exceptions that may be caused by using JDK dynamic proxy.
- In SpringBoot 2.x, if you need to use JDK dynamic proxy by default, you can modify it through the configuration item spring.aop.proxy-target-class=false, and the proxyTargetClass configuration is invalid.
further reading
issue:Default CGLib proxy setting default cannot be overridden by using core framework annotations (@EnableTransactionManagement, @EnableAspectJAutoProxy) #12194
https://github.com/spring-projects/spring-boot/issues/12194
This issue also talked about proxyTargetClass
the issue of setting invalidation. The discussions include: @EnableAspectJAutoProxy
, @EnableCaching
and @EnableTransactionManagement
. Interested readers can refer to the content of this issue by themselves.