Spring High-level Framework

Summary of the Spring

The advantage of the Spring

  • Easy to decouple and simplify development
  • Support for AOP programming
  • Declarative transaction control
  • Convenient program testing
  • Easy integration of various excellent frameworks
  • Reduce the difficulty of using JavaEE apis
  • Source code is a classic Java learning paradigm

The core structure of Spring

  • Data processing module

  • The Web module

  • AOP/Aspect module

  • The Core Container module

  • The Test module

Core ideas Ioc and AOP

IoC

  • What is the IoC

    Note that this is a technical idea, not a technical implementation. Instead of going to the new object ourselves, the IoC container (the Spring framework) helps us instantiate the object and manage it. We ask the IoC container which object we need to use. That is, we lose a right (the right to create and manage objects) and gain a benefit (regardless of the creation and management of objects, etc.).

  • What problem has the IoC solved

    Ioc solves the problem of coupling between objects

  • Difference between Ioc and DI

    DI: Dependancy injection (DI) describes the same thing as IOC. It means that the IOC container infuses the class with dependent objects that it needs. You can see dependency injection from the perspective of the IOC container. IOC control flipping, on the other hand, gives control over object creation to the IOC container from a class or Bean perspective.

AOP

AOP: Aspect Oridented Programming. In order to separate the same business between different businesses into a slice. Then this part of the same business code is injected into the original business logic through the way of dynamic proxy, so as to achieve the enhancement of the original business logic. Fundamentally decoupled to avoid duplication of cross-cutting logic code.

Spring IoC advanced applications

