Interesting Spring: Understanding Aware, Asynchronous Programming, Scheduled Tasks

Posted by twilightnights on Sat, 28 Mar 2020 03:02:22 +0100

Hello, I'm Silent Wang Er, a programmer as tall as Huang Jiaju and as beautiful as Liu Dehua (I don't trust to watch around friends).From the age of the two idols, you can tell that I'm over 10 years old, but to be honest, I've always believed that I'm only 18 because learning makes me young.This article is going to talk about "Spring's Aware, Asynchronous Programming, Scheduled Tasks" in the form of a conversation with my three sisters.

My sister, Spring, has not seen such a presumptuous Title before?"It's amazing what you're saying." Yes, the title of this article is so cool. How else would you click in?

I have a beautiful sister (see picture above, how has it changed?Can't dream a day yet). What's her name?I think smart readers can guess: Silence King Three, yes, age 36.My parents are considering letting her learn from me as a serious Java programmer.I was against it at first, because programmers are prone to hair loss in this industry, and girls are not suitable for hair loss.But life is hard. Instead of disagreeing, do something more positive, such as writing interesting articles to teach her.

"Ergo, I've heard that I'm looking forward to learning Spring's Aware, Asynchronous Programming, and Scheduled Tasks today."

"Alas, three sisters, look at your impatient eyes as round and big as the moon last night."

01,Spring Aware

"Ergo, it is said that Aware is meant for Bean to get the services of Spring Container. Can you tell me more about it?"

"No problem."

Beans generally do not need to know the state of containers or use them directly, but in some cases, they need to operate directly on containers in Beans, which can be accomplished through a specific Aware interface.Common Spring Aware interfaces include the following:

Aware Subinterface describe
BeanNameAware Gets the name of the Bean in the container
BeanFactoryAware Once a Bean is created by a container, there will be a corresponding BeanFactory through which you can access the container directly
ApplicationContextAware Once the Bean is initialized, it is injected into the ApplicationContext through which you can access the container directly
MessageSourceAware Get text information about Message Source
ResourceLoaderAware Get the resource loader to get the external resource file

1)BeanNameAware

Create a new MyBeanName class with the following contents:

public class MyBeanName implements BeanNameAware {
    @Override
    public void setBeanName(String beanName) {
        System.out.println(beanName);
    }
}

MyBeanName implements the BeanNameAware interface and overrides the setBeanName() method.The beanName parameter represents the name of the Bean registered in the Spring container.

Create a new Config class with the following contents:

@Configuration
public class Config {
    @Bean(name = "myCustomBeanName")
    public MyBeanName getMyBeanName() {
        return new MyBeanName();
    }
}

The @Bean annotation is used on the getMyBeanName() method to indicate that the current method returns a Bean object (MyBeanName) and specifies the name of the Bean by the name attribute as "myCustomBeanName".

Create a new BeanNameMain class with the following code:

public class BeanNameMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanNameConfig.class);
        MyBeanName myBeanName = context.getBean(MyBeanName.class);
        context.close();
    }
}

The output of the program is as follows:

myCustomBeanName

If the @Bean() comment (name = "myCustomBeanName)" is removed, the output of the program will be the method name "getMyBeanName" of the getMyBeanName() of the BeanNameConfig class.

2)BeanFactoryAware

Create a new MyBeanFactory class with the following contents:

public class MyBeanFactory implements BeanFactoryAware {
    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void getMyBeanName() {
        MyBeanName myBeanName = beanFactory.getBean(MyBeanName.class);
        System.out.println(beanFactory.isSingleton("myCustomBeanName"));
        System.out.println(beanFactory.isSingleton("getMyBeanFactory"));
    }
}

With the setBeanFactory() method, you can assign a BeanFactory in a container to a beanFactory, a member variable of the MyBeanFactory class, so that you can use BeanFactory in the getMyBeanName() method.

Instances of beans can be obtained by the getBean() method; isSingleton() method can be used to determine if a Bean is a singleton.

Append the Bean of MyBeanFactory to the Config class:

@Configuration
public class Config {
    @Bean(name = "myCustomBeanName")
    public MyBeanName getMyBeanName() {
        return new MyBeanName();
    }

    @Bean
    public MyBeanFactory getMyBeanFactory() {
        return new MyBeanFactory();
    }
}

Create a new BeanFactoryMain class with the following code:

public class BeanFactoryMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        MyBeanFactory myBeanFactory = context.getBean(MyBeanFactory.class);
        myBeanFactory.getMyBeanName();
        context.close();
    }
}

