spring Insider Version 2 IoC and AOP Principles


Written earlier, this blog is a transcript of reading Inside spring Technology. Combination

Chapter 2

2.2 Design and implementation of IoC container series: BeanFactory and ApplicationContext

IoC Container Series for 2.2.1 Spring

As an IoC container, the functional specification is designed as an excuse class, BeanFactory, which reflects the most basic functional specification Spring has set for providing users with an IoC container.

Design of Spring IoC Container

  • From interface BeanFactory to HierarchicalBeanFactory to Configurable BeanFactory, this is a major BeanFactory design path. In this interface design path, the BeanFactory interface defines the specification of the basic IoC container. This interface definition includes getBean, the basic method of an IoC container such as 0 through which beans can be obtained from the container. The HierarchicalBeanFactory interface, which inherits the basic interface of BeanFactory, adds the interface capability of getParentBeanFactory(), which enables BeanFactory to manage parent IoC containers. In the next Configurable BeanFactory interface, there are mainly one or more configuration functions defined for BeanFactory, such as setting parent IoC containers through setParentBeanFactory, configuring Bean post-processor through addBeanPostProcessor(), and so on. Overlay of these interface designs defines BeanFactory as the basic function of a simple IoC container. The design of the BeanFactory simple IoC container is described in more detail later.
  • The second main line of interface design is the interface design with the application context interface as the core. The main interface design involved here is from BeanFactory to Listable BeanFactory, to ApplicationContext, to our commonly used WebApplicationContext or Configurable ApplicationContext interfaces. The basic application contexts we commonly use are the implementations of Configurable ApplicationContext or WebApplicationContext. In this interface system, two interfaces, ListableBeanFactory and HierarchicalBeanFactory, connect BeanFactory interface definition and ApplicationConext application context interface definition. In the ListableBeanFactory interface, many BeanFactory interface functions have been refined, such as defining the getBeanDefinitionNames() interface method; For the HierarchicalBeanFactory interface, as we mentioned earlier, for the ApplicationContext interface, it inherits MessageSource, Resource Loader. The ApplicationEventPublisher interface adds support for the features of advanced containers based on BeanFactory's simple IoC container.
  • The main interface relationship is involved here, and specific IoC containers are implemented under this interface system, such as DefaultListableBeanFactory, which implements Configurable-BeanFactory, a simple IoC container. Like other IoC containers, such as. The XmlBeanFactory is an extension of the DefaultListableBeanFactory, as is the implementation of the ApplicationContext.
  • This interface system is centered on BeanFactory and ApplicationContext. BeanFactory is also the most basic interface of the IoC container. In the design of the ApplicationContext, on the one hand, you can see that it inherits the ListableBeanFactory from the BeanFactory interface system. AutowireCapableBeanFactory. The interface of BeanFactory, such as HierarchicalBeanFactory, has the basic functions of the BeanFactory IoC container and, on the other hand, inherits MessageSource. ResourceLoadr. ApplicationEventPublisher These interfaces, BeanFactory gives the ApplicationContext more advanced IoC container features. For the ApplicationContext, in order to use it in a Web environment, a Web ApplicationContext interface is also designed, which extends functionality by inheriting the ThemeSource interface.
  1. Application scenarios for BeanFactory

    The BeanFactory excuse defines the most basic form of an IoC container and provides the most basic contractual services that an IoC container should adhere to, as well as the lowest and most basic programming specifications that an IoC container should adhere to.

    The BeanFactory interface designs the getBean method, which is the primary method of using the IoC Container API to obtain beans managed in the IoC Container, indexed by the specified name.

    With the BeanFactory definition, users can do the following:

    • The interface method containsBean allows users to determine if a container contains a Bean with a specified name.
    • The interface method isSingleton is used to query whether a given name Bean is a Singleton type Bean. For the Singleton property, the user can specify it in the BeanDefinition.
    • The interface method isPrototype is used to query whether a Bean with a specified name is of prototype type type type type. Like the Singleton property, this property can also be specified by the user in the BeanDefinition.
    • The interface method isTypeMatch is used to query whether the Class type of a Bean with a specified name is a specific Class type. This Class type can be specified by the user.
    • Queries the lass type of a Bean with a specified name through the interface method getType.
    • The interface method getAliases is used to query all aliases for beans with specified names, which are defined by the user in Bean Definition.

  1. Design principle of BeanFactory container

    On the basis of BeanFactory, Spring provides implementations of a series of containers that conform to this IoC container interface. Take the implementation of XmlBeanFactory as an example:

