>>>> 😜😜😜 Making: 👉 github.com/black-ant

A. The preface

Having covered AOP initialization and the creation of AOP proxy classes, this article takes a look at the creation of AOP interceptor objects

2. CglibAopProxy module

The AOP primary proxy class is still CglibAopProxy, so the overall process is still using this object as an example:

2.1 Intercept entry points for object creation

In the CglibAopProxy # getProxy main process, there are several important logic.

// The code has been omitted and modified to a certain extent
public Object getProxy(@Nullable ClassLoader classLoader) {

    / /... Omit the main logic
    Enhancer enhancer = createEnhancer();
    
    // rootClass => com.gang.aop.demo.service.StartService
    // Get all Callback objects -> PIC21001: Callback[Callback[] callbacks = getCallbacks(rootClass); Class<? >[] types =newClass<? >[callbacks.length];for (int x = 0; x < types.length; x++) {
        types[x] = callbacks[x].getClass();
    }

    enhancer.setCallbackFilter(new ProxyCallbackFilter(
        this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, 
        this.fixedInterceptorOffset));
    enhancer.setCallbackTypes(types);

    // Generate the proxy class and create a proxy instance.
    // return createProxyClassAndInstance(enhancer, callbacks);
    enhancer.setInterceptDuringConstruction(false);
    enhancer.setCallbacks(callbacks);
    return (this.constructorArgs ! =null && this.constructorArgTypes ! =null ?
        enhancer.create(this.constructorArgTypes, this.constructorArgs) :
        enhancer.create());
}

Copy the code

PIC21001: Callback[] series parameters

2.1.1 Creating a Callback object

privateCallback[] getCallbacks(Class<? > rootClass)throws Exception {
        // Whether to expose an AOP proxy for each invocation
        boolean exposeProxy = this.advised.isExposeProxy();
        // The configuration is frozen and cannot be notified of changes
        boolean isFrozen = this.advised.isFrozen();
        // Whether all calls to #getTarget() return the same object
        boolean isStatic = this.advised.getTargetSource().isStatic();

        / / select a AOP interceptors - > create here as DynamicAdvisedInterceptor, this is an important part of the class - > 2.1.2
        // advised -> PIC21101 
        Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

        / / create StaticUnadvisedInterceptor/DynamicUnadvisedInterceptor selectivity
        Callback targetInterceptor;
        if (exposeProxy) {
            targetInterceptor = (isStatic ?
                    new StaticUnadvisedExposedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedExposedInterceptor(this.advised.getTargetSource()));
        }
        else {
            targetInterceptor = (isStatic ?
                    new StaticUnadvisedInterceptor(this.advised.getTargetSource().getTarget()) :
                    new DynamicUnadvisedInterceptor(this.advised.getTargetSource()));
        }

        // Select a destination dispatcher
        // StaticDispatcher: the Dispatcher is much faster than the Interceptor
        Callback targetDispatcher = (isStatic ?
                new StaticDispatcher(this.advised.getTargetSource().getTarget()) : new SerializableNoOp());
        
        // PICPIC21102
        Callback[] mainCallbacks = new Callback[] {
                aopInterceptor,  // for normal advice
                targetInterceptor,  // invoke target without considering advice, if optimized
                new SerializableNoOp(),  // no override for methods mapped to this
                targetDispatcher, this.advisedDispatcher,
                new EqualsInterceptor(this.advised),
                new HashCodeInterceptor(this.advised)
        };

        Callback[] callbacks;

        // If the target is static and the notification chain is frozen, we can send the AOP call directly to the target by using the method's fixed chain
        if (isStatic && isFrozen) {
            Method[] methods = rootClass.getMethods();
            Callback[] fixedCallbacks = new Callback[methods.length];
            this.fixedInterceptorMap = new HashMap<>(methods.length);

            for (int x = 0; x < methods.length; x++) {
                Method method = methods[x];
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, rootClass);
                fixedCallbacks[x] = new FixedChainStaticTargetInterceptor(
                        chain, this.advised.getTargetSource().getTarget(), this.advised.getTargetClass());
                this.fixedInterceptorMap.put(method, x);
            }

            // Copy the callbacks from mainCallbacks and fixedCallbacks into the Callbacks array
            callbacks = new Callback[mainCallbacks.length + fixedCallbacks.length];
            System.arraycopy(mainCallbacks, 0, callbacks, 0, mainCallbacks.length);
            System.arraycopy(fixedCallbacks, 0, callbacks, mainCallbacks.length, fixedCallbacks.length);
            this.fixedInterceptorOffset = mainCallbacks.length;
        }
        else {
            callbacks = mainCallbacks;
        }
        // Return all callback objects
        return callbacks;
    }
Copy the code

Target objects and notification surfaces are already included in PIC21101 ADVISED

PIC21102: mainCallbacks structure

