From 25f4784daad586c498517105c2bd0f6e31d2b626 Mon Sep 17 00:00:00 2001 From: whaifree Date: Tue, 22 Oct 2024 23:23:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(springDemo):=20=E6=B7=BB=E5=8A=A0=20Server?= =?UTF-8?q?-Sent=20Events=20(SSE)=20=E5=8A=9F=E8=83=BD=E5=92=8C=E4=BB=A3?= =?UTF-8?q?=E7=90=86=E6=BC=94=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 SSEEmitter 类实现 Server-Sent Events功能 - 添加 ProxyDemo 类演示动态代理 - 更新 UserService 类,增加 Bean 生命周期相关注释 - 调整 application.yaml 文件格式 --- .../cn/whaifree/tech/proxy/ProxyDemo.java | 46 ++++++++ .../springdemo/controller/SSE/SSEEmitter.java | 55 ++++++++++ .../springdemo/entity/UserService.java | 100 ++++++++++++++++-- .../src/main/resources/application.yaml | 1 + 4 files changed, 191 insertions(+), 11 deletions(-) create mode 100644 ForJdk8/src/main/java/cn/whaifree/tech/proxy/ProxyDemo.java create mode 100644 springDemo/src/main/java/cn/whaifree/springdemo/controller/SSE/SSEEmitter.java diff --git a/ForJdk8/src/main/java/cn/whaifree/tech/proxy/ProxyDemo.java b/ForJdk8/src/main/java/cn/whaifree/tech/proxy/ProxyDemo.java new file mode 100644 index 0000000..7917420 --- /dev/null +++ b/ForJdk8/src/main/java/cn/whaifree/tech/proxy/ProxyDemo.java @@ -0,0 +1,46 @@ +package cn.whaifree.tech.proxy; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/10/22 23:13 + * @注释 + */ +public class ProxyDemo { + + interface base{ + void print(); + } + + static class A implements base { + + @Override + public void print() { + System.out.println("A"); + } + } + + + public static void main(String[] args) { + base a = (base) + java.lang.reflect.Proxy.newProxyInstance( + base.class.getClassLoader(), + new Class[]{ + base.class + }, + new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + System.out.println("ProxyA"); + method.invoke(new A(), args); + System.out.println("after invoke"); + return null; + } + } + ); + a.print(); + } +} diff --git a/springDemo/src/main/java/cn/whaifree/springdemo/controller/SSE/SSEEmitter.java b/springDemo/src/main/java/cn/whaifree/springdemo/controller/SSE/SSEEmitter.java new file mode 100644 index 0000000..2ad9641 --- /dev/null +++ b/springDemo/src/main/java/cn/whaifree/springdemo/controller/SSE/SSEEmitter.java @@ -0,0 +1,55 @@ +package cn.whaifree.springdemo.controller.SSE; + +import cn.hutool.core.util.StrUtil; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; + +import java.io.IOException; +import java.util.Map; + +/** + * @version 1.0 + * @Author whai文海 + * @Date 2024/10/22 21:44 + * @注释 + */ +@RestController +public class SSEEmitter { + + public static void main(String[] args) { + int a = 127; + byte c = (byte) a; + System.out.println(Integer.toBinaryString(c)); + System.out.println(c); + } + Map sseEmitterMap = new java.util.HashMap<>(); + + @GetMapping(value = "/sseStart", produces = MediaType.TEXT_EVENT_STREAM_VALUE) + public SseEmitter sse(String key) { + System.out.println(key); + if (!sseEmitterMap.containsKey(key)) { + SseEmitter sseEmitter = new SseEmitter(); + sseEmitterMap.put(key, sseEmitter); + } + + return sseEmitterMap.get(key); + } + + @PostMapping("sendSSE") + public void send(String key, String message) { + if (sseEmitterMap.containsKey(key)) { + SseEmitter sseEmitter = sseEmitterMap.get(key); + try { + System.out.println(StrUtil.format("send message to {}:{}", key, message)); + sseEmitter.send(message); + } catch (IOException e) { + e.printStackTrace(); + } + }else { + throw new IllegalArgumentException("No such key"); + } + } +} diff --git a/springDemo/src/main/java/cn/whaifree/springdemo/entity/UserService.java b/springDemo/src/main/java/cn/whaifree/springdemo/entity/UserService.java index 8736575..c16165d 100644 --- a/springDemo/src/main/java/cn/whaifree/springdemo/entity/UserService.java +++ b/springDemo/src/main/java/cn/whaifree/springdemo/entity/UserService.java @@ -1,12 +1,10 @@ package cn.whaifree.springdemo.entity; + import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.*; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @@ -22,11 +20,53 @@ import org.springframework.core.annotation.Order; */ @Configuration @Order(-1) -class Config{ +class Config { } -//@Component("userService") -public class UserService implements InitializingBean, DisposableBean, BeanFactoryAware, ApplicationContextAware, BeanPostProcessor,AutoCloseable { + +/** + *

Spring Bean生命周期

+ *

Spring Bean 的生命周期包括创建、初始化、使用、销毁等过程。

+ *

Spring Bean 的生命周期

+ * +*
  • 实例化阶段:Bean 被实例化,Bean 实例化后,Bean 处于未初始化状态。
  • +*
  • 初始化阶段:Bean 完成实例化后,Bean 处于初始化状态,Bean 实例变量可以被赋值。
  • +* +* +*
  • 使用阶段:Bean 完成初始化后,Bean 处于可使用状态,Bean 可以被使用。
  • +*
  • 销毁阶段:Bean 不再被使用时,Bean 处于销毁状态,Bean 实例将被销毁。
  • +* +* +* + * + * + * + * + *

    相关Aware注入:让 Bean 能够**感知**到它们所运行的环境或依赖的资源e

    + *

    为什么要叫Aware

    + * Aware是一个接口, + * 指示 Bean 有资格通过 Callback 样式方法由 Spring 容器通知特定框架对象。 + * 实际的方法签名由各个子接口确定,但通常应仅包含一个接受单个参数的返回 void 的方法 + */ +//@Component +public class UserService implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware, BeanPostProcessor, AutoCloseable { + /** * 执行 BeanFactoryAware.setBeanFactory @@ -43,14 +83,17 @@ public class UserService implements InitializingBean, DisposableBean, BeanFactor public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("cn.whaifree.springdemo.entity"); UserService userService = context.getBean("userService", UserService.class); + System.out.println(userService); // 执行 DisposableBean context.close(); } + private String beanName; private BeanFactory beanFactory; private ApplicationContext applicationContext; + @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("执行 BeanPostProcessor.postProcessBeforeInitialization"); @@ -73,25 +116,39 @@ public class UserService implements InitializingBean, DisposableBean, BeanFactor System.out.println("UserService destroy"); } + /** + * org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods(java.lang.String, java.lang.Object) + * + * if (bean instanceof BeanFactoryAware beanFactoryAware) { // 如果实现了BeanFactoryAware接口,就执行setBeanFactory + * beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this); + * } + * @param beanFactory owning BeanFactory (never {@code null}). + * The bean can immediately call methods on the factory. + * @throws BeansException + */ @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; System.out.println("执行 BeanFactoryAware.setBeanFactory"); } + + + @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; - System.out.println("执行 ApplicationContextAware.setApplicationContext"); + System.out.println("ApplicationContextAware.setApplicationContext(ApplicationContext applicationContext) 可以获取applicantionContext,便于获取context,可以提取变成一个公共的component,每次从这个component获取Bean"); } + @PostConstruct - public void init(){ + public void init() { System.out.println("执行 @PostConstruct"); } @PreDestroy - public void destroyMethod(){ + public void destroyMethod() { System.out.println("执行 @PreDestroy"); } @@ -100,6 +157,12 @@ public class UserService implements InitializingBean, DisposableBean, BeanFactor } + @Override + public void setBeanName(String name) { + System.out.println("执行 BeanNameAware.setBeanName"); + // 修改原来的BeanName + } + /** * org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#invokeAwareMethods(java.lang.String, java.lang.Object) @@ -107,7 +170,7 @@ public class UserService implements InitializingBean, DisposableBean, BeanFactor * if (bean instanceof Aware) { * if (bean instanceof BeanNameAware beanNameAware) { * beanNameAware.setBeanName(beanName); - * } + * } * if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) { * ClassLoader bcl = getBeanClassLoader(); * if (bcl != null) { @@ -121,3 +184,18 @@ public class UserService implements InitializingBean, DisposableBean, BeanFactor } + +/** + * 模拟工具类,其实就是可以随时获取本Context + */ +//@Component +//class SpringContextUtil implements ApplicationContextAware { +// static ApplicationContext applicationContext; +// @Override +// public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { +// this.applicationContext = applicationContext; +// } +// public static ApplicationContext getApplicationContext(){ +// return applicationContext; +// } +//} diff --git a/springDemo/src/main/resources/application.yaml b/springDemo/src/main/resources/application.yaml index bc6aca4..414616f 100644 --- a/springDemo/src/main/resources/application.yaml +++ b/springDemo/src/main/resources/application.yaml @@ -8,6 +8,7 @@ spring: data: redis: + host: localhost port: 6379 # 选择db1