XmlBeanFactory source:

public class XmlBeanFactory extends DefaultListableBeanFactory {

	private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

	public XmlBeanFactory(Resource resource) throws BeansException {
		this(resource, null);
	}
	
	public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
		super(parentBeanFactory);
		this.reader.loadBeanDefinitions(resource);
	}

}

Using the IoC container programmatically, we can use the DefaultListableBeanFactory IoC container through the factory object. When using an IoC container, the following steps are required:

1) Create an abstract resource for the IoC configuration file that contains the BeanDefinition definition information.

2) Create a BeanFactory using DefaultListableBeanFactory.

3) Create a reader that loads BeanDefinition, where BeanDefinition as an XML file is loaded using XmlBeanDefinition Reader and configured to the BeanFactory through a callback.

4) Read configuration information from a defined resource location, and the specific parsing process is done by the XmlBeanDefinitionReader. Once you have finished loading and registering the Bean definition, the IoC container you need is set up. At this point you can use the IoC container directly.

  1. Application Scenarios for ApplicationContext

    Applicationis an advanced morphological IoC container that adds additional functionality to the BeanFactory that provides ApplicationContext with the following features that BeanFactory does not have:

    • Supports different sources of information. We see that the ApplicationContext extends the MessageSource interface, and the extended capabilities of these information sources can support internationalization and provide services for developing multilingual versions of applications.
    • Access resources. This - feature is reflected in the support for ResourceLoader and Resource so that we can get Bean Definition resources from different places. This abstraction gives users the flexibility to define Bean definition information, especially from different I/O channels. This is not apparent in the interface relationship, but in general, the specific ApplicationContext inherits a subclass of DefaultResourceLoader. Because DefaultResourceLoader is the base class of AbstractApplicationContext, the use of Resource in the IoC container is explained in detail later.
    • Supports application events. The interface ApplicationEventPublisher is inherited, introducing event mechanisms in the context. The combination of these events and Bean's life cycle facilitates Bean management.
    • Additional services provided in the ApplicationContext. These services enrich the functionality of the basic IoC container. Because of these rich additional capabilities, the ApplicationContext is a framework-oriented style of use compared to a simple BeanFactory, it is generally recommended to use the ApplicationContext as the basic form of the IoC container when developing applications.
  2. Design principles of the ApplicationContext container

    The design principle of the ApplicationContext container is illustrated with the implementation of FileSystemXmlApplicationContext as an example. As a specific application context, only two functions related to its own design need to be implemented.

    One feature is that if the application uses the FileSystemXmlApplicationContext directly, support for instantiating this application context will also start the refresh() process for the IoC container:

    public FileSystemXmlApplicationContext(
          String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
          throws BeansException {
    
       super(parent);
       setConfigLocations(configLocations);
       if (refresh) {
          refresh();
       }
    }
    

    The specific implementation of refresh() starting in the IoC container is analyzed later.

    Another function is specifically related to the design of the FileSystemXmlApplicationContext, which is in part related to how to load Bean Definition resources of XML from the file system. This process prepares you to read BeanDefinition as XML in the file system because different application context implementations correspond to different ways of reading BeanDefinition. The implementation code for FileSystemXmlApplicationContext is as follows:

    protected Resource getResourceByPath(String path) {
       if (path.startsWith("/")) {
          path = path.substring(1);
       }
       return new FileSystemResource(path);
    }
    

Initialization of 2.3 IoC Containers

The initialization of the IoC container is initiated by the refresh() method, which marks the formal start of the IoC container. Specifically, this startup consists of three basic processes: BeanDefinition's Resource Location, Loading, and Registration.

Resource Location for 2.3.1 BeanDefinition

Loading and parsing of 2.3.2 BeanDefinition

Tracking source gets location and loading of Resource:


2.3.3 BeanDefinition Registration in IoC Container

Dependent Injection of 2.4 IoC Container

A getBean is the starting point of a dependency injection, then createBean is called, and Bean objects are generated according to the requirements defined by the BeanDefinition during the createBean process. This createBean is implemented in AbstractAutowireCapableBeanFactory.

A call to doCreateBean() to create a Bean was invoked in createBean(). There is one important method in doCreateBean(): createBeanInstance and populatedBean. The Java object contained in the Bean is generated in the createBeanInstance in a manner specified by the BeanDefinition concerned. The most common instantiate process is instantiateBean, which is instantiated using CGLIB. The SimpleInstantiationStrategy class is Spring's default class for generating Bean objects, providing two ways to instantiate Java objects. One is BeanUtils and the other is CGLIB.

On the basis of instantiating the generation of Bean objects, this paper describes how Spring handles these objects, that is, how to set up the dependencies of these Bean objects after they are generated to complete the dependency injection process. This process is designed to process the properties of various Bean objects (that is, dependency processing), which is based on the BeanDefinition that has been resolved. The populatedBean method handles this process, which is implemented in AbstractAutowireCapableBeanFactory.

Design of Other Related Characteristics of 2.5 Containers

Initialization and destruction of 2.5.1 ApplicationContext and BEan

2.5.2 lazy-init attribute and pre-instantiation

The lazy-init attribute is part of the container refresh. In the finishBeanFactoryInitialization method, the processing of the lazy-init attribute is encapsulated, and the actual processing is done in the preInstantiateSingletons method of DefaultLIstableBeanFactory, the basic container. This method completes the pre-instantiation of a single Bean.

Implementation of 2.5.3 FactoryBean

Following the source discovery of getBean, the implementation of FactoryBean is to get FactoryBean first, then call the getObject method at the end if the required beanName does not start with $

Implementation of 2.5.4 BeanPostProcessor

5.5.5 autowiring (auto-dependent assembly implementation)

BeanPostProcessor is a feature that is often encountered when using an IoC container. The Bean's rear processor is a listener that listens for container-triggered events. After registering it with the IoC container, the beans managed in the container have the ability to receive callbacks to the IoC container events. BeanPostProcessor is very simple to use by designing a specific postprocessor. At the same time, this specific postprocessor needs to implement the interface class BeanPostProcessor and set it to the Bean configuration file in XML. This BeanPostProcessor is an interface class. It has two interface methods, one is
postProcessBeforeInitialization, which provides a callback entry before the Bean is initialized; One is postProcessAfterInitialization, which provides a callback entry after the Bean is initialized, and both triggers of callbacks are related to the life cycle of container-managed beans. The following diagram shows the call relationship starting with the getBean method

Calls to the postProcessBeforeInitialization and postProcessBAfterInitialization methods were completed in the InitializeBean call

The specific initialization process is also an important part of the IoC container's completion of dependent annotators. In the initializeBean method, you need to use the name of the Bean, complete the Bean object that depends on the annotator later, and the BeanDefinition that corresponds to the Bean. With the help of these inputs, complete the initialization of the Bean, including setting the name of the Bean for a Bean of type BeanNameAware, setting the class loader for a Bean of type BeanClassLoaderAware, and setting the IoC container in which the Bean of type BeanFactoryAware resides for callbacks, of course, There are also callbacks to postProcess-BeforeInitialization/postProcess AfterInitialization and processing of the initialization property init-method. After this series of initializations, the result is a bean managed by an IoC container that can be used normally. Implementation code:

Implementation of 2.5.5 autowiring

Handling of autowiring attributes in populateBean

if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
      mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
   MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
      autowireByName(beanName, mbd, bw, newPvs);
   }
   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
      autowireByType(beanName, mbd, bw, newPvs);
   }
   pvs = newPvs;
}

