feat(springDemo): 添加 Server-Sent Events (SSE) 功能和代理演示

- 新增 SSEEmitter 类实现 Server-Sent Events功能
- 添加 ProxyDemo 类演示动态代理
- 更新 UserService 类,增加 Bean 生命周期相关注释
- 调整 application.yaml 文件格式
This commit is contained in:
whaifree 2024-10-22 23:23:03 +08:00
parent 72843c9027
commit 25f4784daa
4 changed files with 191 additions and 11 deletions

View File

@ -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();
}
}

View File

@ -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<String, SseEmitter> 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");
}
}
}

View File

@ -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 {
/**
* <h1>Spring Bean生命周期</h1>
* <p>Spring Bean 的生命周期包括创建初始化使用销毁等过程</p>
* <p>Spring Bean 的生命周期</p>
*
* <li>实例化阶段Bean 被实例化Bean 实例化后Bean 处于未初始化状态</li>
* <li>初始化阶段Bean 完成实例化后Bean 处于初始化状态Bean 实例变量可以被赋值</li>
* <ul>
* <li><code>BeanNameAware.setBeanName</code></li>
* <li><code>BeanFactoryAware.setBeanFactory</code></li>
* <li><code>ApplicationContextAware.setApplicationContext</code></li>
* </ul>
* <ul>
* <li><code>@PostConstruct</code></li>
* <li><code>InitializingBean.afterPropertiesSet</code></li>
* <li><code>BeanPostProcessor.postProcessBeforeInitialization</code></li>
* <li>初始化</li>
* <li><code>BeanPostProcessor.postProcessAfterInitialization</code></li>
* </ul>
* <li>使用阶段Bean 完成初始化后Bean 处于可使用状态Bean 可以被使用</li>
* <li>销毁阶段Bean 不再被使用时Bean 处于销毁状态Bean 实例将被销毁</li>
*
* <ul>
* <li><code>@PreDestroy</code></li>
* <li><code>DisposableBean.destroy</code></li>
*
*
*
* </ul>
*
*
*
*
*
* <h2>相关Aware注入 Bean 能够**感知**到它们所运行的环境或依赖的资源e</h2>
* <h2>为什么要叫Aware</h2>
* 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;
// }
//}

View File

@ -8,6 +8,7 @@ spring:
data:
redis:
host: localhost
port: 6379
# 选择db1