Spring Framework version 5.3.x
1. Basic concepts
AOP is short for Aspect-Oriented Programming. Aspect is a modularity mechanism used to describe cross-cutting concerns that are scattered across objects, classes, and functions.
- Base: object to be enhanced or target object
- Facets: Contains enhanced applications to the base
- Configuration: You can think of it as a kind of weaving, by providing this configuration environment in an AOP architecture that combines the base and aspect to achieve the weaving implementation of the aspect to the target object
- Advice: Defines what to do at the join point to provide the woven interface for section enhancement. In Spring AOP, it mainly describes the aspect behavior of Spring AOP injection around method calls.
- Pointcut: Determines which join point Advice should act on, that is, defines the set of methods that need to be enhanced through the Pointcut.
- Advisor: After you have designed the advice and concerns for the target method, you need an object to combine them. This is the Advisor. With the Advisor, you can define which advice should be used and on which concerns.
2. Source code analysis
Source code parsing is annotated for analysis
Turn AOP on with the @enableAspectJAutoProxy annotation:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
/** * false: Java proxy * true: Cglib proxy */
boolean proxyTargetClass(a) default false;
/** * Proxy exposure to resolve internal calls that cannot use proxies, the default is false */
boolean exposeProxy(a) default false;
}
Copy the code
Annotations using the @ Import annotations AspectJAutoProxyRegistrar class is introduced, the next track AspectJAutoProxyRegistrar class
2.1 AspectJAutoProxyRegistrar source code parsing
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
/ / register AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// Read the configured annotation EnableAspectJAutoProxy property
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if(enableAspectJAutoProxy ! =null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); }}}}Copy the code
Through the source code found AspectJAutoProxyRegistrar ImportBeanDefinitionRegistrar interface is achieved, At the time of the Spring container startup will call ImportBeanDefinitionRegistrar# registerBeanDefinitions method to inject AnnotationAwareAspectJAutoProxyCreator
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
Copy the code
Registered Bean name is: the org. Springframework. Aop. Config. InternalAutoProxyCreator
Final call is AopConfigUtils# registerOrEscalateApcAsRequired method
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired( Class<? > cls, BeanDefinitionRegistry registry,@Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if(! cls.getName().equals(apcDefinition.getBeanClassName())) {int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if(currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); }}return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
Copy the code
Here AnnotationAwareAspectJAutoProxyCreator class registration completed. Then look AnnotationAwareAspectJAutoProxyCreator is how to create the proxy class.
2.2 AnnotationAwareAspectJAutoProxyCreator source code parsing
Let’s look at the class inheritance:
Through inheritance relationship found that implements SmartInstantiationAwareBeanPostProcessor BeanFactoryAware, InstantiationAwareBeanPostProcessor, BeanPostProcessor. Here’s how the interface works:
AbstractAutoProxyCreator rewrite the BeanPostProcessor# postProcessAfterInitialization method And InstantiationAwareBeanPostProcessor# postProcessBeforeInstantiation method, the detailed analysis of the two methods:
2.2.1 AbstractAutoProxyCreator# postProcessBeforeInstantiation
@Override
public Object postProcessBeforeInstantiation(Class
beanClass, String beanName) {
// Get the bean's key
Object cacheKey = getCacheKey(beanClass, beanName);
// Determine if the bean has already been processed, which will be placed in targetSourcedBeans
if(! StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
// Determine whether advise is included
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
// Determine the type and whether it should be skipped
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
if(targetSource ! =null) {
if (StringUtils.hasLength(beanName)) {
this.targetSourcedBeans.add(beanName);
}
// Get notifications and notifiers
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
// Create the proxy
Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
return null;
}
Copy the code
2.2.1 AbstractAutoProxyCreator# postProcessAfterInitialization
Take a look at the call chain for this method:
Look at the below AbstractAutoProxyCreator# postProcessAfterInitialization method:
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if(bean ! =null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) ! = bean) {// Wrap the proxy class
returnwrapIfNecessary(bean, beanName, cacheKey); }}return bean;
}
Copy the code
The main method for generating proxy classes is wrapIfNecessary.
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// Create a front checksum detection for the proxy class
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// Determine whether to generate a proxy object
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Get notifications and notifiers
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if(specificInterceptors ! = DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);
// Create a proxy object
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
Copy the code
GetAdvicesAndAdvisorsForBean method invocation is eventually AbstractAdvisorAutoProxyCreator# getAdvicesAndAdvisorsForBean Methods, is further call * * AbstractAdvisorAutoProxyCreator# findEligibleAdvisors * * methods:
protected List<Advisor> findEligibleAdvisors(Class
beanClass, String beanName) {
// Find candidate advisors
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// Filter out the available ones
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if(! eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); }return eligibleAdvisors;
}
Copy the code
-
findCandidateAdvisors
# AnnotationAwareAspectJAutoProxyCreator implementation class@Override protected List<Advisor> findCandidateAdvisors(a) { // Find all Spring Advisors according to the superclass rules List<Advisor> advisors = super.findCandidateAdvisors(); if (this.aspectJAdvisorsBuilder ! =null) { // Find all aspects (annotated @aspect beans) and parse advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; } Copy the code
-
findAdvisorsThatCanApply
protected List<Advisor> findAdvisorsThatCanApply( List
candidateAdvisors, Class beanClass, String beanName) { ProxyCreationContext.setCurrentProxiedBeanName(beanName); try { return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass); } finally { ProxyCreationContext.setCurrentProxiedBeanName(null); }}Copy the code
So that completes the analysis of these two methods. When the notification and notifier are obtained, the proxy object is created
2.2.2 AbstractautoProxyCreate #createProxy Create a proxy class
protected Object createProxy(Class<? > beanClass,@Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// Create a proxy factory
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
// Determine whether to use JDK proxy or CGLIB proxy
if (proxyFactory.isProxyTargetClass()) {
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
if (Proxy.isProxyClass(beanClass)) {
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
for(Class<? > ifc : beanClass.getInterfaces()) { proxyFactory.addInterface(ifc); }}}else {
// No proxyTargetClass flag enforced, let's apply our default checks...
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else{ evaluateProxyInterfaces(beanClass, proxyFactory); }}// Add the notifier
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// Use original ClassLoader if bean class not locally loaded in overriding class loader
ClassLoader classLoader = getProxyClassLoader();
if (classLoader instanceofSmartClassLoader && classLoader ! = beanClass.getClassLoader()) { classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader(); }// Create a proxy object
return proxyFactory.getProxy(classLoader);
}
Copy the code
3. Spring’s easy process for creating beans
Beans are acquired primarily by the BeanFactory, but are created primarily by the BeanPostProcessor. The creation of the proxy class is implemented through the AbstractautoXyCreator class
Methods and postProcessAfterInitialization postProcessBeforeInstantiation methods to create objects to change and to strengthen the implementation agent object.
4. To summarize
The entire startup process of Spring AOP:
- Create BeanFactoryAdvisorRetrievalHelperAdapter class (notification retrieves adapter) and BeanFactoryAspectJAdvisorsBuilderAdapter class
- All call AbstractAutoProxyCreator# postProcessBeforeInstantiation method to find the Advisor and aspect, will cut build into Advisor
- All call AbstractAutoProxyCreator# postProcessAfterInitialization method, from the cache will all enhancer, create agent factory, and woven into the intensifier, create a proxy object
Tips: mainly through to realize postProcessBeforeInstantiation and postProcessAfterInitialization these two methods to determine whether to create a proxy object and how to create the agent