Take autowireByName for example:

Dependency Check for 2.5.6 Bean s

2.5.7 Bean Perception of IoC Containers

In some cases, the IoC container needs to be manipulated directly in the Bean, which Spring does through a specific aware interface. The aware interface has the following:

  • BeanNameAware, you can get its Bean instance name in the IoC container in Bean.
  • BeanFactoryAware, which gets the IoC container in which the Bean resides, uses the services of the IoC container directly in the Bean.
  • ApplicationContextAware allows you to get the application context in which the Bean resides in a Bean and use the application context services directly in the Bean.
  • MessageSourceAware, the source of the message is available in the Bean.
  • ApplicationEventPublisherAware, an event publisher under Application Context can be used in Bean s to publish events in Application Context.
  • ResourceLoader Aware, which gets ResourceL oader in a Bean, loads the external corresponding Resource resource in the Bean using ResourceL oader.

2.6 Summary

The basic working principle of containers can be roughly summarized as follows:

  • Location of BeanDefinition. For IoC containers, it helps manage dependencies between POJO s, but it also provides Bean definition information based on Spring's definition rules. Beans can be used to define information in a variety of formats, including the XML file format, which is familiar and commonly used. Spring gives users a lot of flexibility in defining beans. The first step in initializing the IoC container is to locate these valid Bean Definition Information, where Spring uses the Resource interface to unify these Bean Definition Information, which is accomplished by ResourceLoader. If you use context, the ApplicationContext itself provides the ability to target customers. Because the context itself is a subclass of DefaultResourceLoader. If the basic BeanFactory is used as the IoC container, the extra work the customer needs to do is specify the appropriate Resource for the BeanFactory to locate the Bean information.
  • Initialization of containers. When using a context, it needs to be initialized, and this IoC container will be available only after initialization is complete. The entry to this process is implemented in refresh, which is equivalent to the container's initialization function. An important part of the initialization process is the manning and registration of BeanDefinition information. Equivalent to the need to create a BeanDefinition-defined data image in an IoC container, Spring separates the loaded functionality from the IoC container for loading flexibility, and BeanDefinition Reader completes the reading, parsing of BeanDefinition information and the creation of BeanDefinition inside the IoC container. In DefaultListableBeanFactory, these BeanDefinitions are maintained in a Hashmap through which subsequent IoC containers manage and manipulate beans.

