智能内容生成服务 · 让AI为你创作精彩内容
一个智能内容生成服务,结合通义千问API和文件监听技术,实现自动化的内容生成与分发(不能多说了,😜😜😜)
- 🖼️ 自动检测指定目录中的图片文件
- 🧠 利用阿里云通义千问大模型分析图片内容
- 📄 自动生成高质量的中文内容
- 📨 支持自动邮件发送生成的内容
- Java 21+
- Spring Boot 3.5
- 阿里云DashScope API
- 文件监听器(File Watcher)
在Spring
内部一个组件同时实现这三个接口很常见!
ApplicationContextAware
接口提供了一种机制,允许在Bean
的初始化(initializeBean
)阶段,获取到ApplicationContext
实例,这是依赖ApplicationContextAwareProcessor
实现的。 既然有了ApplicationContext
,那么就可以获取到实例化FileSystemWatcher
时所需要的FileWatcherProperties
这一Bean
。
FactoryBean
主要用于实例化逻辑比较复杂的Bean
,而FileSystemWatcher
实例化确实又可以很复杂,必须要为该实例配置FileFilter
、SnapshotStateRepository
和FileChangeListener
等组件才能发挥作用,这些组件往往又需要基于FileWatcherProperties
中的内容来决策各自实例化策略,甚至是需要独自实现自己的FileFilter
和SnapshotStateRepository
来替换掉默认的能力。
public interface SmartLifecycle extends Lifecycle, Phased { default boolean isAutoStartup() { return true; } default void stop(Runnable callback) { stop(); callback.run(); } default int getPhase() { return DEFAULT_PHASE; } }
Lifecycle
和SmartLifecycle
接口都用于管理Bean
的生命周期,但SmartLifecycle
提供了更精细的控制:
-
Lifecycle
提供了基本的start()
、isRunning()
和stop()
方法,它适合那些生命周期管理比较简单、不需要关心启动顺序或自动启动条件的组件;此外,其中start()
和stop()
方法需要手动调用,比如分别监听ContextStartedEvent
和ContextClosedEvent
事件以手动调用其start()
和close()
方法。 -
SmartLifecycle
继承自Lifecycle
,并增加了更高级的控制,包括:- isAutoStartup(): 决定是否应该在容器启动时自动启动(默认为
true
)。 - stop(Runnable callback): 允许更优雅的停止,当组件完全停止后,会执行传入的
callback
。 - getPhase(): 这是最关键的区别之一,它定义了组件在启动和关闭阶段的顺序。具有较低
phase
值的组件会先启动,后停止,这对于有依赖关系的组件至关重要。 - 最为重要的一点:
ConfigurableApplicationContext
在执行refresh()
过程中会自动调用DefaultLifecycleProcessor
的onRefresh()
方法,最终自动启动所有的SmartLifecycle
;同样地,ConfigurableApplicationContext
在执行close()
逻辑过程中也会自动调用DefaultLifecycleProcessor
的onClose()
方法,最终自动关闭所有的SmartLifecycle
!ConfigurableApplicationContext
中的doClose()
方法会由其close()
方法或JVM shutdown
钩子自动调用,两条路最终均会走到DefaultLifecycleProcessor
的onClose()
方法,以自动关闭所有的SmartLifecycle
。
- isAutoStartup(): 决定是否应该在容器启动时自动启动(默认为
显然,SmartLifecycle
更牛逼,但弃用Lifecycle
最重要的因素是它无法随着ConfigurableApplicationContext
的状态来实现自动启停,即ConfigurableApplicationContext
的刷新与关闭会自动触发DefaultLifecycleProcessor
中onRefresh()
和onClose()
方法的执行,而DefaultLifecycleProcessor
中onRefresh()
方法中明确屏蔽了Lifecycle
,即使DefaultLifecycleProcessor
的onClose()
方法包含了Lifecycle
的关闭逻辑,但由于isRunning()
为false
,自然Lifecycle
的stop()
方法压根也不会被调用。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void finishRefresh() {
// Reset common introspection caches in Spring's core infrastructure.
resetCommonCaches();
// Clear context-level resource caches (such as ASM metadata from scanning).
clearResourceCaches();
// Initialize lifecycle processor for this context.
initLifecycleProcessor();
// Propagate refresh to lifecycle processor first.
getLifecycleProcessor().onRefresh();
// Publish the final event.
publishEvent(new ContextRefreshedEvent(this));
}
/**
* Actually performs context closing: publishes a ContextClosedEvent and
* destroys the singletons in the bean factory of this application context.
* <p>Called by both {@code close()} and a JVM shutdown hook, if any.
*
* @see #close()
* @see #registerShutdownHook()
*/
protected void doClose() {
// Check whether an actual close attempt is necessary...
if (this.active.get() && this.closed.compareAndSet(false, true)) {
if (logger.isDebugEnabled()) {
logger.debug("Closing " + this);
}
try {
// Publish shutdown event.
publishEvent(new ContextClosedEvent(this));
} catch (Throwable ex) {
logger.warn("Exception thrown from ApplicationListener handling ContextClosedEvent", ex);
}
// Stop all Lifecycle beans, to avoid delays during individual destruction.
if (this.lifecycleProcessor != null) {
try {
this.lifecycleProcessor.onClose();
} catch (Throwable ex) {
logger.warn("Exception thrown from LifecycleProcessor on context close", ex);
}
}
// Destroy all cached singletons in the context's BeanFactory.
destroyBeans();
// Close the state of this context itself.
closeBeanFactory();
// Let subclasses do some final clean-up if they wish...
onClose();
// Reset common introspection caches to avoid class reference leaks.
resetCommonCaches();
// Reset local application listeners to pre-refresh state.
if (this.earlyApplicationListeners != null) {
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Reset internal delegates.
this.applicationEventMulticaster = null;
this.messageSource = null;
this.lifecycleProcessor = null;
// Switch to inactive.
this.active.set(false);
}
}
}
public class DefaultLifecycleProcessor implements LifecycleProcessor, BeanFactoryAware {
@Override
public void onRefresh() {
if (checkpointOnRefresh) {
checkpointOnRefresh = false;
new CracDelegate().checkpointRestore();
}
if (exitOnRefresh) {
Runtime.getRuntime().halt(0);
}
this.stoppedBeans = null;
try {
startBeans(true);
} catch (ApplicationContextException ex) {
stopBeans();
throw ex;
}
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
Map<Integer, LifecycleGroup> phases = new TreeMap<>();
lifecycleBeans.forEach((beanName, bean) -> {
if (!autoStartupOnly || isAutoStartupCandidate(beanName, bean)) {
int startupPhase = getPhase(bean);
phases.computeIfAbsent(startupPhase, phase -> new LifecycleGroup(phase, lifecycleBeans, autoStartupOnly))
.add(beanName, bean);
}
});
if (!phases.isEmpty()) {
phases.values().forEach(LifecycleGroup::start);
}
}
// 纯碎的 Lifecycle 压根不会考虑
private boolean isAutoStartupCandidate(String beanName, Lifecycle bean) {
Set<String> stoppedBeans = this.stoppedBeans;
return (stoppedBeans != null ? stoppedBeans.contains(beanName) :
(bean instanceof SmartLifecycle smartLifecycle && smartLifecycle.isAutoStartup()));
}
}