Implementation of Spring AOP asynchronous operation and Cache operation (PROJECT04_DAY03_01)

5. Implementation of spring AOP asynchronous operation

5.1 asynchronous scenario analysis

In the process of developing the system, the performance of the system is usually considered. An important idea to improve the system performance is to change "serial" to "parallel". Speaking of "parallelism" is naturally inseparable from "asynchrony". Today, let's talk about how to use Spring's @ Async asynchronous annotation.

5.2 asynchronous implementation of spring Services

5.2.1 start asynchronous configuration

In the annotation based configuration, the @ EnableAsync annotation is used to declare asynchronous startup. In the Spring Boot project, the @ EnableAsync annotation is applied to the startup class. The code example is as follows:

@EnableAsync //When the spring container starts, a thread pool is created
   @SpringBootApplication
   public class Application {
        public static void main(String[] args) {
                SpringApplication.run(Application.class, args);
        }
}

5.2.2 @ Async annotation application in spring

On business methods that need to be executed asynchronously, use the @ Async method for asynchronous declaration.

 @Async
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void saveObject(SysLog entity) {
  System.out.println("SysLogServiceImpl.save:"+Thread.currentThread().getName());
      sysLogDao.insertObject(entity);
      //try{Thread.sleep(5000);}catch(Exception e) {}
    }

If it is necessary to obtain the execution results of asynchronous methods in the business layer, you can refer to the following code design for implementation:

   @Transactional(propagation = Propagation.REQUIRES_NEW)
   @Async
   @Override
   public Future<Integer> saveObject(SysLog entity) {
        System.out.println("SysLogServiceImpl.save:"+Thread.currentThread().getName());
        int rows=sysLogDao.insertObject(entity);
        //try{Thread.sleep(5000);}catch(Exception e) {}
        return new AsyncResult<Integer>(rows);
   }

The AsyncResult object can encapsulate the execution results of asynchronous methods. If the outside world needs asynchronous method results, the results can be obtained through the get method of Future object.

When we need to configure the connection pool provided by the spring framework, we can refer to the following code:

spring:
  task:
    execution:
      pool:
        queue-capacity: 128
        core-size: 5
        max-size: 128
        keep-alive: 60000
        thread-name-prefix: db-service-task-

For the meaning of thread pool configuration parameters in the Spring framework, refer to the explanation in the ThreadPoolExecutor object.

Note: for @Async annotations, the worker thread is acquirement based on ThreadPoolTaskExecutor object, then the method described by @Async is invoked to enable the method to run on a worker thread to realize asynchronous operation. However, if the default rejection handling policy in the system and the exception handling during task execution can not meet our own business needs, I can customize the asynchronous thread pool. (for the default asynchronous configuration in SpringBoot, refer to the automatic configuration object TaskExecutionAutoConfiguration)

5.2.3 implementation of spring custom asynchronous pool (expansion)

In order to make the asynchronous pool in Spring better serve our business and avoid OOM as much as possible, you can customize the thread pool optimization design as follows: the key code is as follows:

package com.cy.pj.common.annotation;
@Slf4j
@Setter
@Configuration //This annotation describes a configuration object of the class to be managed by spring
//Read the data prefixed with spring.async.task in the spring configuration file and use the set method
 Inject into attribute
@ConfigurationProperties("spring.async.task")
public class SpringAsyncConfig implements AsyncConfigurer {
	private int corePoolSize = 5;
	private int maxPoolSize = 100;
	private int keepAliveSeconds = 60;
	private int queueCapacity=  128;
	private String threadNamePrefix = "tast===>";
	@Override
	public Executor getAsyncExecutor() {
		System.out.println("corePoolSize="+corePoolSize);
		ThreadPoolTaskExecutor executor = new 
		ThreadPoolTaskExecutor();
		executor.setCorePoolSize(corePoolSize);
		executor.setMaxPoolSize(maxPoolSize);
		executor.setKeepAliveSeconds(keepAliveSeconds);
		executor.setQueueCapacity(queueCapacity);
		executor.setThreadNamePrefix(threadNamePrefix);
		//Custom reject handling policy
		executor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
		@Override
		public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
			log.error("The queue is full and no threads are available");
		}
	});
		executor.initialize();
		return executor;
	}
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return new AsyncUncaughtExceptionHandler() {
		@Override
		public void handleUncaughtException(Throwable ex, Method method, Object... params) {
			log.error("An error occurred while the task was executing {}",ex.getMessage());
		}
		};
	}
}