Once the container initialization is complete, the use of the IoC container is ready, but at this point a BeanDefinition is only established inside the IoC container, and the specific dependencies have not been injected. The IoC container injects related Bean dependencies when the customer requests a Bean from the IoC container for the first time. If pre-injection is required, the client can pre-instantiate through the lazy-init attribute, which is part of the context initialization to control the dependent annotator ahead of time. Once the dependency injection is complete, the IoC container maintains these dependent beans for direct customer use. Beans are now available through getBean s, which are not simple Java objects but beans that already contain dependencies between objects, although these annotation-dependent processes are invisible to the user.

Chapter 3

3.1 Overview of Spring AOP

First briefly review some related AOP concepts, then gradually expand the analysis of AOP implementation principles, through the analysis of implementation principles to understand the Spring AOP module, in the analysis of these implementation principles, including the generation of proxy objects, the implementation of AOP interceptors, and so on. In the analysis, ProxyFactoryBean and ProxyFactory are examples.

3.1.2 Advice Concurrent

Beginning with the interface BeforeAdvice, in the inheritance relationship of BeforeAdvice, a pre-enhanced interface MethodBeforeAdvice is defined that is set for the target method to be enhanced, and a callback function is required to implement this pre-interface:

void before(Method method, Object[] args, @Nullable Object target) throws Throwable;

As a callback function, the implementation of the before method is called back when the target method is configured in Advice. Specific call parameters are: Method object, which is the reflection object of the target method; Object[] array of objects containing input parameters to the target method. Take CountingBeforeAdvice as an example to illustrate the use of BeforeAdvice, which is a concrete implementation of the interface MethodBeforeAdvice.

3.1.3 pointcut tangent

public interface Pointcut {
   ClassFilter getClassFilter();
   MethodMatcher getMethodMatcher();
   Pointcut TRUE = TruePointcut.INSTANCE;
}

As you can see from the Pointcut's basic interface definition, a MethodMatcher needs to be returned. This returned MethodMatcher does the matching judgment for Point, that is, it determines whether the current method call needs to be enhanced or whether a configured Advice notification needs to be applied to the currently invoked method. In the class inheritance relationship of Pointcut, take the implementation principle of the regular expression tangent JdkRegexpMethodPointcut as an example to understand exactly how the tangent point Pointcut works. The JdkRegexpMethodPointcut class completes the function of matching method names through regular expressions. As you can see from the implementation of the base class StaticMethod-MatcherPointcut of JdkRegexpMethodPointcut, setting the MethodMatcher as StaticMethodMatcher, and JdkRegexpMethodPointcut is also a subclass of this MethodMatcher, its class hierarchy relationship is shown in Figures 3-7.