Once MyBeanFactory is initialized, the getMyBeanName() method can be called, and the program outputs the following results:

myCustomBeanName
true
true

The results met our expectations: MyBeanName was named "myCustomBeanName", and MyBeanName and MyBeanFactory scope s were singleton s.

3) Several other Aware interfaces are no longer exemplified.Normally, do not implement the Aware interface because it will couple the Bean with the Spring framework.

02. Asynchronous programming

"Ergo, Spring is said to be able to program asynchronously through @Async. Can you tell me more about it?"

"No problem."

Create a new AsyncService class with the following contents:

public class AsyncService {
    @Async
    public void execute() {
        System.out.println(Thread.currentThread().getName());
    }
}

The @Async comment is used on the public method to indicate that the execute() method is an asynchronous method.

Create a new AsyncConfig class with the following contents:

@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean
    public AsyncService getAsyncService() {
        return new AsyncService();
    }
}

Use the @EnableAsync annotation on the configuration class to turn on asynchronous programming, otherwise the @Async annotation will not work.

Create a new AsyncMain class with the following contents:

public class AsyncMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AsyncConfig.class);
        AsyncService service = context.getBean(AsyncService.class);
        for (int i = 0; i < 10; i++) {
            service.execute();
        }
    }

The program output is as follows:

SimpleAsyncTaskExecutor-1
SimpleAsyncTaskExecutor-9
SimpleAsyncTaskExecutor-7
SimpleAsyncTaskExecutor-8
SimpleAsyncTaskExecutor-10
SimpleAsyncTaskExecutor-3
SimpleAsyncTaskExecutor-2
SimpleAsyncTaskExecutor-4
SimpleAsyncTaskExecutor-6
SimpleAsyncTaskExecutor-5

OK, the result is as expected, asynchronous programming is implemented.As you can see, Spring provides a default impleAsyncTaskExecutor to execute threads, and we can also configure the executor at the method and application levels.

1) Method Level

Create a new AsyncConfig class with the following contents:

@Configuration
@EnableAsync
public class AsyncConfig {
    @Bean
    public AsyncService getAsyncService() {
        return new AsyncService();
    }

    @Bean(name = "threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        return executor;
    }
}

A Bean with a return type of Executor was created in the configuration class, whose name was defined as "threadPoolTaskExecutor", and the core thread pool size of ThreadPoolTaskExecutor was reset, defaulting to 1 and now modified to 5.

New AsyncService class, as follows:

public class AsyncService {
    @Async("threadPoolTaskExecutor")
    public void execute() {
        System.out.println(Thread.currentThread().getName());
    }
}

The @Async annotation requires the thread pool executor "threadPoolTaskExecutor" that we previously configured.

Create a new AsyncMain class with the following contents:

public class AsyncMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AsyncConfig.class);
        AsyncService service = context.getBean(AsyncService.class);
        for (int i = 0; i < 10; i++) {
            service.execute();
        }
    }
}

The program runs as follows:

threadPoolTaskExecutor-1
threadPoolTaskExecutor-2
threadPoolTaskExecutor-4
threadPoolTaskExecutor-3
threadPoolTaskExecutor-5
threadPoolTaskExecutor-3
threadPoolTaskExecutor-2
threadPoolTaskExecutor-4
threadPoolTaskExecutor-1
threadPoolTaskExecutor-5

As you can see from the results, the thread pool executor became "threadPoolTaskExecutor" with a size of 5.

2) Application Level

Create a new AsyncConfig class with the following contents:

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
    @Bean
    public AsyncService getAsyncService() {
        return new AsyncService();
    }

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3);
        executor.initialize();
        return executor;
    }
}

You need to implement the AsyncConfigurer interface and override the getAsyncExecutor() method, this time setting the thread pool size to 3.Note that the executor will execute the initialize() method once.

New AsyncService class, as follows:

public class AsyncService {
    @Async
    public void execute() {
        System.out.println(Thread.currentThread().getName());
    }
}

Create a new AsyncMain class with the following contents:

public class AsyncMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AsyncConfig.class);
        AsyncService service = context.getBean(AsyncService.class);
        for (int i = 0; i < 10; i++) {
            service.execute();
        }
    }
}

The program runs as follows:

ThreadPoolTaskExecutor-2
ThreadPoolTaskExecutor-2
ThreadPoolTaskExecutor-2
ThreadPoolTaskExecutor-2
ThreadPoolTaskExecutor-2
ThreadPoolTaskExecutor-2
ThreadPoolTaskExecutor-2
ThreadPoolTaskExecutor-2
ThreadPoolTaskExecutor-1
ThreadPoolTaskExecutor-3

As you can see from the results, the thread pool executor became ThreadPoolTaskExecutor with a size of 3.

03. Scheduled tasks

"Ergo, Spring is said to be able to accomplish planned tasks through @Scheduled. Can you give me more details on how to do this?"

"No problem."

Create a new ScheduledService class with the following contents:

@Service
public class ScheduledService {
    @Scheduled(fixedDelay = 1000)
    public void scheduleFixedDelayTask() {
        System.out.println(
                "Execute tasks after a fixed period of time - " + System.currentTimeMillis() / 1000);
    }

    @Scheduled(fixedRate = 1000)
    public void scheduleFixedRateTask() {
        System.out.println(
                "Perform tasks at a fixed frequency - " + System.currentTimeMillis() / 1000);
    }

    @Scheduled(cron = "0/2 * * * * ?")
    public void scheduleTaskUsingCronExpression() {
        long now = System.currentTimeMillis() / 1000;
        System.out.println(
                "Cron Expression Execution Task - " + now);
    }
}

The @Service annotation specifies that the ScheduledService class is a Bean for a business layer.The @Scheduled annotation specifies that the current method (return type void, no arguments) is a task execution method and three common uses are as follows:

1) Fixed Delay is used to ensure that there is an NMS delay between the completion time of the task execution and the start time of the next execution of the task, which must be completed before the next execution.

2) fixedRate is used to ensure that scheduled tasks are executed every nms, even though the last call may still be running.

3) Cron expressions are more flexible than fixedDelay and fixedRate, consisting of seven parts separated by spaces, and their complete format is as follows:

Seconds Minutes Hours Day-of-Month Month Day-of-Week Year

The words are so simple that I don't have to translate them.Year is optional.Common examples are as follows:

*/5 * * * * *?? Executes every 5 seconds
0 */1 * * *?? Executes every 1 minute
0. 23 * *?? Executes once a day at 23 o'clock
0 0 1 * *?? Once a day at 1 am:
0 0 1 1 *? Once a month at 1 AM on 1st
0. 23 L *?? Executes at 23 o'clock on the last day of the month
0 0 1? * L. Executes once a week at 1 a.m. on Sunday morning
0 26,29,33 * * *?? Executed once in 26, 29, 33 minutes
0, 0, 13, 18, 21 * *? Each day at 0, 13, 18, 21 points is executed once a day

Create a new ScheduledConfig class with the following contents:

@Configuration
@EnableScheduling
@ComponentScan("high.scheduled")
public class ScheduledConfig {
}

The @EnableScheduling annotation is used to start scheduled tasks.The @ComponentScan annotation scans the classes under the current package and registers them as a Bean if it uses annotations such as @Service.

Create a new ScheduledMain class with the following contents:

public class ScheduledMain {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ScheduledConfig.class);
    }
}

The program runs as follows:

Fixed Frequency Execution Task - 1584666273
Task Execution After Fixed Time Period - 1584666273
Cron Expression Execution Task - 1584666274
Fixed Frequency Execution Task - 1584666274
Task Execution After Fixed Time Period - 1584666274
Fixed Frequency Execution Task - 1584666275
Task Execution After Fixed Time Period - 1584666275
Cron Expression Execution Task - 1584666276

As you can see from the results, if there is no conflict between tasks, the interval between fixedDelay tasks and fixedRate tasks is the same, one second; the interval between Cron expression tasks and the last task is two seconds.

"Brother, have you uploaded the sample code in this article to GitHub?"

"You're so kind, three sisters. Portal~"

"You've taught me really well, brother. I've learned it all. It's not dull at all."

"That must be done. Looking forward to the next one?"

"Of course, look forward to it, look forward to it, look forward to it."

Allow me to spit out warmly. I don't want this article to be blown out anymore. Would it be nice to encourage more for my hard work on originality (creativity + dry goods + fun)?Don't look at it. Give it a compliment. You are the most beautiful and handsome.

If you find this article helpful to you, please WeChat to search for "Silence King II" for the first time to read, reply to "666" [1024], there are 500G HD instructional videos (categorized) that I have prepared for you, and a copy of the face sorted by Dachang Technical Bullman.

Topics: Java Spring Programming Attribute