Where: @ ConfigurationProperties("async thread pool") means to read the configuration information prefixed with "async thread pool" in the application.yml configuration file and assign values to the corresponding properties through the set method of the described class. The key configurations of the connector pool in application.yml are as follows:

async-thread-pool:
       corePoolSize: 20
       maxPoolSize: 1000
       keepAliveSeconds: 30
       queueCapacity: 1000

Subsequently, in the business class, if we use the @ Async annotation to describe business methods, the thread in the ThreadPoolTaskExecutor pool object will be used to execute asynchronous tasks by default.

6. Implementation of Cache operation in spring AOP (extension)

6.1 cache scenario analysis

In the business method, we may call the data layer method to obtain the data in the database. If the frequency of accessing the data is relatively high, in order to improve the query efficiency and reduce the access pressure of the database, we can cache the data in the business layer

6.2 implementation of business cache application in spring

6.2.1 startup cache configuration

Add the @ EnableCaching annotation on the startup class of the project (SpringBoot project) to start the cache configuration. The key codes are as follows:

package com.cy;
/**
* Asynchronous automatic configuration takes effect)
 * @EnableCaching Annotation indicates startup cache configuration
 */
@EnableCaching
@SpringBootApplication
public class Application {
        public static void main(String[] args) {
                SpringApplication.run(Application.class, args);
        }
}

6.2.2 application cache configuration on business method

On the business methods that need to be cached, the @ Cacheable annotation is used to describe the method. It indicates that the return value of the method should be stored in the cache. If the data in the cache needs to be removed during the update operation, the @ CacheEvict annotation can be used on the update method to describe the other method. For example:

Step 1: use cache in the related module query related business methods. The key codes are as follows:

@Cacheable(value = "deptCache")
@Transactional(readOnly = true)
public List<Map<String,Object>> findObjects() {
....
}

The value of the value attribute represents the cache object to be used. The name is specified by yourself. The bottom layer is a map object. When adding data to the cache, the key defaults to the combination of the actual parameters of the method.

Step 2: clear the specified cache data when relevant modules are updated. The key codes are as follows:

@CacheEvict(value="deptCache",allEntries=true)
@Override
public int saveObject(SysDept entity) {...}

Where allEntries means to clear all.

Note: the cache application principle in spring is shown in figure-15:

Figure-15

6.2.3 implementation of custom cache in spring (extension)

In Spring, the underlying implementation of the default cache is a map object. If this map object can not meet our actual needs, we can store the data in the third-party cache system in the actual project

7. Summary

7.1 analysis of key and difficult points

What is AOP, what problems are solved, implementation principle and application scenario.
Basic steps and implementation process of AOP programming (taking the implementation based on AspectJ framework as an example).
The core object and application relationship in AOP programming.
Analysis of the implementation principle of AOP idea in Spring.
Configuration implementation based on annotation in AOP programming.
Transaction control based on annotation in AOP programming.
Implementation of asynchronous operation in AOP programming?
Cache application in AOP programming?

7.2 FAQ analysis

What is the OCP principle?
What is the DIP principle (dependency inversion)?
What is the single responsibility principle (SRP)?
What are the configurations of AOP in Spring? (XML, annotation)
What are the basic types of AOP notifications in Spring? (5 kinds)
How does AOP in Spring create proxy objects for Bean objects? (JDK,CGLIB)
How to specify the execution order of AOP aspects in Spring? (@Order)
The transaction control in the Spring monomer architecture project should be realized through the Connection object,?
How does Spring ensure that a thread has a Connection object? Implemented with ThreadLocal?
What problems may occur when multiple transactions are executed concurrently?
How to understand pessimistic lock and optimistic lock in database?
Do you know the isolation level of transactions? Do you know the specific application scenario?
......
....

7.3 Bug analysis

Pointcut application error, as shown in figure-17:

Figure-17

Problem analysis: check whether the introduction of pointcuts has lost "()"

Tags: Java Spring Spring Boot

Posted on Wed, 20 Oct 2021 16:10:32 -0400 by sigmon