3.1.4 Advisor Notifier

public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
   private Pointcut pointcut = Pointcut.TRUE;
   public DefaultPointcutAdvisor() {
   }
   public DefaultPointcutAdvisor(Advice advice) {
      this(Pointcut.TRUE, advice);
   }
   public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
      this.pointcut = pointcut;
      setAdvice(advice);
   }
   public void setPointcut(@Nullable Pointcut pointcut) {
      this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
   }
   public Pointcut getPointcut() {
      return this.pointcut;
   }
   public String toString() {
      return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]";
   }

}

Design and Implementation of 3.2 Spring AOP

Dynamic proxy characteristics of 3.2.1 JVM

The core technology used in the Spring AOP implementation is dynamic proxy, which is actually a feature of JDK.

Design Analysis of 3.2.2 Spring AOP

3.2.3 Spring AOP Scenarios

On the one hand, applications can use the functions of AOP directly, design cross-cutting concerns of applications, abstract functions that span multiple modules of an application, and flexibly compile them into modules through the use of simple AOP, such as logging functions in applications through AOP. On the other hand, inside Spring,. Some support modules are also implemented through Spring AOP, such as transaction processing, which will be detailed later. From these two perspectives, you can already see the core position of Spring AOP.

3.3 Resume AopProxy Proxy Proxy Object

3.3.1 Design Principles

For Spring applications, proxy object generation is accomplished by configuring and invoking Spring's ProxyFactoryBean.

3.3.2 Configuring ProxyFactoryBean

XML-based configuration:

  1. Defines the notifier Advisor used, which should be defined as a Bean. Importantly, the implementation of this notifier defines the faceted behavior that needs to be enhanced on the target object, known as Advice notification.
  2. Define ProxyFactoryBean as another Bean, which is the main class encapsulating AOP functionality. When configuring ProxyFactoryBean, you need to set important properties related to AOP implementation, such as proxyInterface, interceptorNames, and target. As you can see from the property name, the values of the interceptorNames property tend to set the notifiers that need to be defined, because these notifiers work through the interceptor mechanism using the proxy object in the AOP configuration of the ProxyFactoryBean. So the name interceptor is still used here. It's an old bottled new bar.
  3. Defines a target property, a Bean injected as a target property, which is an object that needs to be enhanced with a facet application in the AOP Notifier, that is, the base object mentioned earlier.

3.3.3 ProxyFactoryBean Generates AopProxy Proxy Proxy Objects

Specific AopProxy generation process:

getObject() method in ProxyFactorybean:

public Object getObject() throws BeansException {
   initializeAdvisorChain();
   if (isSingleton()) {
      return getSingletonInstance();
   }
   else {
      if (this.targetName == null) {
         logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
               "Enable prototype proxies by setting the 'targetName' property.");
      }
      return newPrototypeInstance();
   }
}

Configuring the Advisor chain for the Proxy proxy object is accomplished by the initializeAdvisorChain() method:

private synchronized void initializeAdvisorChain() throws AopConfigException, BeansException {
   if (this.advisorChainInitialized) {
      return;
   }
   if (!ObjectUtils.isEmpty(this.interceptorNames)) {
      if (this.beanFactory == null) {
         throw new IllegalStateException("No BeanFactory available anymore (probably due to serialization) " +
               "- cannot resolve interceptor names " + Arrays.asList(this.interceptorNames));
      }
      if (this.interceptorNames[this.interceptorNames.length - 1].endsWith(GLOBAL_SUFFIX) &&
            this.targetName == null && this.targetSource == EMPTY_TARGET_SOURCE) {
         throw new AopConfigException("Target required after globals");
      }
       // Here is the call to add the Advisor chain, which is configured with the interceptorNames property
      for (String name : this.interceptorNames) {
         if (logger.isTraceEnabled()) {
            logger.trace("Configuring advisor or advice '" + name + "'");
         }

         if (name.endsWith(GLOBAL_SUFFIX)) {
            if (!(this.beanFactory instanceof ListableBeanFactory)) {
               throw new AopConfigException(
                     "Can only use global advisors or interceptors with a ListableBeanFactory");
            }
            addGlobalAdvisor((ListableBeanFactory) this.beanFactory,
                  name.substring(0, name.length() - GLOBAL_SUFFIX.length()));
         }
          // If the program is called here, a named interceptor advice needs to be added, and whether the Bean is of singleton or prototype type type type needs to be checked
         else {
            Object advice;
            if (this.singleton || this.beanFactory.isSingleton(name)) {
               advice = this.beanFactory.getBean(name);
            }
            else {
               advice = new PrototypePlaceholderAdvisor(name);
            }
            addAdvisorOnChainCreation(advice, name);
         }
      }
   }
   this.advisorChainInitialized = true;
}