Basic knowledge of

  • The IoC based

    • BeanFactory differs from ApplicationContext

      BeanFactory is the top interface of the IoC container in the Spring framework. It is used to define basic functions and specifications. ApplicationContext is one of its subinterfaces. So the ApplicationContext has all the functionality provided by the BeanFactory. Generally, we call the BeanFactory the base container of SpringIOC, and the ApplicationContext is the high-level interface of the container that has more functionality than the BeanFactory, such as internationalization support and resource access (XML, Java configuration classes) and so on

    • How to start the IoC container

      • Start the IoC container in Java

        ClassPathXmlApplicationContext: from the root of class loading configuration file (relative path). FileSystemXmlApplicationContext: from a disk loading configuration file path (absolute path). Start the spring container AnnotationConfigApplicationContext: pure annotation mode.

        • Pure comments:

          new Annotation ConfigApplicationContext(SpringConfig.class);
          Copy the code
      • Start the IoC container in the Web environment

        • xml

          Configure the ContextLoaderListener in web.xml to load the XML

          <context-param>
           	<param-name>contextConfigLocation</param-name>
           	<param-value>classpath:applicationContext.xml</param-value>
           </context-param>
           <! Start Spring's IOC container with a listener
           <listener>
           	<listener-class>org.springframework.web.context.ContextLoaderListener
           	</listener-class>
           </listener>
          Copy the code
        • Pure annotations

          ContextLoaderListener to load the annotation configuration class

          <! Tell ContextloaderListener to know that we are using annotations to start the IOC container -->
           <context-param>
           	<param-name>contextClass</param-name>
           	<param-value>org.springframework.web.context.support.AnnotationConfigWebAppli
          cationContext
          	</param-value>
           </context-param>
           <! -- Configure the fully qualified class name of the startup class -->
           <context-param>
           	<param-name>contextConfigLocation</param-name>
           	<param-value>com.lagou.edu.SpringConfig</param-value>
           </context-param>
           <listener>
             <! Start Spring's IOC container with a listener
           	<listener-class>org.springframework.web.context.ContextLoaderListener
           	</listener-class>
           </listener>
          
          Copy the code
    • Three ways to instantiate beans

      • 1. Using a no-parameter constructor (recommended)

        By default, it creates the object by calling the no-argument constructor through reflection. If the class does not have a no-argument constructor, the creation fails.

      • To add their new classes to the SpringIoC container management

        • 2. Static methods

          <! Static method to create object configuration -->
          <bean id="transferService" class="com.lagou.factory.BeanFactory"
           factory-method="getTransferService"></bean>
          Copy the code
        • 3. Create an instance method

          <! Create object with instance method -->
          <bean id="beanFactory"
          class="com.lagou.factory.instancemethod.BeanFactory"></bean>
          <bean id="transferService" factory-bean="beanFactory" factorymethod="getTransferService"></bean>
          Copy the code
    • The scope of the Bean and the life cycle of the different scopes

    The scope of a Bean can be selected at creation time.

    Singleton: Objects are created when the container is created, during project initiation initialization. Objects are destroyed only when the container is destroyed, that is, the same life cycle as an IOC container.

    Prototype: When you need to use this object, a new object instance is created. The IOC container is only responsible for creating objects, not destroying them. Objects live when they are in constant use, and when they are not, they wait for the JVM garbage collection to destroy them.

    • Bean label properties

      In an XML-based IoC configuration, the bean tag is the most basic tag. It represents an object in the IoC container. In other words, if an object is to be managed by Spring, it needs to be configured using this tag in the configuration of XML. The attributes of the Bean tag are as follows:

      • Id attribute: Used to provide a unique identity to the bean. Within a label, the identity must be unique.
      • Class property: Used to specify the fully qualified class name to create the Bean object.
      • Name attribute: Used to give the bean one or more names. Multiple names are separated by Spaces.
      • Factory-bean property: Used to specify the unique identity of the factory bean that created the current bean object. The class attribute becomes invalid when this attribute is specified.
      • Factory-method property: Used to specify the factory method used to create the current bean object. If used with the factory-bean property, the class property is invalid. To be used with the class attribute, the method must be static.
      • Scope property: Used to specify the scope of the bean object. Usually it’s a singleton. You can set it to Prototype when you want to use multi-example patterns.
      • Init-method property: Used to specify the initialization method of the bean object, which is called after the bean object is assembled. Must be a no-parameter method.
      • The destory-method property: Specifies the bean object’s destruction method, which is executed before the bean object is destroyed. It only works if scope is a Singleton.
    • DI XML configuration for dependency injection

      • Dependency injection classification

        • Classified by injection

          • Constructor injection

                      <! --name: insert by parameter name, index: insert by parameter position -->
             <! --<constructor-arg index="0" ref="connectionUtils"/> <constructor-arg index="1" value="zhangsan"/> <constructor-arg The index = "2" value = "1" / > < constructor - arg index = "3" value = "100.5" / > -- >
            
                    <constructor-arg name="connectionUtils" ref="connectionUtils"/>
                    <constructor-arg name="name" value="zhangsan"/>
                    <constructor-arg name="sex" value="1"/>
                    <constructor-arg name="money" value="100.6"/>
            Copy the code
          • Set method injection

        • Categorize by injected data type

          • Basic types and Strings

            <property name="" value=""></property>
            Copy the code
          • Other Bean types

            <property name="" ref=""></property>
            Copy the code
          • Complex types (collection types)

                <property name="myArray">
                        <array>
                            <value>array1</value>
                            <value>array2</value>
                            <value>array3</value>
                        </array>
                    </property>
            
                    <property name="myMap">
                        <map>
                            <entry key="key1" value="value1"/>
                            <entry key="key2" value="value2"/>
                        </map>
                    </property>
            
                    <property name="mySet">
                        <set>
                            <value>set1</value>
                            <value>set2</value>
                        </set>
                    </property>
            
                    <property name="myProperties">
                        <props>
                            <prop key="prop1">value1</prop>
                            <prop key="prop2">value2</prop>
                        </props>
                    </property>
            
            Copy the code
    • DI dependency injection XML and annotation combination schema

      Note:

      1) In actual enterprise development, the use of pure XML schemas is rare

      3) XML + annotations combined with schema, XML files still exist, so the start of the Spring IOC container still starts with loading XML

      4) Which bean definitions are written in XML and which are defined using annotations Beans in third-party JARS are defined in XML, such as beans developed by druid database connection pools that use annotations

      • Mapping of tags to annotations in XML (IoC)

Annotations - DI DI way - the @autowired - combined with @ the Qualifier (" ") - @ Resource @ Resource annotations provided by J2EE, you need to import the package javax.mail. The annotation. The Resource. @resource is automatically injected by ByName by default. @resource was removed in Jdk 11 and needs to be used in a separate jar package - Enable annotation scanning to introduce the Spring Context namespace XML <beans... xmlns:context="http://www.springframework.org/schema/context" http://www.springframework.org/schema/context ... > <! <context:component-scan base-package="com.lagou.edu"/> </beans>"Copy the code
  • Pure annotation pattern

    Modify THE XM + annotation mode, migrate all the remaining content in XML in the form of annotations, and finally delete XML, start the corresponding annotation @Configuration annotation from the Java Configuration class, the current class is a Configuration class @ComponentScan annotation, Instead of context:component-scan @propertysource, introduce an external property configuration file @import to introduce other configuration classes @value to assign to variables, you can assign directly, You can also add method return objects to the SpringIOC container using ${} to read information from the resource configuration file @bean

    <! Tell ContextloaderListener to know that we are using annotations to start the IOC container -->
    <context-param>
      <param-name>contextClass</param-name>
      <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>
    Copy the code

