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 {

}

posted @   无极是一种信仰  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示