SpringFramework进阶的功能
事件驱动和监听器:
设计模式:观察者模式,也叫发布订阅模式,也叫监听器模式,是某一个对象被修改 / 做出某些反应 / 发布一个信息等,会自动通知依赖它的对象(订阅者)
观察者模式三大核心:观察者、被观察主题、订阅者
在springframe中,监听器充当订阅者,事件源充当被观察的主题,IOC容器为观察者。
监听器接口:ApplicationListener
//原生监听器接口,实现这个接口来进行监听
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
//监听事件,ContextRefreshedEvent 和 ContextClosedEvent,分别代表容器刷新完毕和即将关闭
@Component //用 @Component 注解标注监听器
public class ContextRefreshedApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("ContextRefreshedApplicationListener监听到ContextRefreshedEvent事件!");
}
}
注解式监听器 @EventListener
@Component
public class ContextClosedApplicationListener {
@EventListener
public void onContextClosedEvent(ContextClosedEvent event) {
System.out.println("ContextClosedApplicationListener监听到ContextClosedEvent事件!");
}
}
ApplicationListener 会在容器初始化阶段就准备好,在容器销毁时一起销毁;
ApplicationListener 也是 IOC 容器中的普通 Bean ;
内置事件:
ContextRefreshedEvent: IOC 容器刷新完毕但尚未启动
ContextClosedEvent: IOC 容器已经关闭但尚未销毁所有 Bean
ContextStartedEvent:单例bean创建后调用start方法时触发
ContextStoppedEvent:ContextClosedEvent 触发之后才会触发,此时单实例 Bean 还没有被销毁,要先把它们都停掉才可以释放资源,销毁 Bean
自定义事件:
//定义事件
public class RegisterSuccessEvent extends ApplicationEvent {
public RegisterSuccessEvent(Object source) {
super(source);
}
}
//监听器
@Component
public class SmsSenderListener implements ApplicationListener<RegisterSuccessEvent> {
@Override
public void onApplicationEvent(RegisterSuccessEvent event) {
System.out.println("监听到用户注册成功,发送短信。。。");
}
}
//注解式监听
@Component
public class EmailSenderListener {
@EventListener
public void onRegisterSuccess(RegisterSuccessEvent event) {
System.out.println("监听到用户注册成功!发送邮件中。。。");
}
}
//业务层触发逻辑
@Service
public class RegisterService implements ApplicationEventPublisherAware {
ApplicationEventPublisher publisher;
public void register(String username) {
// 用户注册的动作。。。
System.out.println(username + "注册成功。。。");
// 发布事件
publisher.publishEvent(new RegisterSuccessEvent(username));
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
}
//
模块装配:
@EnableXXX:
EnableTransactionManagement :开启注解事务驱动
EnableWebMvc :激活 SpringWebMvc
EnableAspectJAutoProxy :开启注解 AOP 编程
EnableScheduling :开启调度功能(定时任务)
举例:
//自定义注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Import(Boss.class) //核心
public @interface EnableTavern {
}
//实体类
public class Boss {
}
//标注到配置类上
@Configuration
@EnableTavern
public class TavernConfiguration {
}
//这样Boss对象就能被创建到IOC容器中了
@import不只能导入普通类,还能导入@Configuration配置类
//配置类
@Configuration
public class BartenderConfiguration {
@Bean
public Bartender zhangxiaosan() {
return new Bartender("张小三");
}
@Bean
public Bartender zhangdasan() {
return new Bartender("张大三");
}
}
//导入
@Import({Boss.class, BartenderConfiguration.class})
public @interface EnableTavern {
}
@Import +ImportSelector实现类
@Import +ImportBeanDefinitionRegistrar实现类
这两种方法也可以导入
条件装配:模块装配是把指定的全部装配到IOC容器中,但要进行更细粒度的装配,就需要条件装配
Profile:注解可以标注一些组件,当应用上下文的一个或多个指定配置文件处于活动状态时,这些组件允许被注册。
举例:
@Configuration
@Profile("city")
public class BartenderConfiguration {
@Bean
public Bartender zhangxiaosan() {
return new Bartender("张小三");
}
@Bean
public Bartender zhangdasan() {
return new Bartender("张大三");
}
}
//没用refalsh
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TavernConfiguration.class);
// 给ApplicationContext的环境设置正在激活的profile
ctx.getEnvironment().setActiveProfiles("city"); //默认为“default”
Stream.of(ctx.getBeanDefinitionNames()).forEach(System.out::println);
}
//refalsh
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("city");
ctx.register(TavernConfiguration.class);
ctx.refresh();
Stream.of(ctx.getBeanDefinitionNames()).forEach(System.out::println);
}
通过jvm启动参数传入
@profile在实际开发中的用法:
@Configuration
public class DataSourceConfiguration {
@Bean
@Profile("dev")
public DataSource devDataSource() {
return null;
}
@Bean
@Profile("test")
public DataSource testDataSource() {
return null;
}
@Bean
@Profile("prod")
public DataSource prodDataSource() {
return null;
}
}
@Conditional 注解: @profile 控制的是整个项目的运行环境,无法根据单个 Bean 的因素决定是否装配;被标注 @Conditional 注解的 Bean 要注册到 IOC 容器时,必须全部满足 @Conditional 上指定的所有条件才可以
//声明一个 ExistBossCondition 类,表示它用来判断 IOC 容器中是否存在 Boss 的对象:
public class ExistBossCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getBeanFactory().containsBeanDefinition(Boss.class.getName()); //boss存在IOC容器中,条件才满足
}
}
@Bean
@Conditional({ExistBossCondition.class})
public Bar bbbar() {
return new Bar();
}
@ConditionalOnBean:@Conditional的派生类,更加方便
public class OnBeanCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 先获取目标自定义注解ConditionalOnBean上的beanNames属性
String[] beanNames = (String[]) metadata.getAnnotationAttributes(ConditionalOnBean.class.getName()).get("beanNames");
// 逐个校验IOC容器中是否包含传入的bean名称
for (String beanName : beanNames) {
if (!context.getBeanFactory().containsBeanDefinition(beanName)) {
return false;
}
}
return true;
}
}
@Bean
@ConditionalOnBean(beanNames = "com.linkedbear.spring.configuration.c_conditional.component.Boss")
public Bar bbbar() {
return new Bar();
}
@ComponentScan按注解过滤
@Configuration
@ComponentScan(basePackages = "com.linkedbear.spring.annotation.f_typefilter",
includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Animal.class))
public class TypeFilterConfiguration {
}
按注解排除
@Configuration
@ComponentScan(basePackages = "com.linkedbear.spring.annotation.f_typefilter",
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Animal.class))
public class TypeFilterConfiguration {
}
按类型过滤
@Configuration
@ComponentScan(basePackages = "com.linkedbear.spring.annotation.f_typefilter",
includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = Color.class)},
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Animal.class)})
public class TypeFilterConfiguration {
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)