Advanced features

  • Lazy-init lazy loading

    Lazy loading (lazy creation) of beans The default behavior of the ApplicationContext container is to instantiate all Singleton beans ahead of time when the server is started. Pre-instantiation means that all singleton beans are created and configured by the ApplicationContext instance as part of the initialization process. Beans with lazy-init set to true will not be instantiated in advance when ApplicationContext is started, but when the bean is first requested from the container via getBean. XML: lazy-init at the container level by using the “default-lazy-init” annotation on elements :@ lazy

    Application Scenario (1) Enable lazy loading to improve container startup and operation performance to a certain extent. (2) Enable lazy loading for beans that are not frequently used. In this way, the Bean is loaded only when it is occasionally used, and the Bean does not need to occupy resources from the beginning

  • FactoryBean and BeanFactory The BeanFactory interface is the top-level interface of a container. It defines the basic behavior of the container and is responsible for producing and managing a factory of beans using subinterface types such as ApplicationContext. In Spring, there are two types of beans: ordinary beans and factory beans. A FactoryBean can generate a Bean instance of a certain type (which is returned to us). That is, we can use it to customize the Bean creation process. The static and instantiation methods of Bean creation are similar to factoryBeans. Factorybeans are used a lot, especially in some components of the Spring framework, as well as other frameworks that integrate with the Spring framework.

    // Allow us to customize the Bean creation process (complete the definition of complex beans)
    public interface FactoryBean<T> {
     @Nullable
     // Returns the Bean instance created by FactoryBean. If isSingleton returns true, the instance will be placed in the Spring containerIn the singleton object cache poolMap
     T getObject(a) throws Exception;
     @Nullable
     // Returns the Bean type created by FactoryBeanClass<? > getObjectType();// Returns whether the scope is singleton
     default boolean isSingleton(a) {
     return true; }}Copy the code

    We customize a CompanyFactoryBean to implement the FactoryBean interface and configure it into the Spring container.

    public class CompanyFactoryBean implements FactoryBean<Company> {
     private String companyInfo; // Company name, address, size
     public void setCompanyInfo(String companyInfo) {
     this.companyInfo = companyInfo; }@Override
     public Company getObject(a) throws Exception {
     // create a complex object Company
     Company company = new Company();
     String[] strings = companyInfo.split(",");
     company.setName(strings[0]);
     company.setAddress(strings[1]);
     company.setScale(Integer.parseInt(strings[2]));
     return company;
     }
     @Override
     publicClass<? > getObjectType() {return Company.class;
     }
     @Override
     public boolean isSingleton(a) {
     return true; }}Copy the code

    The XML configuration

    <bean id="companyBean" class="com.lagou.edu.factory.CompanyFactoryBean">
     <property name="companyInfo" value="Laigou, Zhongguancun,500"/>
    </bean>
    Copy the code
  • Rear processor

    Spring provides an extended interface for two types of post-processing beans, BeanPostProcessor and BeanFactoryPostProcessor, which are used differently. BeanFactory initialization — > Bean objects can do something after BeanFactory initialization using BeanFactoryPostProcessor postprocessing There are a few things you can do postprocessing with the BeanPostProcessor after the Bean object is instantiated (which is not complete throughout the Bean’s life cycle). Note: an object does not have to bea springbean, but a springbean must Bean object

    • BeanFactoryPostProcessor

    When the BeanFactoryPostProcessor method is called, the bean has not yet been instantiated and has just been resolved into a BeanDefinition object. So you can do some definition processing. Spring BeanFactoryPostProcessor postProcessBeanFactory interface provides only a method (ConfigurableListableBeanFactory var1). In ConfigurableListableBeanFactory BeanDefinition can be obtained. Classic use: Replace placeholders

    • BeanDefinition -> Parses XML

      BeanDefinition object: The bean label we defined in XML, and Spring parses the bean label into a JavaBean, which is the BeanDefinition

    • SpringBean life cycle diagram

    • BeanPostProcessor