This initialization process has a flag bit advisorChainInitialized, which indicates whether the notifier chain has been initialized. If it's already initialized, it's not initialized anymore, but returned directly. That is, this initialization happens the first time an application gets a proxy object through a ProxyFactoryBean. After completing this initialization, all the notifiers that appear in the configuration are read, and the process of getting the notifier is simple. Give the name of the notifier to the container's getBean method, which is accomplished through callbacks to the IoC container. The notifier obtained from the IoC container is then added to the interceptor chain, which is accomplished by the addAdvisorOnChainCreation method.

Generating a singleton object is done in the code of getSingletonInstance(), which is the call entry for ProxyFactoryBean to generate an AopProxy proxy object. The proxy object encapsulates the call to the target object of the target, that is, the method call to the target object is intercepted by the proxy object generated here. The specific generation process is to first read the configuration in ProxyFactoryBean to prepare the proxy object for generation, such as setting the proxy's method call interface. Spring specifically generates proxy objects through the AopProxy class. For the generation of proxy objects in the getSingletonInstance() method, the following code is shown:

private synchronized Object getSingletonInstance() {
   if (this.singletonInstance == null) {
      this.targetSource = freshTargetSource();
      if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
         // Identify entries that require proxying based on the AOP framework
         Class<?> targetClass = getTargetClass();
         if (targetClass == null) {
            throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
         }
         // Set the interface of the proxy object here
         setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
      }
      // Initialize the shared singleton instance.
      super.setFrozen(this.freezeProxy);
      // The method here uses ProxyFactory to generate the desired Proxy
      this.singletonInstance = getProxy(createAopProxy());
   }
   return this.singletonInstance;
}

// Proxy object by AopProxy returned from createProxy
protected Object getProxy(AopProxy aopProxy) {
		return aopProxy.getProxy(this.proxyClassLoader);
}

Specific proxy object generation is done with the help of AopProxyFactory in ProxyCreatorSupport s. Entry implementation to generate proxy objects:

protected final synchronized AopProxy createAopProxy() {
   if (!this.active) {
      activate();
   }
   // Get AopProxy from AopProxyFactory, which is defined in the initialization function and uses DefaultAopProxyFactory
   return getAopProxyFactory().createAopProxy(this);
}

In Spring, the generation of AopProxy proxy objects using JDK and CGLIB is done by JdkDynamicAopProxy and CglibProxyFactory. The detailed proxy object generation process follows
The subsections of polygons are analyzed in detail.

3.3.4 JDK Generate AopProxy Proxy Proxy Object

public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
   }
   Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
   findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
   return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}

3.3.5 CGLIB Generate AopProxy Proxy Proxy Object

public Object getProxy(@Nullable ClassLoader classLoader) {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
   }
   // Get the target object configured in the IoC container from advised
   try {
      Class<?> rootClass = this.advised.getTargetClass();
      Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

      Class<?> proxySuperClass = rootClass;
      if (ClassUtils.isCglibProxyClass(rootClass)) {
         proxySuperClass = rootClass.getSuperclass();
         Class<?>[] additionalInterfaces = rootClass.getInterfaces();
         for (Class<?> additionalInterface : additionalInterfaces) {
            this.advised.addInterface(additionalInterface);
         }
      }

      // 
      validateClassIfNecessary(proxySuperClass, classLoader);

      //  Verify interface settings for proxy objects
      // Create and configure an Enhancer for CGLIB, which is the primary operation class for CGLIB
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
       
      // Setting up Enhancer objects, including setting proxy interfaces, callback methods
      // IoC configuration from advised, such as DynamicAdvisedInterceptor interceptor using AOP
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      // fixedInterceptorMap only populated at this point, after getCallbacks call above
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);

      // Generate Proxy Object
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   catch (CodeGenerationException | IllegalArgumentException ex) {
      throw new AopConfigException("Could not generate CGLIB subclass of class [" +
            this.advised.getTargetClass() + "]: " +
            "Common causes of this problem include using a final class or a non-visible class",
            ex);
   }
   catch (Throwable ex) {
      // TargetSource.getTarget() failed
      throw new AopConfigException("Unexpected AOP exception", ex);
   }
}

