Spring 框架不仅仅提供了 IOC 容器和 AOP 功能,还设计了一套灵活的扩展接口,方便开发者在应用初始化、销毁等不同阶段插入自定义逻辑。今天,我们来一起看看 Spring 中常见的扩展接口,并通过实例说明各自的使用场景!
一、InitializingBean 和 DisposableBean
- InitializingBean:实现该接口的 Bean 会在属性填充后自动调用 afterPropertiesSet 方法,适合用来执行 Bean 的初始化逻辑。
- DisposableBean:实现该接口的 Bean 会在容器销毁时自动调用 destroy 方法,用于清理资源。
示例:
public class MyService implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() {
System.out.println("MyService initialized");
}
@Override
public void destroy() {
System.out.println("MyService destroyed");
}
}
使用这些接口,可以确保在 Bean 初始化和销毁时执行特定的操作,适合有启动和清理需求的服务类。
二、ApplicationContextAware 和 BeanNameAware
- ApplicationContextAware:实现该接口的 Bean 可以在初始化时获取 ApplicationContext,让 Bean 可以直接访问 Spring 容器。
- BeanNameAware:实现该接口的 Bean 可以获取自身在容器中的名称(即 Bean 名称),适合需要根据名称执行特定逻辑的 Bean。
示例:
public class MyService implements ApplicationContextAware, BeanNameAware {
private ApplicationContext applicationContext;
private String beanName;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public void printInfo() {
System.out.println("Bean name: " + beanName);
System.out.println("Application context: " + applicationContext);
}
}
在需要访问容器资源的场景中(如动态加载其他 Bean),这些接口特别有用。
三、BeanPostProcessor 和 BeanFactoryPostProcessor
- BeanPostProcessor:该接口用于在 Bean 初始化前后执行自定义逻辑,是处理 Bean 属性或增强功能的常用扩展接口。
- BeanFactoryPostProcessor:在 BeanFactory 实例化后但 Bean 实例化之前被调用,用于修改 Bean 定义,比如动态改变属性配置。
示例:
@Component
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("Before Initialization of bean: " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("After Initialization of bean: " + beanName);
return bean;
}
}
使用 BeanPostProcessor 可以实现自定义的 AOP 切面逻辑,适合日志记录、性能监控等需求。
四、ApplicationListener 和事件机制
- ApplicationListener:Spring 的事件驱动模型中,ApplicationListener 接口用于监听容器中的事件,常用于处理应用启动、关闭等事件。
示例:
@Component
public class MyEventListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("Application context refreshed!");
}
}
这种事件机制在需要响应容器变化的场景中非常有用,例如在应用启动完成后执行某些初始化操作。
当然,Spring 中的扩展接口远不止这些,以下还有些其他常用的扩展接口,每个接口都有其独特的应用场景:
六、SmartInitializingSingleton
SmartInitializingSingleton 接口用于在所有单例 Bean 初始化完成后执行特定逻辑。通常用于依赖于其他单例 Bean 的初始化顺序较低的情况。
使用场景:比如,需要在所有单例初始化后,进行某种全局性的检查或触发。
示例:
@Component
public class MySmartSingletonBean implements SmartInitializingSingleton {
@Override
public void afterSingletonsInstantiated() {
System.out.println("All singletons have been instantiated!");
}
}
七、EnvironmentAware
EnvironmentAware 接口允许获取 Spring 环境配置 (Environment),可以用来访问系统属性、配置文件等。
使用场景:当需要读取配置文件中的特定属性或系统属性时,非常有用。
示例:
@Component
public class EnvironmentAwareBean implements EnvironmentAware {
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
String profile = environment.getActiveProfiles()[0];
System.out.println("Active Profile: " + profile);
}
}
八、Ordered 接口与优先级管理
Ordered 接口用于定义 Bean 的执行顺序,可以让某些特定 Bean 在其他 Bean 前优先执行。Ordered 通常结合 @Order 注解来定义顺序。
使用场景:常用于自定义的 BeanPostProcessor 或者 ApplicationListener,确保它们按照预定义顺序执行。
示例:
@Component
@Order(1)
public class FirstProcessor implements Ordered {
// 处理逻辑
@Override
public int getOrder() {
return 1;
}
}
九、ServletContextAware
ServletContextAware 接口允许获取 ServletContext,从而可以操作 Web 应用的上下文。
使用场景:适用于 Web 项目,通常用于在 Bean 中访问 Web 容器的上下文参数、资源等。
示例:
@Component
public class ServletContextAwareBean implements ServletContextAware {
@Override
public void setServletContext(ServletContext servletContext) {
System.out.println("ServletContext Name: " + servletContext.getServletContextName());
}
}
十、ApplicationRunner 和 CommandLineRunner
ApplicationRunner 和 CommandLineRunner 是 Spring Boot 提供的两个接口,在 Spring Boot 应用启动完成后会被自动调用。
- ApplicationRunner:可接收 ApplicationArguments 对象,适合处理应用启动参数。
- CommandLineRunner:可接收原始的命令行参数。
使用场景:适合在应用启动时初始化数据、启动任务、打印启动信息等。
示例:
@Component
public class MyAppRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
System.out.println("Application started with args: " + args.getOptionNames());
}
}
@Component
public class MyCommandRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("Command line args: " + Arrays.toString(args));
}
}
十一、FactoryBean 接口
FactoryBean 是一个特殊的 Bean,可以自定义创建对象的过程。实现该接口的 Bean 会返回一个代理对象,而不是 Bean 本身。
使用场景:适用于需要动态生成 Bean 实例,或代理创建复杂对象的场景。
示例:
public class MyFactoryBean implements FactoryBean<MyService> {
@Override
public MyService getObject() {
return new MyService();
}
@Override
public Class<?> getObjectType() {
return MyService.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
除了上面这些,Spring 的扩展接口还有一些其他常见的,继续如下所示:
十三、MessageSourceAware
MessageSourceAware 接口用于获取 MessageSource,这是 Spring 提供的国际化消息源。实现该接口的 Bean 可以访问国际化的消息,方便在应用中实现多语言支持。
使用场景:适用于需要动态获取不同语言的文本信息,常用于国际化应用中。
示例:
@Component
public class MessageSourceAwareBean implements MessageSourceAware {
private MessageSource messageSource;
@Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
public void printMessage() {
String message = messageSource.getMessage("greeting", null, Locale.ENGLISH);
System.out.println(message);
}
}
十四、ResourceLoaderAware
ResourceLoaderAware 接口允许获取 ResourceLoader,可以用来加载各种类型的资源文件(如文件系统、类路径、URL)。
使用场景:当需要动态加载文件资源(如配置文件、图像等)时,可以通过该接口直接获取资源。
示例:
@Component
public class ResourceLoaderAwareBean implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
public void loadResource(String path) {
Resource resource = resourceLoader.getResource(path);
System.out.println("Resource exists: " + resource.exists());
}
}
十五、PropertySourcesPlaceholderConfigurer
PropertySourcesPlaceholderConfigurer 是一个用于处理属性占位符(如 ${...})的特殊 Bean,通常配合 @Value 注解使用,来从外部属性文件中加载配置。
使用场景:在项目中使用外部配置文件(如 .properties 或 .yml 文件)时,通过该 Bean 可以在 Spring 环境中加载和解析这些配置。
示例:
@Configuration
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
十六、AsyncConfigurer
AsyncConfigurer 接口允许自定义异步任务执行器和异常处理器。通过实现该接口,可以定义自己的 Executor 和 AsyncUncaughtExceptionHandler。
使用场景:适用于需要自定义异步任务的执行逻辑或处理异步异常的场景。
示例:
@Configuration
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return Executors.newFixedThreadPool(5);
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, params) -> System.out.println("Async error in method: " + method.getName());
}
}
十七、EmbeddedValueResolverAware
EmbeddedValueResolverAware 接口允许获取 StringValueResolver,可以用于解析字符串中的占位符(如 ${...})和表达式(如 #{...})。
使用场景:当 Bean 中有需要动态解析的属性占位符或表达式时,通过该接口可以方便地实现解析。
示例:
@Component
public class ValueResolverAwareBean implements EmbeddedValueResolverAware {
private StringValueResolver resolver;
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.resolver = resolver;
}
public void printResolvedValue(String placeholder) {
System.out.println("Resolved value: " + resolver.resolveStringValue(placeholder));
}
}
十八、ApplicationEventPublisherAware
ApplicationEventPublisherAware 接口允许获取 ApplicationEventPublisher,可以用于在 Spring 应用上下文中发布事件。
使用场景:适用于需要在应用中触发自定义事件的情况,如某操作完成后通知其他 Bean。
示例:
@Component
public class EventPublisherBean implements ApplicationEventPublisherAware {
private ApplicationEventPublisher eventPublisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
public void publishEvent(String message) {
eventPublisher.publishEvent(new CustomEvent(this, message));
}
}
public class CustomEvent extends ApplicationEvent {
private String message;
public CustomEvent(Object source, String message) {
super(source);
this.message = message;
}
public String getMessage() {
return message;
}
}
十九、SmartLifecycle
SmartLifecycle 接口用于控制 Bean 的启动和停止顺序,是 Lifecycle 接口的扩展。实现该接口的 Bean 可以通过 isAutoStartup 来决定是否在容器启动时自动启动。
使用场景:常用于需要在容器启动或停止时执行特定逻辑的场景,如启动和关闭后台任务。
示例:
@Component
public class MySmartLifecycleBean implements SmartLifecycle {
private boolean running = false;
@Override
public void start() {
System.out.println("Starting MySmartLifecycleBean");
running = true;
}
@Override
public void stop() {
System.out.println("Stopping MySmartLifecycleBean");
running = false;
}
@Override
public boolean isRunning() {
return running;
}
}
在 Spring 框架中,确实有许多扩展接口,除了前面提到的,这里再介绍一些更少见但也十分有用的扩展接口。每个接口都有其特定的使用场景,这些接口能帮助开发者在复杂场景下获得更精细的控制:
二十、BeanClassLoaderAware
BeanClassLoaderAware 接口允许 Bean 获取类加载器 ClassLoader。实现该接口的 Bean 可以在运行时动态加载类或资源。
使用场景:当需要在运行时加载类或资源(比如插件加载器、字节码生成)时,该接口会非常有用。
示例:
@Component
public class ClassLoaderAwareBean implements BeanClassLoaderAware {
private ClassLoader classLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
public void loadClass(String className) throws ClassNotFoundException {
Class<?> clazz = classLoader.loadClass(className);
System.out.println("Loaded class: " + clazz.getName());
}
}
二十一、NotificationPublisherAware
NotificationPublisherAware 是 Spring 提供的用于管理 JMX 通知的扩展接口。实现该接口的 Bean 可以通过 NotificationPublisher 来发送 JMX 通知。
使用场景:适用于需要在应用中向外部系统发送 JMX 通知的情况,通常用于系统监控或状态更新。
示例:
@Component
public class JmxNotificationBean implements NotificationPublisherAware {
private NotificationPublisher notificationPublisher;
@Override
public void setNotificationPublisher(NotificationPublisher notificationPublisher) {
this.notificationPublisher = notificationPublisher;
}
public void sendNotification(String message) {
notificationPublisher.sendNotification(new Notification("type", this, 0, message));
}
}
二十二、LoadTimeWeaverAware
LoadTimeWeaverAware 接口用于获取 LoadTimeWeaver,这是 Spring 用于实现加载时织入(如 AOP)的组件。实现该接口的 Bean 可以在加载时织入特定的逻辑。
使用场景:常用于实现加载时的 AspectJ 织入,以便在运行时动态增强 Bean 的行为。
示例:
@Component
public class WeaverAwareBean implements LoadTimeWeaverAware {
private LoadTimeWeaver loadTimeWeaver;
@Override
public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
this.loadTimeWeaver = loadTimeWeaver;
}
}
二十三、BeanNameAware
BeanNameAware 接口允许获取当前 Bean 的名称。实现该接口的 Bean 可以在容器初始化时获取它在容器中的名称。
使用场景:适用于需要在运行时知道自身名称的 Bean,常用于调试或在特殊情况下依赖 Bean 名称的逻辑。
示例:
@Component
public class BeanNameAwareComponent implements BeanNameAware {
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
public void printBeanName() {
System.out.println("Bean name: " + beanName);
}
}
二十四、DruidDataSource MBean 扩展
如果项目中使用了阿里巴巴的 Druid 数据源,Spring 也支持将其注册为 MBean 以便进行监控和管理。
使用场景:适合需要监控数据库连接池状态的场景。
示例:
@Configuration
public class DruidConfiguration {
@Bean
public ServletRegistrationBean<StatViewServlet> druidServlet() {
ServletRegistrationBean<StatViewServlet> servletRegistrationBean =
new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
servletRegistrationBean.addInitParameter("loginUsername", "admin");
servletRegistrationBean.addInitParameter("loginPassword", "admin");
return servletRegistrationBean;
}
}
二十五、Aspect Oriented Programming (AOP) 相关接口
在 Spring AOP 中,还有一些接口可以用于拦截方法执行,例如 MethodInterceptor。Spring 的 AOP 功能允许通过切面、通知、连接点等机制对方法调用进行增强。
使用场景:适用于需要动态代理或拦截方法调用,加入日志、权限校验、事务管理等横切关注点的场景。
示例:
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object logMethodExecution(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Executing method: " + joinPoint.getSignature().getName());
Object result = joinPoint.proceed();
System.out.println("Method executed successfully");
return result;
}
}
最后的小总结
1. ApplicationContextAware
- 描述:用于获取 ApplicationContext 实例。
- 场景:访问 Spring 容器中的其他 Bean,或获取环境属性。
2. BeanFactoryAware
- 描述:用于获取 BeanFactory 实例。
- 场景:动态获取 Bean 或管理 Bean 的生命周期。
3. EnvironmentAware
- 描述:获取 Environment,访问环境属性和配置文件。
- 场景:动态读取环境变量或配置文件属性。
4. ResourceLoaderAware
- 描述:获取 ResourceLoader,加载文件资源。
- 场景:加载配置文件、图片等资源。
5. MessageSourceAware
- 描述:获取 MessageSource,访问国际化消息。
- 场景:多语言支持,动态获取不同语言文本。
6. ApplicationEventPublisherAware
- 描述:获取 ApplicationEventPublisher,发布自定义事件。
- 场景:在应用中触发特定事件并通知其他组件。
7. EmbeddedValueResolverAware
- 描述:获取 StringValueResolver,解析占位符和表达式。
- 场景:解析属性占位符或表达式。
8. BeanNameAware
- 描述:获取当前 Bean 的名称。
- 场景:需要在运行时获取 Bean 名称,调试或依赖名称的逻辑。
9. InitializingBean & DisposableBean
- 描述:InitializingBean 在初始化后调用,DisposableBean 在销毁时调用。
- 场景:在 Bean 的生命周期中执行初始化或销毁逻辑。
10. SmartInitializingSingleton
- 描述:容器启动完成后调用实现此接口的所有单例 Bean。
- 场景:用于容器完全启动后执行特定操作,如数据库检查、缓存加载。
11. FactoryBean
- 描述:创建复杂 Bean 的工厂类。
- 场景:Bean 需要复杂构造过程时,使用 FactoryBean 提供实例。
12. ApplicationListener
- 描述:监听并处理 Spring 容器内的事件。
- 场景:对容器事件做出反应,如上下文启动、刷新、关闭等。
13. SmartLifecycle
- 描述:扩展了 Lifecycle 接口,控制启动和停止顺序。
- 场景:容器启动或停止时执行特定逻辑。
14. LoadTimeWeaverAware
- 描述:获取 LoadTimeWeaver,支持加载时织入(如 AOP)。
- 场景:加载时增强 Bean,比如使用 AspectJ 动态代理。
15. AsyncConfigurer
- 描述:配置自定义异步任务执行器和异常处理器。
- 场景:自定义异步任务的执行逻辑或处理异步异常。
16. PropertySourcesPlaceholderConfigurer
- 描述:处理配置文件中的占位符解析,适用于外部配置管理。
- 场景:从外部属性文件中加载配置,如 .properties 文件。
17. ServletContextAware
- 描述:获取 ServletContext 实例,适用于 Web 环境。
- 场景:访问 Web 环境中的资源或管理 Web 容器级别的设置。
18. BeanClassLoaderAware
- 描述:获取类加载器 ClassLoader。
- 场景:在运行时加载类或资源,如插件加载器。
19. NotificationPublisherAware
- 描述:管理 JMX 通知,通过 NotificationPublisher 发送通知。
- 场景:向外部系统发送 JMX 通知,如系统监控。
20. LoadTimeWeaverAware
- 描述:实现加载时织入,支持动态增强 Bean 行为。
- 场景:在加载时织入 AOP 增强逻辑,特别是 AspectJ 应用场景。
21. BeanNameAware
- 描述:获取当前 Bean 的名称。
- 场景:需要在运行时获取自身名称,适合调试和管理 Bean 名称的情况。
22. DruidDataSource MBean 扩展
- 描述:在应用使用阿里巴巴 Druid 数据源时,可注册为 MBean 管理。
- 场景:监控数据库连接池状态,适用于系统监控需求。
23. Aspect Oriented Programming (AOP) 相关接口
- 描述:如 MethodInterceptor,用于拦截方法调用,实现 AOP。
- 场景:加入日志、权限校验、事务管理等横切关注点。
这些扩展接口帮助我们实现对 Bean 生命周期、资源管理、事件发布、属性解析等细节的控制。合理使用这些接口可以让应用更加模块化、灵活、符合不同的业务需求。