spring学习笔记(二)spring中的事件及多线程

简介: spring学习笔记(二)spring中的事件及多线程

 我们知道,在实际开发中为了解耦,或者提高用户体验,都会采用到异步的方式。这里举个简单的例子,在用户注册的sh时候,一般我们都会要求手机验证码验证,邮箱验证,而这都依赖于第三方。这种情况下,我们一般会通过新起一个线程或者消息中间件的方式去处理。


其实在spring中,本身就提供了publish-event-listener机制还有异步任务机制。通过这两种机制,能很好的帮助我们解耦我们的应用跟代码的管理


publish-event-listener机制:


我们先看代码:

/**
 * 配置类,主要为了扫面组件
 */
@Configuration
@ComponentScan("com.spring.publishevent")
public class Config {
}
/**
 * 
 * @Description: 事件类,必须实现ApplicationEvent
 * 
 */
public class MyEvent extends ApplicationEvent {
    private String msg;
    public MyEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }
    public String getMsg() {
        return msg;
    }
}
/**
 * @Author: dmz
 * @Description: 观察者,必须实现ApplicationListener,并指定泛型为我们的自定义事件
 * @Date: Create in 0:23 2019/3/15
 */
@Component
public class MyListener implements ApplicationListener<MyEvent> {
    @Override
    public void onApplicationEvent(MyEvent event) {
        System.out.println(event.getMsg());
    }
}
/**
 * @Author: dmz
 * @Description: 发布者,直接用我们的上下文对象进行发布,它继承了ApplicationEventPublisher
 * @Date: Create in 0:42 2019/3/15
 */
@Component
public class MyPublisher {
    @Autowired
    private ApplicationContext applicationContext;
    public void publish() {
        applicationContext.publishEvent(new MyEvent(this, "hello event"));
    }
}

运行结果:

image.png

原理分析:我们debug追踪下代码

微信图片_20221110210007.png

核心代码就是上面这一句:

先看第一个方法:getApplicationEventMulticaster()

微信图片_20221110210027.png

它其实就是返回当前类持有的ApplicationEventMulticaster这个接口的实现的引用,我们看下这个接口上的注释

/**
 * Interface to be implemented by objects that can manage a number of
 * {@link ApplicationListener} objects, and publish events to them.
...........

英文稍微好些的同学就能知道,这个接口其实就是管理了我们的listener,并且可以向它们发布事件


现在我们知道了getApplicationEventMulticaster()返回的其实一个发布者,我们的容器applicationContext其实就是调用这个对象去发布事件


并且它管理了我们所有的listener。


接下来我们继续看:multicastEvent(......)这个方法

微信图片_20221110210123.png

getApplicationListeners(event, type),其实就是返回了当前对象所管理的监听了当前事件的listener,之后在调用listener的invokeListener(listener, event)方法。

微信图片_20221110210158.png

段代码我们暂时忽略,稍后再讲

现在我们继续跟进invokeListener(....)方法,发现最终会调用到

微信图片_20221110210248.png

也就是我们实现了applicationListener接口所实现的方法,不难发现整个过程是同步的。


不过虽然是同步的,也能解耦我们的代码,这并不冲突。不仅如此,还能提高我们代码的复用性


在spring4.2以后,有一种更优雅的方式实现发布监听模式,不再需要我们去实现那么多接口,采用注解即可实现,代码如下:(配置类代码不变)

/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 0:20 2019/3/15
 */
public class MyEvent {
    private String msg;
    public MyEvent(String msg) {
        this.msg = msg;
    }
    public String getMsg() {
        return msg;
    }
}
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 1:32 2019/3/15
 */
@Data
@AllArgsConstructor
public class MySecondEvent {
    private String msg;
}
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 0:23 2019/3/15
 */
@Component
public class MyListener{
    @EventListener
    public void onApplicationEvent(MyEvent event) {
        System.out.println(event.getMsg());
    }
    @EventListener
    public void onApplicationEvent(MySecondEvent event) {
        System.out.println(event.getMsg());
    }
}
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 0:32 2019/3/15
 */
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(Config.class);
        applicationContext.publishEvent(new MyEvent("hello event"));
        applicationContext.publishEvent(new MySecondEvent("hello secondEvent"));
    }
}

运行结果如下:

image.png

原理不再分析了,其实跟第一种差不多


异步处理机制(多线程):


先看代码:

