7. AOP Creation Agent for Spring Source Analysis 7

Posted by denoteone on Thu, 10 Oct 2019 20:54:33 +0200

1. Prepare to create an agent

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   //1. Finding Enhancers
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      //2. Creating Agents
      Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      return proxy;
   }
}
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
   //Chapter 6 AOP Search Enhancer has analyzed this step
   List advisors = findEligibleAdvisors(beanClass, beanName);
   if (advisors.isEmpty()) {
      return DO_NOT_PROXY;
   }
   return advisors.toArray();
}
protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, 
                                                                                         TargetSource targetSource) {
   //For the creation and processing of proxy classes, it is handed over to ProxyFactory, which only does some preparatory work.
   ProxyFactory proxyFactory = new ProxyFactory();
   //Get the relevant attributes in the current class
   proxyFactory.copyFrom(this);

   if (!shouldProxyTargetClass(beanClass, beanName)) {
      //Like interface com.lwh.spring.JdkProxy.PersonService
      Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
      for (Class<?> targetInterface : targetInterfaces) {
         //Add proxy interface
         proxyFactory.addInterface(targetInterface);
      }
   }
   
   //Encapsulate the interceptor as an enhancer. The type of interceptor here is the enhancer.
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   for (Advisor advisor : advisors) {
      //And add it to ProxyFactory
      proxyFactory.addAdvisor(advisor);
   }
   //SingletonTargetSource for target object [com.lwh.spring.JdkProxy.PersonServiceImpl@1130520d]
   proxyFactory.setTargetSource(targetSource);
   //Custom agent, empty implementation, implemented by subclasses
   customizeProxyFactory(proxyFactory);

   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }
   //Create agent
   return proxyFactory.getProxy(this.proxyClassLoader);
}
protected Advisor[] buildAdvisors(String beanName, Object[] specificInterceptors) {
   
   Advisor[] commonInterceptors = resolveInterceptorNames();

   List<Object> allInterceptors = new ArrayList<Object>();
   if (specificInterceptors != null) {
      //Added interceptor
      allInterceptors.addAll(Arrays.asList(specificInterceptors));
      if (commonInterceptors != null) {
         if (this.applyCommonInterceptorsFirst) {
            allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
         }
         else {
            allInterceptors.addAll(Arrays.asList(commonInterceptors));
         }
      }
   }

   Advisor[] advisors = new Advisor[allInterceptors.size()];
   for (int i = 0; i < allInterceptors.size(); i++) {
      //Converting Interceptor to Advisor
      advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
   }
   return advisors;
}
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
   if (adviceObject instanceof Advisor) {
      return (Advisor) adviceObject;
   }
   if (!(adviceObject instanceof Advice)) {
      throw new UnknownAdviceTypeException(adviceObject);
   }
   Advice advice = (Advice) adviceObject;
   if (advice instanceof MethodInterceptor) {
      return new DefaultPointcutAdvisor(advice);
   }
   for (AdvisorAdapter adapter : this.adapters) {
      if (adapter.supportsAdvice(advice)) {
         return new DefaultPointcutAdvisor(advice);
      }
   }
   throw new UnknownAdviceTypeException(advice);
}

2. Creating Agents

return proxyFactory.getProxy(this.proxyClassLoader);

public Object getProxy(ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   return getAopProxyFactory().createAopProxy(this);
}
//This function really completes the creation of the agent.
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
   //Three Conditions Affect Spring's Judgment
   //1. Opti property, not recommended for users to use this setting
   //2.proxytargetclass attribute, previously analyzed
   //3. Is there a proxy interface?
   if (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()) {
         //Using JDK dynamic proxy
         return new JdkDynamicAopProxy(config);
      }
      return CglibProxyFactory.createCglibProxy(config);
   }
   else {
      //The target object implements the interface and uses JDK dynamic proxy by default
      return new JdkDynamicAopProxy(config);
   }
}

3. Acquisition Agent

public Object getProxy(ClassLoader classLoader) {
   //The first step is to create the agent, and then to obtain the agent.
   return createAopProxy().getProxy(classLoader);
}

public Object getProxy(ClassLoader classLoader) {
   //Get the proxy interface, which is actually the dynamic proxy implementation of JDK. It is recommended to review the dynamic proxy of JDK.
   Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   //Return the proxy object
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
The key of JDK dynamic proxy is to implement InvocationHandler method and invoke method, and the JdkDynamicAopProxy here
 The InvocationHandler interface is implemented, so there must be an invoke method. Look at Notes < JDK Dynamic Agent > and you can see that the proxy object is obtained.
PersonService personService = ctx.getBean("personService", PersonService.class);
What is actually called here is the sayHello method in the generated proxy class. Look at the figure below. Because it's a note taken before, the package names are inconsistent, but the meaning is obvious. The sayHello method in the proxy class
 The invoke method in InvocationHandler is also called. This h object, that is, InvocationHandler, is set in Proxy.newProxyInstance, so the following call is made
 The sayHello method first enters the invoke method personService.sayHello() of JdkDynamicAopProxy.

4. Method Call

//Get the proxy object
PersonService personService = ctx.getBean("personService", PersonService.class);
//Method call
personService.sayHello();

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   MethodInvocation invocation;
   Object oldProxy = null;
   boolean setProxyContext = false;
   //SingletonTargetSource for target object [com.lwh.spring.JdkProxy.PersonServiceImpl@6986852]
   TargetSource targetSource = this.advised.targetSource;
   Class targetClass = null;
   Object target = null;

   try {
      //Delete part of the code
      Object retVal;
      //SingletonTargetSource for target object [com.lwh.spring.JdkProxy.PersonServiceImpl@6986852]
      target = targetSource.getTarget();
      if (target != null) {
         //class com.lwh.spring.JdkProxy.PersonServiceImpl
         targetClass = target.getClass();
      }

      //Get the interceptor chain of the current method
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      if (chain.isEmpty()) {
         //If the chain is empty, call the tangent method directly
         retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
      }
      else {
         //Encapsulate the interceptor in ReflectiveMethod Invocation to facilitate link calls using its proceed method
         invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         //Execute interceptor chain calls
         retVal = invocation.proceed();
      }

      Class<?> returnType = method.getReturnType();
      if (retVal != null && retVal == target && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         retVal = proxy;
      } else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
      }
      return retVal;
   }
   finally {
   }
}

public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.
   //After all enhancement methods are executed, a current Interceptor Index counter is maintained and incremented.
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }
   //List interceptors AndDynamicMethod Matchers, which records the enhancement methods to be executed and retrieves the enhancement methods to be executed by subscribing
   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Evaluate dynamic method matcher here: static part will already have
      // been evaluated and found to match.
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // Dynamic matching failed.
         // Skip this interceptor and invoke the next in the chain.
         return proceed();
      }
   }
   else {
      // It's an interceptor, so we just invoke it: The pointcut will have
      // been evaluated statically before this object was constructed.
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

Topics: Programming Spring JDK Attribute