preface

AOP is one of the more common features we use with Spring, and today let’s take a look at the nuts and bolts

@EnableAspectJAutoProxy

Whenever you use AOP in a project, you must tag @enableAspectJAutoProxy on a class that stands for enabling AOP.

@Aspect
@Component
@Slf4j
@EnableAspectJAutoProxy
public class AspectTest {
}
Copy the code

Click enter EnableAspectJAutoProxy, will find EnableAspectJAutoProxy import AspectJAutoProxyRegistrar class

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({AspectJAutoProxyRegistrar.class})
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;
​
    boolean exposeProxy() default false;
}
Copy the code

In a previous Spring article, I wrote that the @import annotation can introduce three types of classes

  • ImportSelector type
  • ImportBeanDefinitionRegistrar type
  • Ordinary class

No matter what type, is a way of registered BeanDefinition, Import is ImportBeanDefinitionRegistrar here, This class is registered AnnotationAwareAspectJAutoProxyCreator the BeanDefinition

@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
      BeanDefinitionRegistry registry, @Nullable Object source) {
​
   return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
Copy the code

See AnnotationAwareAspectJAutoProxyCreator inheritance of this class diagram, will find that it is only on the basis of the original Spring – AOP extensions made annotations. In particular, this class implements BeanPostProcessor. Those of you familiar with Spring’s source code should know what implementing this class means. AOP adds to Spring’s existing Bean lifecycle and does not escape Spring’s trap

Some basics

Advice and Advisor

We often see Advice and Advisor. What is the difference between them?

Advice is a notification, Advisor is an enhancer, and each Advisor holds an Advice

public interface Advisor { Advice EMPTY_ADVICE = new Advice() {}; // for example, this interface can getAdvice Advice() held by the Advisor; boolean isPerInstance(); }Copy the code
AopInfrastructureBean
// The interface inside Spring does not have any implementation, just a tag interface. If a class in Spring implements this interface, Public interface AopInfrastructureBean {} // In the AbstractAutoProxyCreator class, there is a method, // If it is a subclass of Advice, Pointcut, Advisor, AopInfrastructureBean, Protected Boolean isInfrastructureClass(Class<? > beanClass) { boolean retVal = Advice.class.isAssignableFrom(beanClass) || Pointcut.class.isAssignableFrom(beanClass) || Advisor.class.isAssignableFrom(beanClass) || AopInfrastructureBean.class.isAssignableFrom(beanClass); if (retVal && logger.isTraceEnabled()) { logger.trace("Did not attempt to auto-proxy infrastructure class [" + beanClass.getName() + "]"); } return retVal; }Copy the code
Pointcut

Pointcut is the most high-level abstraction of Spring AOP. It is mainly responsible for capturing the corresponding JoinPoints of the system. If you compare joinPoints to data, then Pointcut is the query condition. ClassFilter and MethodMatcher limit matching to Joinpoint at different levels. ClassFilter is class-level, and MethodMatcher is method-level. So matching at the class level is relatively simple

public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); Pointcut TRUE = TruePointcut.INSTANCE; } public interface ClassFilter {Boolean matches(Class<? > clazz); ClassFilter TRUE = TrueClassFilter.INSTANCE; } public interface MethodMatcher {// There is a concept of static and dynamic pointcuts // static pointcuts: only test once // dynamic pointcuts: Check Boolean matches(Method Method, Class<? > targetClass); Return true Boolean isRuntime(); boolean matches(Method method, Class<? > targetClass, Object... args); MethodMatcher TRUE = TrueMethodMatcher.INSTANCE; }Copy the code
IntroductionAdvisor

Provides class-level interception for AOP

public interface IntroductionAdvisor extends Advisor, IntroductionInfo { ClassFilter getClassFilter(); void validateInterfaces() throws IllegalArgumentException; Public interface IntroductionInfo {// This interface can define classes that are applicable to AOP, and classes that are not. >[] getInterfaces(); }Copy the code
PointcutAdvisor

Provides method-level interception for AOP

public interface PointcutAdvisor extends Advisor {
​
   Pointcut getPointcut();
​
}
Copy the code

If you look at these classes alone, you might get confused. Here is the code for getting the interceptor chain from AOP

@Override public List<Object> getInterceptorsAndDynamicInterceptionAdvice( Advised config, Method method, @Nullable Class<? > targetClass) { AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance(); Advisor[] advisors = config.getAdvisors(); List<Object> interceptorList = new ArrayList<>(advisors.length); Class<? > actualClass = (targetClass ! = null ? targetClass : method.getDeclaringClass()); Boolean hasIntroductions = null; for (Advisor advisor : Advisors) {if (Advisor instanceof PointcutAdvisor) {PointcutAdvisor = (PointcutAdvisor) advisor; / / if it is filtered or advisor in advance is suitable for the target class if (config. IsPreFiltered () | | PointcutAdvisor. GetPointcut (.) getClassFilter () matches (actualClass)) {/ / the method level of screening MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher(); boolean match; if (mm instanceof IntroductionAwareMethodMatcher) { if (hasIntroductions == null) { hasIntroductions = hasMatchingIntroductions(advisors, actualClass); } match = ((IntroductionAwareMethodMatcher) mm).matches(method, actualClass, hasIntroductions); } else { match = mm.matches(method, actualClass); } if (match) { MethodInterceptor[] interceptors = registry.getInterceptors(advisor); If (mm. IsRuntime ()) {for (MethodInterceptor interceptor: interceptors) { interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm)); } } else { interceptorList.addAll(Arrays.asList(interceptors)); }}}} // if the advisor is an instanceof the IntroductionAdvisor else if (advisor instanceof IntroductionAdvisor) {IntroductionAdvisor ia = (IntroductionAdvisor) advisor; if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) { Interceptor[] interceptors = registry.getInterceptors(advisor); interceptorList.addAll(Arrays.asList(interceptors)); Else {Interceptor[] interceptors = registry. GetInterceptors (Advisor); interceptorList.addAll(Arrays.asList(interceptors)); } } return interceptorList; }Copy the code
AdvisorAdapter

AdvisorAdapter is a bridge between Advisor and MethodInterceptor. In a dynamic proxy, a series of interceptors are executed before a specified method is executed. The unit of these interceptors is MethodInterceptor

Public Interface AdvisorAdapter {// Whether this adapter supports this Advice Boolean supportsAdvice(Advice Advice); // Convert an Advisor to MethodInterceptor MethodInterceptor getInterceptor(Advisor Advisor); }Copy the code

Let’s briefly look at a class and feel how does this adapter transform

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable { private final List<AdvisorAdapter> adapters = new ArrayList<>(3); / / in the constructor to build good AdvisorAdapter several implementation class public DefaultAdvisorAdapterRegistry () {registerAdvisorAdapter (new MethodBeforeAdviceAdapter()); registerAdvisorAdapter(new AfterReturningAdviceAdapter()); registerAdvisorAdapter(new ThrowsAdviceAdapter()); } @Override public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException { List<MethodInterceptor> interceptors = new ArrayList<>(3); Advice advice = advisor.getAdvice(); // Advice is a MethodInterceptor, If (advice instanceof MethodInterceptor) {interceptors.add((MethodInterceptor) advice); } // Check whether AdvisorAdapter ADAPTS to Advice. If yes, convert it to MethodInterceptor for (AdvisorAdapter Adapter: this.adapters) { if (adapter.supportsAdvice(advice)) { interceptors.add(adapter.getInterceptor(advisor)); } } if (interceptors.isEmpty()) { throw new UnknownAdviceTypeException(advisor.getAdvice()); } return interceptors.toArray(new MethodInterceptor[0]); } @Override public void registerAdvisorAdapter(AdvisorAdapter adapter) { this.adapters.add(adapter); }}Copy the code

The source code parsing

Mentioned above, AnnotationAwareAspectJAutoProxyCreator inherit AbstractAutoProxyCreator and implements the BeanPostProcessor, in AbstractAutoProxyCreator class, There are two methods is more important, respectively is postProcessBeforeInstantiation and postProcessAfterInitialization, first take a look at postProcessBeforeInstantiation

postProcessBeforeInstantiation

This method mainly intercepts classes that do not require a proxy

public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { @Override public Object postProcessBeforeInstantiation(Class<? > beanClass, String beanName) { Object cacheKey = getCacheKey(beanClass, beanName); 1. If beanName is not null // 2. If the bean does not exist in the targetSourcedBeans Map cache (when the bean has a custom TargetSource, the proxy is created in this method and placed in the Map if (! StringUtils.hasLength(beanName) || ! This. TargetSourcedBeans. The contains (beanName)) {/ / if the bean exists in advisedBeans this Map cache, Direct return / / advisedBeans the Map is actually existed which beans do not need to be agents of the if (this. AdvisedBeans. Either containsKey (cacheKey)) {return null; } // isInfrastructureClass determines which beans do not need to be proxied ShouldSkip this method will determine whether the class needs to be skipped if (isInfrastructureClass (beanClass) | | shouldSkip (beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return null; }} // If we have a custom TargetSource, get it here, TargetSource = getCustomTargetSource(beanClass, beanName); if (targetSource ! = null) { if (StringUtils.hasLength(beanName)) { this.targetSourcedBeans.add(beanName); } Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); return proxy; } return null; }}Copy the code

Let’s take a closer look at the shouldSkip method, which is very important because all the advisors required by AOP have been parsed

@Override protected boolean shouldSkip(Class<? > beanClass, String beanName) {// candidateAdvisors = findCandidateAdvisors(); for (Advisor advisor : candidateAdvisors) { if (advisor instanceof AspectJPointcutAdvisor && ((AspectJPointcutAdvisor) advisor).getAspectName().equals(beanName)) { return true; } } return super.shouldSkip(beanClass, beanName); }Copy the code
@override protected List<Advisor> findCandidateAdvisors() {// Find the bean List<Advisor> advisors = according to the rule super.findCandidateAdvisors(); / / find the @ Aspect annotations bean if (this. AspectJAdvisorsBuilder! = null) { advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors()); } return advisors; }Copy the code
public List<Advisor> findAdvisorBeans() { // Determine list of advisor bean names, if not cached already. String[] advisorNames = this.cachedAdvisorBeanNames; If (advisorNames == null) {// Get advisorNames = for all beans in the current BeanFactory that implement the Advisor interface BeanFactoryUtils.beanNamesForTypeIncludingAncestors( this.beanFactory, Advisor.class, true, false); this.cachedAdvisorBeanNames = advisorNames; } if (advisorNames.length == 0) { return new ArrayList<>(); } List<Advisor> advisors = new ArrayList<>(); for (String name : AdvisorNames) {// Provides a hook method that can be extended appropriately to exclude this name if (isEligibleBean(name)) {// If the current bean is still being created, Ignore the if (this. The beanFactory. IsCurrentlyInCreation (name)) {if (logger. IsTraceEnabled ()) {logger. Trace (" Skipping currently created advisor '" + name + "'"); }} else {try {// put it in the result and return advisors. Add (this.beanFactory.getBean(name, advisor.class)); } catch (BeanCreationException ex) { Throwable rootCause = ex.getMostSpecificCause(); if (rootCause instanceof BeanCurrentlyInCreationException) { BeanCreationException bce = (BeanCreationException) rootCause; String bceBeanName = bce.getBeanName(); if (bceBeanName ! = null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) { if (logger.isTraceEnabled()) { logger.trace("Skipping advisor '" + name + "' with dependency on currently created bean: " + ex.getMessage()); } // Ignore: indicates a reference back to the bean we're trying to advise. // We want to find advisors other than the currently created bean itself. continue; } } throw ex; } } } } return advisors; }Copy the code
public List<Advisor> buildAspectJAdvisors() { List<String> aspectNames = this.aspectBeanNames; if (aspectNames == null) { synchronized (this) { aspectNames = this.aspectBeanNames; If (aspectNames == null) {// Save Advisor object List<Advisor> advisors = new ArrayList<>(); aspectNames = new ArrayList<>(); // Get the names of all the components in the container. Very consumption performance String [] beanNames = BeanFactoryUtils. BeanNamesForTypeIncludingAncestors (enclosing the beanFactory, Object, class, true, false); For (String beanName: beanNames) {if (! isEligibleBean(beanName)) { continue; } // Use beanName to get Class<? > beanType = this.beanFactory.getType(beanName, false); if (beanType == null) { continue; } / / whether the Class for plane @ Aspect the if (this. AdvisorFactory. IsAspect (beanType)) {/ / section is added to the cache aspectNames. Add (beanName); AspectMetadata amd = new AspectMetadata(beanType, beanName); if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); Advisor / / access Advisor List < > classAdvisors = this. AdvisorFactory. GetAdvisors (factory); / / added to the cache if (this. The beanFactory. IsSingleton (beanName)) {this. AdvisorsCache. Put (beanName classAdvisors); } else { this.aspectFactoryCache.put(beanName, factory); } advisors.addAll(classAdvisors); } else { // Per target or per this. if (this.beanFactory.isSingleton(beanName)) { throw new IllegalArgumentException("Bean with name '" + beanName + "' is a singleton, but aspect instantiation model is not singleton"); } MetadataAwareAspectInstanceFactory factory = new PrototypeAspectInstanceFactory(this.beanFactory, beanName); this.aspectFactoryCache.put(beanName, factory); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } } this.aspectBeanNames = aspectNames; return advisors; If (aspectnames.isempty ()) {return collections.emptyList (); if (aspectnames.isempty ()) {return collections.emptyList (); } List<Advisor> advisors = new ArrayList<>(); for (String aspectName : aspectNames) { List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName); if (cachedAdvisors ! = null) { advisors.addAll(cachedAdvisors); } else { MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName); advisors.addAll(this.advisorFactory.getAdvisors(factory)); } } return advisors; }Copy the code

Take a look at the getAdvisors method in detail

@Override public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) { // Gets the Class Class<? Tagged @aspect > aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); / / get marked as @ the name String of Aspect aspectName = aspectInstanceFactory. GetAspectMetadata () getAspectName (); validate(aspectClass); // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator // so that it will only instantiate once. MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory = new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); List<Advisor> advisors = new ArrayList<>(); // Get all the methods of the section class, which excludes the @pointcut annotation Method for (Method Method: GetAdvisorMethods (aspectClass)) {/ / analytical method of plane Advisor Advisor = getAdvisor (method, lazySingletonAspectInstanceFactory. 0, aspectName); if (advisor ! = null) { advisors.add(advisor); } } // If it's a per target aspect, emit the dummy instantiating aspect. if (! advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory); advisors.add(0, instantiationAdvisor); } // Find introduction fields. for (Field field : aspectClass.getDeclaredFields()) { Advisor advisor = getDeclareParentsAdvisor(field); if (advisor ! = null) { advisors.add(advisor); } } return advisors; }Copy the code
public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut, Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {this.declaredPointcut = declaredPointcut; / / section of the Class. This declaringClass = aspectJAdviceMethod. GetDeclaringClass (); / / section method name this. MethodName = aspectJAdviceMethod. The getName (); / / section method parameter type enclosing parameterTypes. = aspectJAdviceMethod getParameterTypes (); This.aspectjadvicemethod = aspectJAdviceMethod; this.aspectJAdvisorFactory = aspectJAdvisorFactory; this.aspectInstanceFactory = aspectInstanceFactory; This. DeclarationOrder = declarationOrder; This.aspectname = aspectName; if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) { Pointcut preInstantiationPointcut = Pointcuts.union( aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut); this.pointcut = new PerTargetInstantiationModelPointcut( this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory); this.lazy = true; } else { this.pointcut = this.declaredPointcut; this.lazy = false; InstantiatedAdvice = instantiateAdvice(this.declaredpointcut); // instantiateAdvice = instantiateAdvice(this.declaredpointcut); }}Copy the code
@Override @Nullable public Advice getAdvice(Method candidateAdviceMethod, AspectJExpressionPointcut expressionPointcut, MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) { Class<? > candidateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass(); validate(candidateAspectClass); AspectJAnnotation<? > aspectJAnnotation = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod); if (aspectJAnnotation == null) { return null; } // If we get here, we know we have an AspectJ method. // Check that it's an AspectJ-annotated class if (! isAspect(candidateAspectClass)) { throw new AopConfigException("Advice must be declared inside an aspect type: " + "Offending method '" + candidateAdviceMethod + "' in class [" + candidateAspectClass.getName() + "]"); } if (logger.isDebugEnabled()) { logger.debug("Found AspectJ method: " + candidateAdviceMethod); } AbstractAspectJAdvice springAdvice; / / generated according to the annotation corresponding Advice implementation class switch (aspectJAnnotation. GetAnnotationType ()) {case AtPointcut: if (logger.isDebugEnabled()) { logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'"); } return null; case AtAround: springAdvice = new AspectJAroundAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtBefore: springAdvice = new AspectJMethodBeforeAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfter: springAdvice = new AspectJAfterAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); break; case AtAfterReturning: springAdvice = new AspectJAfterReturningAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterReturningAnnotation.returning())) { springAdvice.setReturningName(afterReturningAnnotation.returning()); } break; case AtAfterThrowing: springAdvice = new AspectJAfterThrowingAdvice( candidateAdviceMethod, expressionPointcut, aspectInstanceFactory); AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation(); if (StringUtils.hasText(afterThrowingAnnotation.throwing())) { springAdvice.setThrowingName(afterThrowingAnnotation.throwing()); } break; default: throw new UnsupportedOperationException( "Unsupported advice type on method: " + candidateAdviceMethod); } the Advice / / / / configuration Settings section name springAdvice. SetAspectName (aspectName); / / Settings section of the implementation of priority springAdvice. SetDeclarationOrder (declarationOrder); String[] argNames = this.parameterNameDiscoverer.getParameterNames(candidateAdviceMethod); if (argNames ! = null) {/ / set the method parameters springAdvice. SetArgumentNamesFromStringArray (argNames); } springAdvice.calculateArgumentBindings(); return springAdvice; }Copy the code
postProcessAfterInitialization

After postProcessBeforeInstantiation processing, all need not be agents of class has been blocked, Advisor also is parsed, everything is ok, the generated proxy objects

@Override public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean ! = null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) ! = bean) { return wrapIfNecessary(bean, beanName, cacheKey); } } return bean; }Copy the code
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) { return bean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { return bean; } // If it is an infrastructure class, or a class that should be skipped, the proxy should not be generated, Direct return to bean if (isInfrastructureClass (bean getClass ()) | | shouldSkip (bean. GetClass (), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); return bean; } // If specificInterceptors are not null, Create the corresponding proxy Object Object [] specificInterceptors = getAdvicesAndAdvisorsForBean (bean. GetClass (), beanName, null); if (specificInterceptors ! = DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); 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
@Override @Nullable protected Object[] getAdvicesAndAdvisorsForBean( Class<? > beanClass, String beanName, @Nullable TargetSource targetSource) { List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { return DO_NOT_PROXY; } return advisors.toArray(); } protected List<Advisor> findEligibleAdvisors(Class<? > beanClass, String beanName) {List<Advisor> candidateAdvisors = findCandidateAdvisors(); List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, candidateAdvisors) beanName); // Sort the Advisor extendAdvisors(eligibleAdvisors); if (! eligibleAdvisors.isEmpty()) { eligibleAdvisors = sortAdvisors(eligibleAdvisors); } return eligibleAdvisors; }Copy the code
@override public AopProxy createAopProxy(AdvisedSupport Config) throws AopConfigException { Config. IsProxyTargetClass (the default) to false / / if true, indicates mandatory use of additional agent / /, so some interviewers ask which classes will use additional agent, which can use the JDK dynamic proxy class, If (! Cglib) ¶ If (! NativeDetector.inNativeImage() && (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) { Class<? > targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } // cglib proxy return new ObjenesisCglibAopProxy(config); } else {// JDK dynamic proxy return new JdkDynamicAopProxy(config); }}Copy the code
@Override public Object getProxy(@Nullable ClassLoader classLoader) { if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); Return proxy. newProxyInstance(classLoader, this.proxiedInterfaces, this); }Copy the code
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException { Assert.notNull(config, "AdvisedSupport must not be null"); If the advisor is empty, there is no corresponding section. If the advisor is empty, there is no corresponding section. If the targetSource is empty, there is no corresponding section. When creating an agent, if there is no source for the class, or if there is no corresponding slice, If (config.getAdvisorCount() == 0 && config.gettargetSource () == AdvisedSupport.empty_target_source) {throw new AopConfigException("No advisors and no TargetSource specified"); } this.advised = config; / / get all the proxy interface enclosing proxiedInterfaces = AopProxyUtils.com pleteProxiedInterfaces (enclosing advised, true); / / determine whether equal and hashCode methods be rewritten findDefinedEqualsAndHashCodeMethods (enclosing proxiedInterfaces); }Copy the code
// We know that the equal and hashCode methods are often used by collection frameworks to determine whether a key is duplicated. Is a relatively high frequency operation / / so AOP will in particular cache down whether the interface overrides the equal and hashCode methods private void findDefinedEqualsAndHashCodeMethods (Class <? >[] proxiedInterfaces) { for (Class<? > proxiedInterface : proxiedInterfaces) { Method[] methods = proxiedInterface.getDeclaredMethods(); For (Method Method: methods) {if (aoputils.isequalsMethod (Method)) {this.equalsdefined = true; } / / whether hashCode methods be rewritten the if (AopUtils. IsHashCodeMethod (method)) {enclosing hashCodeDefined = true; } // If (this.equalsDefined &&this.hashCodeDefined) {return; }}}}Copy the code
Method calls implement interception
@Override @Nullable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object oldProxy = null; boolean setProxyContext = false; / / get the target object TargetSource TargetSource = this. Advised. TargetSource; Object target = null; // The equal method does not need the proxy if (! this.equalsDefined && AopUtils.isEqualsMethod(method)) { return equals(args[0]); } // If the method is hashCode, no need to delegate else if (! this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { return hashCode(); }... Object retVal; / / expose the proxy object to variable thread if (this. Advised. ExposeProxy) {oldProxy = AopContext. SetCurrentProxy (proxy); setProxyContext = true; } target = targetSource.getTarget(); Class<? > targetClass = (target ! = null ? target.getClass() : null); List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); / / if the interceptor chain is empty, it is directly invoke the specified method if (chain. IsEmpty ()) {Object [] argsToUse = AopProxyUtils. AdaptArgumentsIfNecessary (method, args);  retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse); } else {// If the interceptor chain is not empty, Is used in the chain of responsibility design pattern the MethodInvocation invocation = new ReflectiveMethodInvocation (proxy, target, method and the args, targetClass, chain); RetVal = Invocation. Proceed (); } // Get the method return value type Class<? > returnType = method.getReturnType(); // If this is returned, the proxy object is returned if (retVal! = null && retVal == target && returnType ! = Object.class && returnType.isInstance(proxy) && ! RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) { retVal = proxy; Else if (retVal == null && returnType! = Void.TYPE && returnType.isPrimitive()) { throw new AopInvocationException( "Null return value from advice does not match primitive return type for: " + method); } return retVal; } finally { if (target ! = null && ! targetSource.isStatic()) { targetSource.releaseTarget(target); } if (setProxyContext) { AopContext.setCurrentProxy(oldProxy); }}}Copy the code
@override @nullable public Object proceed() throws Throwable {// Proceed with subscript -1 until the last interceptor, To perform the target method if (this. CurrentInterceptorIndex = = this. InterceptorsAndDynamicMethodMatchers. The size () - 1) {return invokeJoinpoint(); } // Before obtaining the interceptor, First + + Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex); if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) { InterceptorAndDynamicMethodMatcher dm = (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice; Class<? > targetClass = (this.targetClass ! = null ? this.targetClass : this.method.getDeclaringClass()); if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) { return dm.interceptor.invoke(this); } else { return proceed(); } } else { return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); }}Copy the code

The resources

Geek time

www.tianxiaobo.com/2018/06/20/…

www.cnblogs.com/toby-xu/p/1…