环境说明
- JDK 17
- Spring 6.0.6
环境准备
添加 Spring 依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.6</version>
</dependency>
Bean Aware
Spring提供了一些以Aware结尾的接口,实现了Aware接口的bean在被初始化之后,可以获取相应资源。即实现了Aware接口的类会获得某些感知能力,Spring容器会在Bean被加载时,根据类实现的感知接口,调用类中实现的对应感知方法。
比如 BeanNameAware 接口,这个接口获取的资源就是BeanName:
@Component
public class Student implementsBeanNameAware {
public void study(){
System.out.println("室友还在打游戏,我狠狠的学Java,太爽了");
}
@Override
public void setBeanName(String name) {
System.out.println("我在加载阶段获取了Bean 的名字 " + name);
}
}
又比如BeanClassLoaderAware,它能够使得我们在Bean加载阶段就获取到当前Bean的类加载器:
@Component
public class Student implements BeanClassLoaderAware{
public void study(){
System.out.println("室友还在打游戏,我狠狠的学Java,太爽了");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println(classLoader);
}
}
任务调度
有时我们希望使用多线程来处理我们的结果或是执行一些定时任务,到达指定时间再去执行。这时我们首先想到的就是创建一个新的线程来处理,或是使用TimerTask来完成定时
异步任务
异步任务执行,需要使用Spring异步任务支持,在配置类上添加@EnableAsync
注解:
@EnableAsync
@Configuration
public class MainConfig {
...
接着在需要异步执行的方法上添加@Async
注解,即可将此方法标记为异步,当此方法被调用时,会异步执行,也就是新开一个线程执行,而不是在当前线程执行:
@Component
public class Student{
public void syncTest() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"我是同步执行的方法,开始...");
Thread.sleep(5000);
System.out.println("我是同步执行的方法,结束!");
}
@Async
public void asyncTest() throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"我是异步执行的方法,开始...");
Thread.sleep(5000);
System.out.println("我是异步执行的方法,结束!");
}
}
测试:
public static void main(String[] args) throws InterruptedException {
ApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Student stu = context.getBean(Student.class);
stu.asyncTest(); // 异步执行
stu.syncTest(); // 同步执行
}
执行结果显示:异步执行的任务是在其他线程启动的,所以说并不会在当前线程阻塞,可以看到马上就开始执行下一行代码,调用同步执行的任务了。
定时任务
定时任务即就是指定在哪个时候再去执行。Spring中的定时任务是全局性质的,当Spring程序启动后,定时任务也就跟着启动了,可以在配置类上添加@EnableScheduling
注解:
@EnableScheduling
@Configuration
public class MainConfig {
...
接着直接在配置类里面编写定时任务,把要做的任务写成方法,并添加@Scheduled
注解:
@EnableScheduling
@Configuration
public class MainConfig {
@Scheduled(fixedRate = 2000) //单位是毫秒,这里是每两秒钟打印一次
public void task(){
System.out.println("我是定时任务!"+new Date());
}
...
@Scheduled
中有很多参数,这里需要指定’cron’, ‘fixedDelay(String)’, or 'fixedRate(String)'的其中一个,否则无法创建定时任务:
- fixedDelay:在上一次定时任务执行完之后,间隔多久继续执行。
- fixedRate:无论上一次定时任务有没有执行完成,两次任务之间的时间间隔。
- cron:如果嫌上面两个不够灵活,你还可以使用cron表达式来指定任务计划。
监听器
监听实际上就是等待某个事件的触发,当事件触发时,对应事件的监听器就会被通知。
要编写监听器,只需要让Bean继承ApplicationListener就可以了,并且将类型指定为对应的Event事件,这样,当发生某个事件时就会通知我们:
@Component
public class TestListener implements ApplicationListener<ContextRefreshedEvent> {
// ContextRefreshedEvent 事件会在Spring容器初始化完成会触发一次
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println(event.getApplicationContext());
}
}
当然,还可以自定义事件:
// 自定义事件
public class TestEvent extends ApplicationEvent { //自定义事件需要继承ApplicationEvent
public TestEvent(Object source) {
super(source);
}
}
// 编写监听器
@Component
public class TestListener implements ApplicationListener<TestEvent> {
@Override
public void onApplicationEvent(TestEvent event) {
System.out.println("发生了一次自定义事件,成功监听到!");
}
}
// 设定在定时任务中每秒钟发生一次这个事件
@Component
public class TaskComponent implements ApplicationEventPublisherAware {
ApplicationEventPublisher publisher;
@Scheduled(fixedRate = 1000) //一秒一次
public void task(){
publisher.publishEvent(new TestEvent(this));
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
}