Extension: Function of ProxyCallbackFilter

This class implements an Accept method that returns the index of the callback function

private static class ProxyCallbackFilter implements CallbackFilter {

    private final AdvisedSupport advised;

    private final Map<Method, Integer> fixedInterceptorMap;

    private final int fixedInterceptorOffset;
    
}
Copy the code

2.1.2 DynamicAdvisedInterceptor

Action: This generic AOP callback is used when the target is dynamic or the proxy is not frozen: the creation process can be seen in getCallbacks in 2.1.1

// How does this object implement method interception
private static class DynamicAdvisedInterceptor implements MethodInterceptor.Serializable {

    // PRO212001: Role of AdvisedSupport
    private final AdvisedSupport advised;

    public DynamicAdvisedInterceptor(AdvisedSupport advised) {
        this.advised = advised;
    }

    @Override
    @Nullable
    // proxy -> EnhancerBySpringCGLIB
    // method -> actual service method
    // args: method parameter
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        Object oldProxy = null;
        boolean setProxyContext = false;
        Object target = null;
        // The target of the current call,
        TargetSource targetSource = this.advised.getTargetSource();
        try {
            if (this.advised.exposeProxy) {
                oldProxy = AopContext.setCurrentProxy(proxy);
                setProxyContext = true;
            }
            // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...target = targetSource.getTarget(); Class<? > targetClass = (target ! =null ? target.getClass() : null);
            // Use this configuration to determine the list of MethodInterceptor objects for the given method
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
            Object retVal;
            // Check if we only have one InvokerInterceptor (no notification, only reflection calls)
            if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
               // The method proxy calls directly
                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                retVal = methodProxy.invoke(target, argsToUse);
            }
            else {
                // Core logic, where a method call is created
                retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
            }
            // Process the return type
            retVal = processReturnType(proxy, target, method, retVal);
            return retVal;
        }
        finally {
            if(target ! =null && !targetSource.isStatic()) {
                targetSource.releaseTarget(target);
            }
            if (setProxyContext) {
                // Restore the old proxyAopContext.setCurrentProxy(oldProxy); }}}}// SingletonTargetSource Object structure
public class SingletonTargetSource implements TargetSource.Serializable {

    // Use reflection to cache and invoke the target
    private final Object target;
}

/ / CglibMethodInvocation structure
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {

    @Nullable
    private final MethodProxy methodProxy;

    public CglibMethodInvocation(Object proxy, @Nullable Object target, Method method,
        Object[] arguments, @NullableClass<? > targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {

        super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);

    // Use method proxies only for public methods not derived from java.lang.Object
    this.methodProxy = (Modifier.isPublic(method.getModifiers()) && method.getDeclaringClass() ! = Object.class && ! AopUtils.isEqualsMethod(method) && ! AopUtils.isHashCodeMethod(method) && ! AopUtils.isToStringMethod(method) ? methodProxy :null);
}

    

Copy the code

As you can see, DynamicAdvisedInterceptor is MethodInterceptor implementation class, the interface to intercept method

MethodInterceptor inheritance:

PRO212001: Role of AdvisedSupport

What it does: AOP proxy configuration manager base class. It is not an AOP proxy per se, but subclasses of the class are usually factories from which an AOP proxy instance is obtained directly

Features: This class is serializable and is used to save the proxy fast


public class AdvisedSupport extends ProxyConfig implements Advised {

    // Notify the chain factory -> Pro
    AdvisorChainFactory advisorChainFactory = new DefaultAdvisorChainFactory();

    // Key is the method cache and value is the advisor chain
    private transient Map<MethodCacheKey, List<Object>> methodCache;

    // The interface to be implemented by the proxy
    privateList<Class<? >> interfaces =new ArrayList<>();

    // A collection of Advisor objects in which each notification is wrapped as a notifier
    private List<Advisor> advisors = new ArrayList<>();

    // For internal operations, the object will be refreshed when the Advisor changes
    private Advisor[] advisorArray = new Advisor[0];

}

// Function of AdvisorChainFactory

Copy the code

The core logic of the agent:

Corresponding method has additional agent through Enhancer in front, called actual call DynamicAdvisedInterceptor, completed by DynamicAdvisedInterceptor AOP classes call again

XXX $$EnhancerBySpringCGLIB$$EnhancerBySpringCGLIB$$… For Class level calls, which are discussed separately later

conclusion

SequenceDiagram requester -) DynamicAdvisedInterceptor: requester calls Interceptor object DynamicAdvisedInterceptor CglibMethodInvocation: -) Invocation CglibMethodInvocation-) the aspect: actually calls the aspect object and executes the corresponding notification method

Subsequent call the specific method is ReflectiveMethodInvocation, regardless of here

Or the feeling is not clear, the whole method is not very clear, consider the completion of the whole series for a deep grinding, welcome to 👉