BeanPostProcessor is bean-level processing that can be specific to a particular Bean. This interface provides two methods that are executed before and after the Bean's initialization method. It is similar to defining a BeanPostProcessor class with the method specified in init-method when defining a Bean. By default, all beans in the entire Spring container are processed. The method parameters are Object and String. The first parameter is the instance of each bean, and the second parameter is the value of the name or ID attribute of each bean. So we can use the second parameter to determine the specific bean we are going to process.Copy the code

Spring IoC source in depth analysis

Design is elegant

  • Design patterns

Note: principles, methods and techniques

  • The principle of

    Macro principle: Focus on the source code structure and business process from the perspective of God (play down the details of writing a specific line of code)

  • Methods and Techniques

    Breakpoint (Observing the Call Stack) Counterlead (Find Lead) Experience (doXXX in the Spring Framework, where specific processing is done)

The Spring IoC container initializes the body process

  • IoC container system

  • Bean lifecycle critical timing points

    AbstractApplicationContext# refresh () function

  • The Spring IoC container initializes the main process

    @Override
    public void refresh(a) throws BeansException, IllegalStateException {
     synchronized (this.startupShutdownMonitor) {
         // Step 1: Preprocess before refreshing
         prepareRefresh();
         /* Get BeanFactory; The default implementation is DefaultListableBeanFactory load BeanDefition and register to BeanDefitionRegistry * /
         ConfigurableListableBeanFactory beanFactory =
        obtainFreshBeanFactory();
         // Step 3: Prepare the BeanFactory (BeanFactory does some Settings, such as adding the context class)PrepareBeanFactory (beanFactory);try {
             // Step 4: Post-processing after BeanFactory preparation is completed
             postProcessBeanFactory(beanFactory);
             // Step 5: Instantiate and invoke the Bean that implements the BeanFactoryPostProcessor interface
             invokeBeanFactoryPostProcessors(beanFactory);
             // Step 6: Register the BeanPostProcessor (Bean's post-processor) and wait before and after creating the BeanLine registerBeanPostProcessors (the beanFactory);// Step 7: Initialize the MessageSource component (internationalization; Message binding, message parsing);
             initMessageSource();
             // Step 8: Initialize the event dispatcher
             initApplicationEventMulticaster();
             // Step 9: Subclasses override this method to customize the logic when the container is refreshed
             onRefresh();
             // Step 10: Register application listeners. Is to register a listener bean that implements the ApplicationListener interface
             registerListeners();
             /* Step 11: Initialize all remaining non-lazy-loaded singleton bean instantiations create non-lazy-loaded singleton bean instances (with no properties set) fill property initializer method calls (e.g. AfterPropertiesSet, init-method) The BeanPostProcessor (post-processor) is called to post */ on the instance bean
             finishBeanFactoryInitialization(beanFactory);
             /* Step 12: Refresh the context. Basically, LifecycleProcessor's onRefresh() method is called and the ContextRefreshedEvent */ is published
             finishRefresh();
        }
    Copy the code

BeanFactory creation process

  • Get the BeanFactory subprocess

    The BeanFactory is obtained at obtainFreshBeanFactory(), the second step of the refresh() method of the container initialization body process

    AbstractRefreshableApplicationContextprotected ConfigurableListableBeanFactory obtainFreshBeanFactory() { refreshBeanFactory(); Return getBeanFactory(); }Copy the code
    Protected final void refreshBeanFactory() throws BeansException {// Determine whether beans exist in the BeanFactory. Beanfactory if (hasBeanFactory()) {destroyBeans(); closeBeanFactory(); } the try {/ / create a DefaultListableBeanFactory DefaultListableBeanFactory the beanFactory = createBeanFactory (); / / to serialize the beanFactory id the beanFactory. SetSerializationId (getId ()); // Customize some attributes of the Bean factory customizeBeanFactory(beanFactory); // Load the beantions loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); }} instead!Copy the code

    The sequence diagram is as follows:

  • BeanDefinition loads the parsing and registration subprocesses

    Resource localization: refers to the process for the defifinition of BeanDefifinition. In plain English, this means finding the XML text that defines the Javabean information

    And encapsulate it as a Resource object.

    BeanDefinition load: The user-defined Javabeans are represented as the data structures in the IoC container, and the data structures in the container are the BeanDefifinition

    The registration is done by handing the BeanDefinition to a CurrentHashMap maintained in the BeanFactory.

Bean creation process

In step 11 of initializing the container,

AbstractApplicationContext# refresh () # finishBeanFactoryInitialization# preInstantiateSingletons initializes all the rest of the Singleton beans

	/** * Finish the initialization of this context's bean factory, * initializing all remaining singleton beans. */
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		if(! beanFactory.hasEmbeddedValueResolver()) { beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal)); }// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false.false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		beanFactory.freezeConfiguration();

		/* * instantiate all........ * /
		// Instantiate all remaining (non-lazy-init) singletons.
		beanFactory.preInstantiateSingletons();
	}
Copy the code

Continue to enter the DefaultListableBeanFactory preInstantiateSingletons method in a class, see factories Bean or common Bean, GetBean -> doGetBean ->creatBean -> doCreatBean According to Spinrg code named logic we eventually find AbstractAutowireCapableBeanFactory# doCreateBean method.

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, Final @Nullable Object[] args) throws BeanCreationException {if (instanceWrapper == null) { InstanceWrapper = createBeanInstance(beanName, MBD, args); }... // Initialize the bean instance. Object exposedObject = bean; Try {// The Bean property fills the populateBean(beanName, MBD, instanceWrapper); ExposedObject = initializeBean(beanName, exposedObject, MBD); }...Copy the code

Enter the initializeBean() method

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() ! = null) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null; }, getAccessControlContext()); } else {// invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || ! MBD. IsSynthetic BeanPostProcessor ()) {/ / call the initialization method wrappedBean = applyBeanPostProcessorsBeforeInitialization (wrappedBean, beanName); } try {// call init-method invokeInitMethods(beanName, wrappedBean, MBD); } catch (Throwable ex) { throw new BeanCreationException( (mbd ! = null ? mbd.getResourceDescription() : null), beanName, "Invocation of init method failed", ex); } if (mbd == null || ! Mbd.issynthetic ()) {// Initialize the method after calling BeanPostProcessor (where AOP implements dynamic proxies) wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }Copy the code

To summarize the above process, the Bean lifecycle diagram can be obtained:

Principle of lazy-init lazy loading mechanism

public void preInstantiateSingletons() throws BeansException { ... List<String> beanNames = new ArrayList<>(this.beanDefinitionNames); // Trigger initialization of all non-lazy singleton beans... // Init lazy loaded Bean for (String beanName: beanNames) {... }}Copy the code

Initialization of normal beans is performed during the container-initiated initialization phase, whereas lazy-init=true beans are fired when context.getBean() is first called from the container. Spring starts by parsing all bean information (including XML and annotations) into beanDefinitions that Spring recognizes and storing them in a Hashmap for initialization. Each BeanDefinition is then processed. Lazy loads are not processed during container initialization, while others are initialized and dependency injected during container initialization.

conclusion

  • For beans decorated as lazy-init, the Spring container does not init and dependency injection during the initialization phase, but only when the getBean is first initialized and dependency injected
  • For non-lazy-loaded beans, the getBean is fetched from the cache because the bean has already been initialized and cached during container initialization

IoC cycle dependency issues

Circular dependencies are circular references, in which two or more beans hold each other and form a closed loop. For example, A depends on B, B depends on C, and C depends on A.

The cycle dependency scenarios in Spring are:

  • Constructor loop dependencies (constructor injection)
  • Circular dependencies for Field properties (set injection)

Because Spring’s theory of loop dependency is based on Java reference passing, object properties can be set later when an object reference is retrieved, but the constructor is called before the reference is retrieved, so there is no way to resolve the constructor’s loop dependency. Constructor circular dependencies problem cannot be solved, can only throw BeanCurrentlyInCreationException abnormalities, when solving attribute circular dependencies, spring is exposed in advance object, the method of the object reference not set the value of an attribute exposed in advance.

Spring resolves loop dependencies through setXxx or @autoWired methods by exposing an ObjectFactory object ahead of time. Simply put, after ClassA calls the constructor to initialize the object, ObjectFactory exposes ClassA instantiated objects to the Spring container before calling ClassA’s setClassB method.

  • Cyclic dependency processing mechanism

    Prototype bean constructor parameter loop dependency (unable to resolve)

    Spring will error handle the initialization of the prototype bean either through the constructor parameter cyclic dependency or through the setXxx method. Based on Java reference passing, when obtaining a reference to an object, the properties of the object can be set later. Spring does this by exposing an ObjectFactory object ahead of time. Simply put, after ClassA calls the constructor to initialize the object, ObjectFactory exposes ClassA instantiated objects to the Spring container before calling ClassA’s setClassB method.

    boolean earlySingletonExposure = (mbd.isSingleton() &&
    this.allowCircularReferences &&
     isSingletonCurrentlyInCreation(beanName));
     if (earlySingletonExposure) {
     if (logger.isDebugEnabled()) {
     logger.debug("Eagerly caching bean '" + beanName +
     "' to allow for resolving potential circular references");
     }
     // Inject the initialized object into the container ahead of time with the ObjectFactory object
     addSingletonFactory(beanName, new ObjectFactory<Object>() {
     @Override
     public Object getObject(a) throws BeansException {
     returngetEarlyBeanReference(beanName, mbd, bean); }}); }Copy the code

Spring’s cyclic dependencies

Spring AOP advanced applications

AOP nature

AOP essence: to enhance crosscutting logic without changing the original business logic, crosscutting logic code is often permission verification code, logging code, transaction control code, performance monitoring code.

AOP related terms

Join points: special timing points, such as method start, method end, normal operation end, method exception, etc., are called join points. Every method in a project has a join point, and a join point is a candidate point

Spring uses AspectJ syntax to describe Advice enhancements: First level: refers to the second level of crosscutting logic: Azimuth points (by adding crosscutting logic to some connection points, they are called azimuth points and describe specific specific times) Aspect aspects: The Aspect concept is a comprehensive Aspect Aspect of the above concept = pointcut + enhancement = pointcut (locking method) + azimuth point (special timing in locking method) + crosscutting logic

AOP proxy selection for AOP in Spring

By default, Spring chooses whether to use JDK or CGLIB based on whether the proxied object implements an interface. Spring selects CGLIB when the proxied object does not implement any interface. When the proxied object implements the interface, Spring selects the JDK’s official proxy technology. We can configure Spring to enforce the use of CGLIB.

How AOP is configured in Spring

In Spring’s AOP configuration, as in the IoC configuration, three types of configuration are supported. Type 1: Configure using XML Type 2: Configure using XML+ annotations Type 3: Configure using pure annotations

Implementation of AOP in Spring

Five types of Advice:

1. Pre-notification

2. Post notification

2. Exception notification

4. Final notice

5. Surround notifications

  • Using XML Configuration

    • Introducing coordinates

      <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-aop</artifactId>
       <version>5.1.12. RELEASE</version>
      </dependency>
      <dependency>
       <groupId>org.aspectj</groupId>
       <artifactId>aspectjweaver</artifactId>
       <version>1.9.4</version>
      </dependency>
      Copy the code
    • AOP core configuration

      <beans xmlns=" xmlns:aop="http://www.springframework.org/schema/aop"
             xsi:schemaLocation=" http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd ">
      
      
      <! -- Aspect = pointcut (locking method) + azimuth point (special moment in locking method) + crosscutting logic -->
          <aop:config>
              <aop:aspect id="logAspect" ref="logUtils">
      
                  <! Pointcut locks the method we are interested in, using AspectJ syntax expressions -->
                  <! --<aop:pointcut id="pt1" expression="execution(* *.. *. * (..) ) "/ > -- >
                  <aop:pointcut id="pt1" expression="execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..) )"/>
      
      
                  <! -- pointcut,pointcut -->
                  <! -- AOP :before -->
                  <aop:before method="beforeMethod" pointcut-ref="pt1"/>
                  <! Aop :after, final notification, execute anyway -->
                  <! -- AOP :after-returnning -->
                  <aop:around method="arroundMethod" pointcut-ref="pt1"/>
      
              </aop:aspect>
          </aop:config>
      Copy the code
  • Use XML+ annotations

    • Turn on Spring support for annotation AOP in XML

      <! Enable Spring support for annotation AOP -->
      <aop:aspectj-autoproxy/>
      Copy the code
    • Section class code:

      @component@aspect Public class LogUtil {/** * step 1: Write a method * Step 2: use the @pointcut annotation in the method * Step 3: Provide a Pointcut expression for the annotation's value property * detail: * 1. When referring to pointcut expressions, it must be the method name +(), such as "pointcut()". * 2. In the current section, can directly write method name. Use in other facets must be fully qualified method names. */ @Pointcut("execution(* com.lagou.service.impl.*.*(..) )") public void pointcut(){} @Before("pointcut()") public void beforePrintLog(JoinPoint jp){ Object[] args = jp.getArgs(); System.out.println(" Pre-notification: beforePrintLog, arguments are: "+ arrays.toString (args)); } @AfterReturning(value = "pointcut()",returning = "rtValue") public void afterReturningPrintLog(Object rtValue){ System.out.println(" afterReturningPrintLog, return: "+rtValue); } @AfterThrowing(value = "pointcut()",throwing = "e") public void afterThrowingPrintLog(Throwable e){ System.out.println(" Exception notification: afterThrowingPrintLog, exception is: "+e); } @after ("pointcut()") public void afterPrintLog(){system.out.println (" afterPrintLog"); } @param PJP * @return */ @around ("pointcut()") public Object aroundPrintLog(ProceedingJoinPoint PJP){ Object rtValue = null; Out.println (" out.println "); Object[] args = pjp.getargs (); Proceed (args); // proceed(args); Println (" postnotification "); // Postnotification system.out.println (" postnotification "); }catch (Throwable t){system.out.println (" Throwable t "); t.printStackTrace(); } system.out.println (" system.out.println "); } return rtValue; }}Copy the code
  • Use a pure annotation configuration

    Replace the configuration of the enabled function in the configuration file.

    Add the configuration in config

    @EnableAspectJAutoProxy 
    Copy the code
  • About AspectJ pointcut expressions

    Examples of pointcut expressions used:

    Fully qualified method name Access modifier return value package name. Package name. Package Name. Class Name. Method Name (parameter list) Public void com. Lagou. Service. Impl. TransferServiceImpl. UpdateAccountByCardNo (c om. Lagou. Pojo. Account) access modifier can omit void Com. Lagou. Service. Impl. TransferServiceImpl. UpdateAccountByCardNo (c om. Lagou. Pojo. Account) can use the * return value, Said any return value * com. Lagou. Service. Impl. TransferServiceImpl. UpdateAccountByCardNo (c om. Lagou. Pojo. Account) package name can be used. Represents any package, but has several levels of packages, must write several *.... TransferServiceImpl. UpdateAccountByCardNo (com) lagou. Pojo. Accou nt) package name can be used.. Represents the current package and its subpackages *.. TransferServiceImpl. UpdateAccountByCardNo (com) lagou. Pojo. Account) the name of the class and method names, can be used. Represents any class, any method *... (com.lagou.pojo.Account) Parameter list, which can use specific types Basic type write directly Type name: int Reference type must write fully qualified class name: java.lang.String Parameter list can use *, which indicates any parameter type, but must have arguments * *.. *.*(*) Argument lists can use.. , indicates that the parameter is optional. Arguments can be of any type * *.. *. * (..) Full wildcard mode: * *.. *. * (..)Copy the code

