Java监听器(Listener)
目录
1. 监听器简介
1.1 什么是监听器
监听器(Listener)是Java中用于监听特定事件发生的组件,当被监听的事件发生时,监听器会自动执行相应的处理逻辑。它是观察者模式的一种实现。
1.2 核心特性
- 事件驱动: 基于事件的发生来触发执行
- 异步处理: 不阻塞主线程的执行
- 解耦合: 事件源与监听器之间松耦合
- 可扩展性: 支持多个监听器监听同一事件
1.3 监听器 vs 观察者 vs 回调
| 特性 | 监听器(Listener) | 观察者(Observer) | 回调(Callback) |
|---|---|---|---|
| 实现方式 | 接口实现 | 接口实现 | 函数引用 |
| 事件类型 | 预定义事件 | 自定义事件 | 异步结果 |
| 使用场景 | GUI事件、Web事件 | 数据变化通知 | 异步操作完成 |
| 耦合度 | 低 | 低 | 中 |
| 性能开销 | 较低 | 较低 | 最低 |
2. 源码分析
2.1 核心接口和类
2.1.1 EventListener接口
public interface EventListener {
// 标记接口,所有监听器接口的父接口
// 不包含任何方法,仅用于类型标识
}
2.1.2 EventObject类
public class EventObject implements java.io.Serializable {
protected transient Object source;
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");
this.source = source;
}
public Object getSource() {
return source;
}
public String toString() {
return getClass().getName() + "[source=" + source + "]";
}
}
2.1.3 PropertyChangeListener接口
public interface PropertyChangeListener extends EventListener {
void propertyChange(PropertyChangeEvent evt);
}
2.1.4 PropertyChangeEvent类
public class PropertyChangeEvent extends EventObject {
private String propertyName;
private Object oldValue;
private Object newValue;
public PropertyChangeEvent(Object source, String propertyName,
Object oldValue, Object newValue) {
super(source);
this.propertyName = propertyName;
this.oldValue = oldValue;
this.newValue = newValue;
}
public String getPropertyName() {
return propertyName;
}
public Object getOldValue() {
return oldValue;
}
public Object getNewValue() {
return newValue;
}
}
2.2 监听器执行流程
2.2.1 执行时序图
2.2.2 监听器管理源码分析
public class ListenerManager {
private final List<EventListener> listeners = new ArrayList<>();
public synchronized void addListener(EventListener listener) {
if (listener != null && !listeners.contains(listener)) {
listeners.add(listener);
}
}
public synchronized void removeListener(EventListener listener) {
listeners.remove(listener);
}
public synchronized void notifyListeners(EventObject event) {
for (EventListener listener : listeners) {
try {
if (listener instanceof PropertyChangeListener) {
((PropertyChangeListener) listener).propertyChange((PropertyChangeEvent) event);
}
// 可以添加其他类型的监听器处理
} catch (Exception e) {
// 记录异常,不影响其他监听器
System.err.println("Error notifying listener: " + e.getMessage());
}
}
}
}
2.3 监听器注册机制
2.3.1 动态注册
public class DynamicListenerRegistration {
private final ListenerManager listenerManager = new ListenerManager();
public void registerListener(EventListener listener) {
listenerManager.addListener(listener);
}
public void unregisterListener(EventListener listener) {
listenerManager.removeListener(listener);
}
public void fireEvent(EventObject event) {
listenerManager.notifyListeners(event);
}
}
2.3.2 注解注册
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EventListener {
String eventType() default "";
int priority() default 0;
}
public class AnnotationBasedListenerManager {
private final Map<String, List<Method>> eventHandlers = new HashMap<>();
public void registerListener(Object listener) {
Class<?> clazz = listener.getClass();
for (Method method : clazz.getMethods()) {
EventListener annotation = method.getAnnotation(EventListener.class);
if (annotation != null) {
String eventType = annotation.eventType();
eventHandlers.computeIfAbsent(eventType, k -> new ArrayList<>()).add(method);
}
}
}
}
3. 设计模式分析
3.1 观察者模式(Observer Pattern)
3.1.1 模式结构
3.1.2 实现原理
- Subject: 被观察的对象,维护观察者列表
- Observer: 观察者接口,定义更新方法
- 事件通知: 当状态变化时,通知所有观察者
3.2 发布-订阅模式(Publish-Subscribe)
3.2.1 模式结构
public interface EventBus {
void publish(Event event);
void subscribe(Class<? extends Event> eventType, EventHandler handler);
void unsubscribe(Class<? extends Event> eventType, EventHandler handler);
}
public class SimpleEventBus implements EventBus {
private final Map<Class<? extends Event>, List<EventHandler>> handlers = new ConcurrentHashMap<>();
@Override
public void publish(Event event) {
List<EventHandler> eventHandlers = handlers.get(event.getClass());
if (eventHandlers != null) {
for (EventHandler handler : eventHandlers) {
handler.handle(event);
}
}
}
@Override
public void subscribe(Class<? extends Event> eventType, EventHandler handler) {
handlers.computeIfAbsent(eventType, k -> new ArrayList<>()).add(handler);
}
}
3.3 责任链模式(Chain of Responsibility)
3.3.1 模式结构
public abstract class EventHandler {
protected EventHandler nextHandler;
public void setNext(EventHandler handler) {
this.nextHandler = handler;
}
public abstract void handle(Event event);
protected void handleNext(Event event) {
if (nextHandler != null) {
nextHandler.handle(event);
}
}
}
public class LoggingEventHandler extends EventHandler {
@Override
public void handle(Event event) {
// 记录日志
System.out.println("Logging event: " + event);
// 传递给下一个处理器
handleNext(event);
}
}
3.4 策略模式(Strategy)
3.4.1 模式结构
public interface EventProcessingStrategy {
void processEvent(Event event);
}
public class AsyncEventProcessingStrategy implements EventProcessingStrategy {
private final ExecutorService executor = Executors.newFixedThreadPool(10);
@Override
public void processEvent(Event event) {
executor.submit(() -> {
// 异步处理事件
processEventInternal(event);
});
}
private void processEventInternal(Event event) {
// 具体的事件处理逻辑
}
}
4. 项目应用场景
4.1 属性变化监听器
4.1.1 实现代码
@Component
public class ConfigurationChangeListener implements PropertyChangeListener {
private static final Logger logger = LoggerFactory.getLogger(ConfigurationChangeListener.class);
@Override
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
Object oldValue = evt.getOldValue();
Object newValue = evt.getNewValue();
logger.info("配置项变化 - 名称: {}, 旧值: {}, 新值: {}",
propertyName, oldValue, newValue);
// 根据配置项类型执行相应操作
switch (propertyName) {
case "database.url":
handleDatabaseUrlChange((String) oldValue, (String) newValue);
break;
case "cache.enabled":
handleCacheEnabledChange((Boolean) oldValue, (Boolean) newValue);
break;
case "thread.pool.size":
handleThreadPoolSizeChange((Integer) oldValue, (Integer) newValue);
break;
default:
logger.warn("未知的配置项: {}", propertyName);
}
}
private void handleDatabaseUrlChange(String oldUrl, String newUrl) {
// 处理数据库URL变化
logger.info("数据库URL从 {} 变更为 {}", oldUrl, newUrl);
// 重新初始化数据库连接池等操作
}
private void handleCacheEnabledChange(Boolean oldEnabled, Boolean newEnabled) {
// 处理缓存启用状态变化
if (Boolean.TRUE.equals(newEnabled)) {
logger.info("缓存已启用");
// 初始化缓存
} else {
logger.info("缓存已禁用");
// 清理缓存
}
}
private void handleThreadPoolSizeChange(Integer oldSize, Integer newSize) {
// 处理线程池大小变化
logger.info("线程池大小从 {} 变更为 {}", oldSize, newSize);
// 调整线程池大小
}
}
4.1.2 配置类
@Configuration
public class ConfigurationConfig {
@Bean
public PropertyChangeSupport propertyChangeSupport() {
return new PropertyChangeSupport(this);
}
@Bean
public ConfigurationChangeListener configurationChangeListener() {
return new ConfigurationChangeListener();
}
@PostConstruct
public void init() {
PropertyChangeSupport pcs = propertyChangeSupport();
pcs.addPropertyChangeListener(configurationChangeListener());
}
}
4.2 生命周期监听器
4.2.1 实现代码
@Component
public class ApplicationLifecycleListener implements ApplicationListener<ApplicationEvent> {
private static final Logger logger = LoggerFactory.getLogger(ApplicationLifecycleListener.class);
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartedEvent) {
handleApplicationStarted((ApplicationStartedEvent) event);
} else if (event instanceof ApplicationReadyEvent) {
handleApplicationReady((ApplicationReadyEvent) event);
} else if (event instanceof ApplicationFailedEvent) {
handleApplicationFailed((ApplicationFailedEvent) event);
} else if (event instanceof ApplicationStoppedEvent) {
handleApplicationStopped((ApplicationStoppedEvent) event);
}
}
private void handleApplicationStarted(ApplicationStartedEvent event) {
logger.info("应用程序启动中...");
// 执行启动时的初始化操作
initializeSystem();
}
private void handleApplicationReady(ApplicationReadyEvent event) {
logger.info("应用程序已就绪");
// 执行就绪后的操作
performPostStartupTasks();
}
private void handleApplicationFailed(ApplicationFailedEvent event) {
logger.error("应用程序启动失败", event.getException());
// 执行失败处理操作
handleStartupFailure(event.getException());
}
private void handleApplicationStopped(ApplicationStoppedEvent event) {
logger.info("应用程序已停止");
// 执行停止时的清理操作
performCleanup();
}
private void initializeSystem() {
// 系统初始化逻辑
logger.info("正在初始化系统组件...");
}
private void performPostStartupTasks() {
// 启动后任务
logger.info("正在执行启动后任务...");
}
private void handleStartupFailure(Throwable exception) {
// 启动失败处理
logger.error("启动失败,正在执行恢复操作...");
}
private void performCleanup() {
// 清理操作
logger.info("正在执行清理操作...");
}
}
4.3 业务事件监听器
4.3.1 事件定义
public abstract class BusinessEvent extends EventObject {
private final LocalDateTime timestamp;
private final String eventId;
public BusinessEvent(Object source) {
super(source);
this.timestamp = LocalDateTime.now();
this.eventId = UUID.randomUUID().toString();
}
public LocalDateTime getTimestamp() {
return timestamp;
}
public String getEventId() {
return eventId;
}
}
public class UserRegistrationEvent extends BusinessEvent {
private final User user;
public UserRegistrationEvent(Object source, User user) {
super(source);
this.user = user;
}
public User getUser() {
return user;
}
}
public class OrderCreatedEvent extends BusinessEvent {
private final Order order;
public OrderCreatedEvent(Object source, Order order) {
super(source);
this.order = order;
}
public Order getOrder() {
return order;
}
}
4.3.2 监听器实现
@Component
public class UserRegistrationListener implements ApplicationListener<UserRegistrationEvent> {
@Autowired
private EmailService emailService;
@Autowired
private NotificationService notificationService;
@Override
public void onApplicationEvent(UserRegistrationEvent event) {
User user = event.getUser();
// 发送欢迎邮件
CompletableFuture.runAsync(() -> {
emailService.sendWelcomeEmail(user);
});
// 发送欢迎通知
CompletableFuture.runAsync(() -> {
notificationService.sendWelcomeNotification(user);
});
// 记录用户注册日志
logUserRegistration(user);
}
private void logUserRegistration(User user) {
// 记录用户注册日志
}
}
@Component
public class OrderCreatedListener implements ApplicationListener<OrderCreatedEvent> {
@Autowired
private InventoryService inventoryService;
@Autowired
private PaymentService paymentService;
@Override
public void onApplicationEvent(OrderCreatedEvent event) {
Order order = event.getOrder();
// 检查库存
CompletableFuture.runAsync(() -> {
inventoryService.checkAndReserveInventory(order);
});
// 创建支付订单
CompletableFuture.runAsync(() -> {
paymentService.createPaymentOrder(order);
});
// 发送订单确认通知
sendOrderConfirmation(order);
}
private void sendOrderConfirmation(Order order) {
// 发送订单确认通知
}
}
4.4 异步事件监听器
4.4.1 实现代码
@Component
public class AsyncEventListener {
private final ExecutorService executorService;
private final Map<Class<? extends Event>, List<EventHandler>> eventHandlers = new ConcurrentHashMap<>();
public AsyncEventListener() {
this.executorService = Executors.newFixedThreadPool(10);
}
public <T extends Event> void registerHandler(Class<T> eventType, EventHandler<T> handler) {
eventHandlers.computeIfAbsent(eventType, k -> new ArrayList<>()).add(handler);
}
public <T extends Event> void publishEvent(T event) {
List<EventHandler> handlers = eventHandlers.get(event.getClass());
if (handlers != null) {
for (EventHandler handler : handlers) {
executorService.submit(() -> {
try {
handler.handle(event);
} catch (Exception e) {
// 记录异常,不影响其他处理器
System.err.println("Error handling event: " + e.getMessage());
}
});
}
}
}
@PreDestroy
public void shutdown() {
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
@FunctionalInterface
public interface EventHandler<T extends Event> {
void handle(T event);
}
5. 面试高频点
5.1 基础概念类
5.1.1 监听器与观察者的区别
答案要点:
- 实现方式: 监听器通常基于接口实现,观察者可以是接口或抽象类
- 事件类型: 监听器监听特定类型事件,观察者观察对象状态变化
- 耦合度: 监听器耦合度更低,观察者耦合度相对较高
- 使用场景: 监听器用于事件驱动,观察者用于状态变化通知
扩展问题:
- 监听器能监听多个事件源吗?
- 观察者模式中的推拉模型有什么区别?
5.1.2 监听器的执行顺序
答案要点:
- 注册顺序: 通常按注册顺序执行
- 优先级: 可以通过优先级控制执行顺序
- 异常处理: 一个监听器异常不影响其他监听器
- 异步执行: 支持同步和异步两种执行方式
代码示例:
// 监听器执行顺序示例
public class OrderedListenerManager {
private final List<OrderedListener> listeners = new ArrayList<>();
public void addListener(OrderedListener listener) {
listeners.add(listener);
// 按优先级排序
listeners.sort(Comparator.comparing(OrderedListener::getPriority));
}
public void notifyListeners(Event event) {
for (OrderedListener listener : listeners) {
try {
listener.onEvent(event);
} catch (Exception e) {
// 记录异常,继续执行下一个
log.error("Listener execution failed", e);
}
}
}
}
5.2 源码实现类
5.2.1 EventObject如何传递事件信息
答案要点:
- 事件源: 通过source字段标识事件来源
- 事件数据: 子类可以添加具体的事件数据字段
- 序列化支持: 实现Serializable接口,支持序列化
- 类型安全: 通过泛型确保类型安全
源码关键点:
public class EventObject implements java.io.Serializable {
protected transient Object source; // 事件源,transient避免序列化
public EventObject(Object source) {
if (source == null)
throw new IllegalArgumentException("null source");
this.source = source;
}
public Object getSource() {
return source;
}
}
5.2.2 监听器注册机制
答案要点:
- 动态注册: 运行时添加和移除监听器
- 类型安全: 通过泛型确保监听器类型匹配
- 线程安全: 使用同步机制保证线程安全
- 内存管理: 及时移除不需要的监听器避免内存泄漏
注册示例:
public class ListenerRegistry {
private final Map<Class<? extends Event>, List<EventListener>> registry = new ConcurrentHashMap<>();
public <T extends Event> void register(Class<T> eventType, EventListener<T> listener) {
registry.computeIfAbsent(eventType, k -> new ArrayList<>()).add(listener);
}
public <T extends Event> void unregister(Class<T> eventType, EventListener<T> listener) {
List<EventListener> listeners = registry.get(eventType);
if (listeners != null) {
listeners.remove(listener);
}
}
}
5.3 设计模式类
5.3.1 监听器使用了哪些设计模式
答案要点:
- 观察者模式: 事件源与监听器之间的松耦合关系
- 发布-订阅模式: 事件发布者与订阅者的解耦
- 责任链模式: 多个监听器按顺序处理事件
- 策略模式: 不同类型事件使用不同处理策略
模式应用场景:
- 观察者: 对象状态变化通知
- 发布-订阅: 事件总线实现
- 责任链: 事件处理管道
- 策略: 事件处理策略选择
5.3.2 如何实现自定义事件系统
答案要点:
- 定义事件基类: 继承EventObject或自定义基类
- 实现监听器接口: 定义事件处理方法
- 事件管理器: 管理监听器注册和事件分发
- 异步处理: 支持异步事件处理
实现示例:
public class CustomEventSystem {
private final Map<Class<? extends Event>, List<EventHandler>> handlers = new ConcurrentHashMap<>();
private final ExecutorService executor = Executors.newFixedThreadPool(10);
public <T extends Event> void subscribe(Class<T> eventType, EventHandler<T> handler) {
handlers.computeIfAbsent(eventType, k -> new ArrayList<>()).add(handler);
}
public <T extends Event> void publish(T event) {
List<EventHandler> eventHandlers = handlers.get(event.getClass());
if (eventHandlers != null) {
for (EventHandler handler : eventHandlers) {
executor.submit(() -> handler.handle(event));
}
}
}
}
5.4 应用场景类
5.4.1 监听器在项目中的典型应用
答案要点:
- 配置变更: 监听配置变化并自动更新
- 生命周期管理: 监听应用启动、停止等事件
- 业务事件: 监听业务操作完成事件
- 系统监控: 监听系统状态变化
实际案例:
// 配置变更监听器
@Component
public class ConfigChangeListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
String propertyName = evt.getPropertyName();
Object newValue = evt.getNewValue();
// 根据配置项执行相应操作
switch (propertyName) {
case "cache.enabled":
updateCacheStatus((Boolean) newValue);
break;
case "thread.pool.size":
updateThreadPoolSize((Integer) newValue);
break;
}
}
private void updateCacheStatus(Boolean enabled) {
// 更新缓存状态
}
private void updateThreadPoolSize(Integer size) {
// 更新线程池大小
}
}
5.4.2 如何实现异步事件监听器
答案要点:
- 线程池管理: 使用线程池处理异步事件
- 异常处理: 异步执行中的异常处理机制
- 资源管理: 及时释放线程池资源
- 性能优化: 合理配置线程池参数
实现示例:
@Component
public class AsyncEventListener {
private final ExecutorService executor;
private final List<EventHandler> handlers = new ArrayList<>();
public AsyncEventListener() {
this.executor = Executors.newFixedThreadPool(10);
}
public void addHandler(EventHandler handler) {
handlers.add(handler);
}
public void publishEvent(Event event) {
for (EventHandler handler : handlers) {
executor.submit(() -> {
try {
handler.handle(event);
} catch (Exception e) {
log.error("Async event handling failed", e);
}
});
}
}
@PreDestroy
public void shutdown() {
executor.shutdown();
}
}
5.5 性能优化类
5.5.1 监听器性能优化策略
答案要点:
- 异步处理: 对于耗时操作使用异步处理
- 批量处理: 批量处理多个事件
- 缓存机制: 缓存事件处理结果
- 资源池化: 使用对象池减少GC压力
优化示例:
@Component
public class OptimizedEventListener {
private final ExecutorService executor;
private final Cache<String, Object> resultCache;
public OptimizedEventListener() {
this.executor = Executors.newFixedThreadPool(20);
this.resultCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.build();
}
public void handleEvent(Event event) {
// 检查缓存
String cacheKey = generateCacheKey(event);
Object cachedResult = resultCache.getIfPresent(cacheKey);
if (cachedResult != null) {
return;
}
// 异步处理事件
executor.submit(() -> {
Object result = processEvent(event);
resultCache.put(cacheKey, result);
});
}
private String generateCacheKey(Event event) {
return event.getClass().getSimpleName() + ":" + event.hashCode();
}
}
5.5.2 监听器内存管理
答案要点:
- 及时移除: 及时移除不需要的监听器
- 弱引用: 使用WeakReference避免内存泄漏
- 生命周期管理: 监听器与监听对象生命周期同步
- 资源清理: 在监听器销毁时清理相关资源
管理示例:
public class MemorySafeListenerManager {
private final Map<Object, List<WeakReference<EventListener>>> listeners = new WeakHashMap<>();
public void addListener(Object source, EventListener listener) {
listeners.computeIfAbsent(source, k -> new ArrayList<>())
.add(new WeakReference<>(listener));
}
public void notifyListeners(Object source, Event event) {
List<WeakReference<EventListener>> listenerRefs = listeners.get(source);
if (listenerRefs != null) {
// 清理已失效的引用
listenerRefs.removeIf(ref -> ref.get() == null);
// 通知有效的监听器
for (WeakReference<EventListener> ref : listenerRefs) {
EventListener listener = ref.get();
if (listener != null) {
listener.onEvent(event);
}
}
}
}
}
6. 总结
6.1 学习路径图
6.2 核心优势总结
| 优势 | 说明 | 重要性 |
|---|---|---|
| 解耦合 | 事件源与监听器之间松耦合 | ⭐⭐⭐⭐⭐ |
| 可扩展性 | 支持动态添加和移除监听器 | ⭐⭐⭐⭐⭐ |
| 异步处理 | 支持异步事件处理,不阻塞主线程 | ⭐⭐⭐⭐⭐ |
| 事件驱动 | 基于事件的发生来触发执行 | ⭐⭐⭐⭐ |
| 类型安全 | 通过泛型确保类型安全 | ⭐⭐⭐⭐ |
6.3 适用场景总结
| 场景 | 适用性 | 推荐程度 |
|---|---|---|
| 配置变更监听 | 高 | ⭐⭐⭐⭐⭐ |
| 生命周期管理 | 高 | ⭐⭐⭐⭐⭐ |
| 业务事件处理 | 高 | ⭐⭐⭐⭐⭐ |
| 系统监控 | 高 | ⭐⭐⭐⭐⭐ |
| 异步任务处理 | 中 | ⭐⭐⭐⭐ |
| 状态变化通知 | 中 | ⭐⭐⭐⭐ |
6.4 注意事项总结
| 注意事项 | 说明 | 影响程度 |
|---|---|---|
| 内存泄漏 | 及时移除不需要的监听器 | ⭐⭐⭐⭐⭐ |
| 异常处理 | 监听器异常不应影响其他监听器 | ⭐⭐⭐⭐⭐ |
| 线程安全 | 多线程环境下的并发安全 | ⭐⭐⭐⭐ |
| 性能影响 | 监听器过多会影响性能 | ⭐⭐⭐⭐ |
| 事件顺序 | 监听器执行顺序的确定性 | ⭐⭐⭐ |
6.5 学习建议
| 学习阶段 | 重点内容 | 建议时间 |
|---|---|---|
| 初级阶段 | 基础概念、简单使用 | 1-2天 |
| 中级阶段 | 源码分析、设计模式 | 3-5天 |
| 高级阶段 | 自定义实现、性能优化 | 5-7天 |
| 实战阶段 | 项目应用、问题解决 | 持续学习 |
6.6 发展方向
| 方向 | 技能要求 | 发展前景 |
|---|---|---|
| Java专家 | 深入Java生态,掌握事件机制 | ⭐⭐⭐⭐⭐ |
| 架构师 | 设计事件驱动架构,制定最佳实践 | ⭐⭐⭐⭐⭐ |
| 性能专家 | 优化事件处理性能,解决性能瓶颈 | ⭐⭐⭐⭐ |
| 系统专家 | 设计系统监控,实现自动化运维 | ⭐⭐⭐⭐⭐ |
6.7 最终建议
- 理论与实践结合: 先理解概念,再动手实践,最后深入源码
- 循序渐进: 从简单监听器开始,逐步增加复杂度
- 关注性能: 在实际项目中注意监听器的性能影响
- 持续学习: 关注Java版本更新,学习新特性
- 总结归纳: 建立自己的知识体系,形成最佳实践
通过系统学习Java监听器,你将能够:
- 深入理解Java的事件机制和观察者模式
- 掌握监听器的设计思想和实现原理
- 在实际项目中灵活运用监听器解决各种问题
- 在面试中展现扎实的技术功底
- 为后续学习Java生态其他组件打下坚实基础

1285

被折叠的 条评论
为什么被折叠?