3.4 Implementation of Spring AOP Interceptor Call

3.4.1 Design Principles

3.4.2 JdkDynamicAopProxy invoke interception

When a Proxy object is generated in JdkDynamicAopProxy, the generation call to the AopProxy proxy object is made:

Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

3.4.4 Calls to target object methods

If no interceptor is set, the method of the target object is invoked directly. For JdkDynamicAopProxy proxy objects, this method call to the target object is made through AopUtils using a reflection mechanism in AopUtils. Implemented in the invokeJoinpointUsingReflection method, as shown in the code below. In this call, the reflected object of the calling method is first obtained, and then invoke is used to initiate the call to the reflected object of the method:

public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
      throws Throwable {
   // Call the method of the target object using the method
   try {
      ReflectionUtils.makeAccessible(method);
      return method.invoke(target, args);
   }
   catch (InvocationTargetException ex) {
      // Invoked method threw a checked exception.
      // We must rethrow it. The client won't see the interceptor.
      throw ex.getTargetException();
   }
   catch (IllegalArgumentException ex) {
      throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
            method + "] on target [" + target + "]", ex);
   }
   catch (IllegalAccessException ex) {
      throw new AopInvocationException("Could not access method [" + method + "]", ex);
   }
}

Call to 3.4.5 AOP interceptor chain

Before the interceptor's interception method can be run, a matching judgment needs to be made on the proxy method to determine whether the interceptor meets the requirements of section enhancement. You must remember that the matches matching process is required in the Pointcut tangent point, where matches call the method matching judgment to determine whether notification enhancements are required. The call you see below is where matches are made, and the specific processing is in the proceed method of ReflectiveMethodInvocation, as shown in the code below. In proceed method, make a judgment first, and if it is now running to the end of the interceptor chain, it will directly call the target object's implementation method. Otherwise, proceed along the interceptor chain to get the next interceptor, through which matches are made to determine if it is appropriate for cross-sectional enhancement, and if so, get the notification from the interceptor and launch the invoke method of the notification for cross-sectional enhancement. After this process finishes, the proceed method is iteratively called until the interceptors in the interceptor chain have completed the above intercept process.

public Object proceed() throws Throwable {
    
   //The call starts with the interceptor with index -1 and increments in order If the interceptor iteration in the interceptor chain is completed, the call to the target function starts here, which is done through the reflection mechanism and is implemented in AopUtils. InvokeJoinpointUs ingReflection method
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }
   // Processed here along the defined interceptor0r InterceptionAdvice chain
   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
      // Do you remember the Pointcut you analyzed earlier? This is where the match is triggered and if it matches the defined Pointcut, the advice will be executed
      InterceptorAndDynamicMethodMatcher dm =
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
      if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
         return dm.interceptor.invoke(this);
      }
      else {
         // If they do not match, proceed will be called recursively until all interceptors have been run
         return proceed();
      }
   }
   else {
      // //If it is an interceptor, call the interceptor's corresponding method directly
      return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
   }
}

3.4.6 Configuration Notification Class

3.4.7 Implementation of Advice Notification

3.4.8 ProxyFactory implements AOP

Advanced features of 3.5 Spring AOP

m =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
//If there is no match, proceed will be called recursively until all interceptors have been run
return proceed();
}
}
else {
// //If it is an interceptor, call the interceptor's corresponding method directly
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}

#### 3.4.6 Configuration Notification Class

#### 3.4.7 Implementation of Advice Notification

#### 3.4.8 ProxyFactory implements AOP

### Advanced features of 3.5 Spring AOP

Keywords: Java Spring

Added by rash on Tue, 18 Jan 2022 17:13:33 +0200