Spring’s support for declarative transactions

Programmatic transactions: add transaction control code to the business code. Such transaction control mechanism is called programmatic transaction declarative transactions. The purpose of transaction control is achieved through XML or annotation configuration

  • Four characteristics of transactions

    Four properties of ACID

    • Atomicity: Indicates that the operation of a transaction is an atomic, indivisible, smallest unit. All or nothing.

    • Consistency: Indicates that the database status is consistent before and after a transaction occurs.

    • Isolation: Indicates that the execution of transactions is isolated from each other, and the execution of one transaction cannot affect another.

      For example: transaction 1 raises employee’s salary by 2000 yuan, but transaction 1 has not been submitted. Employee initiates transaction 2 to query salary, and finds that the salary has been increased by 2000 yuan, and reads the data not submitted by transaction 1 (dirty reading).

    • Durability: Transactions that change database data are permanent and non-returnable, meaning that data in the database is modified once a transaction is committed. At the same time, the database failure does not affect the data.

  • Transaction isolation level

    Regardless of the isolation level, the following situations occur: dirty reads for the isolation level in dealing with transaction concurrency: a transaction in one thread reads uncommitted data in another thread. Non-repeatable read: when a transaction in one thread reads an update that has been committed by another thread: Employees A transaction 1, query salary, salary is 1 w, transaction 1 has not closed at this time Launched A transaction 2 financial personnel, give employees A piece of 2000 dollars, and submit the transaction staff through transaction 1 again launched A query request, found that wage is 1.2 w, originally to can not read out 1 w, called not repeatable read virtual (phantom read) : A transaction in one thread reads an INSERT or DELETE that has been committed in another thread.

    The database defines four isolation levels: Serializable: Can avoid dirty read, unrepeatable read, and virtual read. Repeatable read (serialization) highest Repeatable read: can avoid dirty read and unrepeatable read. Second, rows to be updated are locked Read COMMITTED: this avoids dirty reads. Unrepeatable reads and phantom reads must occur. Read uncommitted: The lowest level, and none of the above can be guaranteed. (Read unsubmitted) minimum

    MySQL’s default isolation level is: REPEATABLE READ

  • Propagation behavior of transactions

    Transactions are usually controlled at the service layer. If A method of the service layer calls another method of the service layer, B and A method have already been added with transaction control, then when A calls B, some negotiation of the transaction needs to be carried out, which is called transaction propagation behavior. A calls B, and we observe from B’s point of view to define the propagation behavior of the transaction

  • The transaction API in Spring

    PlatformTransactionManager

    Public interface PlatformTransactionManager {/ * * * * / transaction state information is TransactionStatus getTransaction (@ Nullable TransactionDefinition definition) throws TransactionException; /** * Commit the transaction */ void commit(TransactionStatus status) throws TransactionException; /** * rollback the transaction */ void rollback(TransactionStatus status) throws TransactionException; }Copy the code

    This interface is Spring’s transaction manager core interface. Spring itself does not support transaction implementation, but is responsible for providing standards for what transactions are supported at the bottom of the application. This is also a concrete application of the policy pattern. There are also specific policies built into the Spring framework for us. Slightly, for example: DataSourceTransactionManager, HibernateTransactionManager and so on. (DataSourceTransactionManager is ultimately crosscutting logic code, declarative transaction have to do is using Aop (dynamic proxy) to weave to the business transaction control logic code

  • Spring declarative transaction configuration

    It’s essentially a slice

    • Pure XML

      <tx:advice id="txAdvice" transaction-manager="transactionManager">
       <! Customize transaction details, propagation behavior, isolation level, etc.
       <tx:attributes>
       <! -- General configuration -->
       <tx:method name="*" read-only="false"
      propagation="REQUIRED" isolation="DEFAULT" timeout="1"/>
       <! -- Coverage configuration for queries -->
       <tx:method name="query*" read-only="true"
      propagation="SUPPORTS"/>
       </tx:attributes>
       </tx:advice>
       <aop:config>
       <! Advice-ref reference enhancement = crosscutting logic + azimuth -->
       <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..) )"/>
       </aop:config>
      Copy the code
    • A half note

      The XML configuration

      <! - configuration transaction manager - > < bean id = "transactionManager" class = ". Org. Springframework. JDBC datasource. DataSourceTransactionManage r "> <property name="dataSource" ref="dataSource"></property> </bean> <! <tx:annotation-driven transactionManager ="transactionManager"/>Copy the code

      Add the @Transactional annotation to an interface, class, or method

      @Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
      Copy the code
    • All annotations

      In the Spring configuration on the class add @ EnableTransactionManagement annotations

      @EnableTransactionManagement// Enable Spring annotation transaction support
      public class SpringConfiguration {}Copy the code