package com.spring.asycn.config;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 0:23 2019/3/16
 */
@Configuration
@EnableAsync
@ComponentScan("com.spring.asycn.service")
public class AsyncConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(10);
        threadPoolTaskExecutor.setMaxPoolSize(50);
        threadPoolTaskExecutor.setQueueCapacity(5);
        threadPoolTaskExecutor.setKeepAliveSeconds(1);
        threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncUncaughtExceptionHandler() {
            @Override
            public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
                System.out.println("出现异常啦~~~~~~");
            }
        };
    }
}
package com.spring.asycn.service;
import org.springframework.stereotype.Component;
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 0:24 2019/3/16
 */
@Component
public class SyncService {
    //@Async
    public  void test(int i) {
            System.out.println(Thread.currentThread().getName() + "执行方法______________"+i);
    }
}
package com.spring.asycn;
import com.spring.asycn.config.AsyncConfig;
import com.spring.asycn.service.SyncService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
 * @Author: dmz
 * @Description:
 * @Date: Create in 0:23 2019/3/16
 */
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext =
                new AnnotationConfigApplicationContext(AsyncConfig.class);
        SyncService bean = applicationContext.getBean(SyncService.class);
        for (int i = 0; i < 100; i++) {
            bean.test(i);
        }
    }
}

我们将test方法上的@Async注解打开跟注释分别执行可以得到如下结果:

这个注释掉的结果:

微信图片_20221110210541.png

这是打开的结果:

微信图片_20221110210635.png

很明显,一个是单线程,一个是多线程并发执行,线程池就是我们配置的线程池

相关文章
|
7月前
|
监控 Java 应用服务中间件
微服务——SpringBoot使用归纳——为什么学习Spring Boot
本文主要探讨为什么学习Spring Boot。从Spring官方定位来看,Spring Boot旨在快速启动和运行项目,简化配置与编码。其优点包括:1) 良好的基因,继承了Spring框架的优点;2) 简化编码,通过starter依赖减少手动配置;3) 简化配置,采用Java Config方式替代繁琐的XML配置;4) 简化部署,内嵌Tomcat支持一键式启动;5) 简化监控,提供运行期性能参数获取功能。此外,从未来发展趋势看,微服务架构逐渐成为主流,而Spring Boot作为官方推荐技术,与Spring Cloud配合使用,将成为未来发展的重要方向。
206 0
微服务——SpringBoot使用归纳——为什么学习Spring Boot
|
12月前
|
编解码 数据安全/隐私保护 计算机视觉
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
如何使用OpenCV进行同步和异步操作来打开海康摄像头,并提供了相关的代码示例。
703 1
Opencv学习笔记(十):同步和异步(多线程)操作打开海康摄像头
|
6月前
|
Java Spring
Spring框架的学习与应用
总的来说,Spring框架是Java开发中的一把强大的工具。通过理解其核心概念,通过实践来学习和掌握,你可以充分利用Spring框架的强大功能,提高你的开发效率和代码质量。
148 20
|
9月前
|
Java Spring
Java Spring Boot监听事件和处理事件
通过上述步骤,我们可以在Java Spring Boot应用中实现事件的发布和监听。事件驱动模型可以帮助我们实现组件间的松耦合,提升系统的可维护性和可扩展性。无论是处理业务逻辑还是系统事件,Spring Boot的事件机制都提供了强大的支持和灵活性。希望本文能为您的开发工作提供实用的指导和帮助。
330 15
|
10月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
188 1
|
12月前
|
Java Maven Spring
springboot学习一:idea社区版本创建springboot项目的三种方式(第三种为主)
这篇文章介绍了在IntelliJ IDEA社区版中创建Spring Boot项目的三种方法,特别强调了第三种方法的详细步骤。
9384 0
springboot学习一:idea社区版本创建springboot项目的三种方式(第三种为主)
|
11月前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
229 9
|
12月前
|
前端开发 Java 数据库
SpringBoot学习
【10月更文挑战第7天】Spring学习
140 9
|
12月前
|
XML Java 数据格式
Spring学习
【10月更文挑战第6天】Spring学习
92 1
|
12月前
|
Java 测试技术 开发者
springboot学习四:Spring Boot profile多环境配置、devtools热部署
这篇文章主要介绍了如何在Spring Boot中进行多环境配置以及如何整合DevTools实现热部署,以提高开发效率。
496 2