Spring AOP source depth analysis

Proxy object creation process

AOP source code analysis of Spirng

Spring declarative transaction control

@ EnableTransactionManagement hs.1-note 1) by introducing the @ import TransactionManagementConfigurationSelector class its selectImports method to import the other two categories: AutoProxyRegistrar and ProxyTransactionManagementConfiguration 2) registerBeanDefinitions AutoProxyRegistrar analysis method, the introduction of the other classes, InfrastructureAdvisorAutoProxyCreator, introduced by AopConfigUtils. RegisterAutoProxyCreatorIfNecessary (registry), It inherits Abstractauto Xycreator, Is a rear handler class 3) ProxyTransactionManagementConfiguration is an added @ Configuration annotation Configuration class (registered bean) registration affairs enhancer (injection properties parser, transaction interceptor) attributes the parser: AnnotationTransactionAttributeSource, internal hold a parser collection Set < TransactionAnnotationParser > annotationParsers; Specific use SpringTransactionAnnotationParser parser, used to resolve @ the transaction attribute of Transactional transaction interceptor: TransactionInterceptor implements the MethodInterceptor interface, which is a generic interceptor that merges with aop enhancements before producing proxy objects. The invokeWithinTransaction method, which ultimately affects the broker object TransactionInterceptor, triggers the original business logic call (enhanced transaction)Copy the code