SpringBoot组件

过滤器

使用

  • 实现filter接口并实现doFilter方法
  • 添加过滤器有两种方式
    • 使用@WebFilter+@Component+@order指定顺序
      • 或者使用@WebFilter+在主程序类上添加@ServletComponentScan
    • 使用@Bean + FilterRegistrationBean
  • 其实过滤器应该在spring容器之前的,但是使用了注解方式交给容器管理之后他好像和spring的拦截器也没有什么不同了
  • 过滤器在项目启动时就会实例化以及初始化,在服务关闭的时候销毁

注解方式

@Slf4j  
@Component  
// 使用order指定顺序  
@Order(3)  
@WebFilter(filterName = "studentLogFilter",urlPatterns = {"/student/**"})  
public class HttpRequestLogFilter implements Filter {  
    @Override  
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {  
        log.info("==========================studentLogFilter1 filter================>>>>>>>>>>");  
        HttpServletRequest request = (HttpServletRequest) servletRequest;  
        // 获取请求路径  
        String contextPath = request.getContextPath();  
        String requestURI = request.getRequestURI();  
        String queryString = request.getQueryString();  
        String servletPath = request.getServletPath();  
        log.info("studentLogFilter contextPath is {},requestURI is {},queryString is {},servletPath is {}",contextPath,requestURI,queryString,servletPath);  
        Enumeration<String> headerNames = request.getHeaderNames();  
        while (headerNames.hasMoreElements()){  
            String s = headerNames.nextElement();  
            String header = request.getHeader(s);  
            log.info("studentLogFilter head message {} = {}",s,header);  
        }  
        // 读取body中的参数 但是SelvetRequest的inputStream只能够读取一次  
        // 使用ContentCachingRequestWrapper对request进行包装 ContentCachingRequestWrapper能够让inputStream重复读取  
        ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request, 0);  
        // 读取  
        byte[] bytes = requestWrapper.getContentAsByteArray();  
        if(bytes.length > 0){  
            log.info("studentLogFilter request body is {}",new String(bytes));  
        }  
        filterChain.doFilter(requestWrapper,servletResponse);  
    }  
}

@Bean的方式

public class MyConfig {  
    @Bean  
    public FilterRegistrationBean<HttpRequestLog3Filter> studentLogFilter3(){  
        // 现在做出一个选择吧,按照网上一模一样写的 但是不知道为啥不好用  
        // 1.找出原因(花费时间)  
        // 2.暂时跳过 反正还有注解版可以使用 √        FilterRegistrationBean<HttpRequestLog3Filter> filter = new FilterRegistrationBean<>();  
        //设置过滤器实例  
        filter.setFilter(new HttpRequestLog3Filter());  
        // 过滤器名称  
        filter.setName("studentFilter3");  
        // 是否启用  
        // filter.setEnabled(true);  
        // 设置过滤路径  
        //filter.setUrlPatterns(Collections.singletonList("/student/**"));  
        // 设置优先级  
        filter.setOrder(0);  
        // 增加过滤路径  
        filter.addUrlPatterns("/**");  
        return filter;  
    }  
}

@Slf4j  
public class HttpRequestLog3Filter implements Filter {  
    @Override  
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {  
        log.info("FilterRegistrationBean 方式添加过滤器 ");  
        System.out.println("================================================");  
        filterChain.doFilter(servletRequest,servletResponse);  
    }  
}

监听器

应用生命周期监听器(SpringApplicationRunListener)

  • 监听springBoot应用启动的完整流程
public interface SpringApplicationRunListener {
	//开始启动 
    default void starting(ConfigurableBootstrapContext bootstrapContext) {
    }
	// 环境准备完成
    default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
    }
	// 上下文准备完成 什么是上下文?
    default void contextPrepared(ConfigurableApplicationContext context) {
    }
	// 上下文加载完成
    default void contextLoaded(ConfigurableApplicationContext context) {
    }
	// 应用已启动
    default void started(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {
    }
	// 应用就绪
    default void ready(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {
    }
	// 应用启动失败
    default void failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {
    }
}
使用方式
  • 继承SpringApplicationRunListener实现其中的方法
  • 在resource目录下新建META-INF/spring.factories文件
    • 在文件中指定自己写的ApplicationRunListener
    	org.springframework.boot.SpringApplicationRunListener=\  
    com.cpz.mybatistest.listener.MySpringApplicationRunListener
    
/**  
 * spring应用启动监听器  
 * @author: caorongwei  
 * 2026/1/16 13:45 */@Slf4j  
public class MySpringApplicationRunListener implements SpringApplicationRunListener {  
    @Override  
    public void starting(ConfigurableBootstrapContext bootstrapContext) {  
        // 这个地方用log打印不出来  
        System.out.println("++++++++++++Application starting++++++++++");  
        System.out.println("startTime:==========>>>>" + LocalDateTime.now());  
        // bootstrapContext 就是spring容器  
        // 注册自定义Bootstrap组件 不是往IOC容器中注册  
        bootstrapContext.register(Student.class, BootstrapRegistry.InstanceSupplier.from(() -> {  
            Student s = new Student();  
            s.setAddress("阿美莉卡斯坦福大学");  
            s.setName("生命的礼物");  
            s.setAge(30);  
            s.setHeight(189.1);  
            s.setSex("男");  
            return s;  
        }));  
    }  
  
    @Override  
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {  
        // 环境准备好 这个地方可以指定激活那个环境配置  
		log.info("====================environmentPrepared======================");  
        // 这个位置能够获取到Student对象  
        Student orElse = bootstrapContext.getOrElse(Student.class, null);  
        log.info("+++++++++++++ Student is {}",orElse);  
        // 获取系统环境变量  
        Map<String, Object> systemEnvironment = environment.getSystemEnvironment();  
        systemEnvironment.forEach((key,value)->{  
            log.info("============== systemEnvParm is {} = {}",key,value);  
        });  
        for (String activeProfile : environment.getActiveProfiles()) {  
            log.info("=================== activeProfile is {}",activeProfile);  
        }  
        //可以在这里修改环境配置 新增激活的配置  
        //environment.addActiveProfile();  
  
    }  
  
    @Override  
    public void contextPrepared(ConfigurableApplicationContext context) {  
        // 上下文准备完毕 但是还没开始制造Bean 现在获取Bean会报错  
        // 也是能够获取IOC容器对象,  
        // org.springframework.boot.web.server.servlet.context.AnnotationConfigServletWebServerApplicationContext@16f1f8fb has not been refreshed yet  
        log.info("==========================contextPrepared======================");  
        //能够注册Bean到IOC容器中  
        ((BeanDefinitionRegistry) context).registerBeanDefinition("student01", BeanDefinitionBuilder.genericBeanDefinition(Student.class).getBeanDefinition());  
    }  
  
    @Override  
    public void contextLoaded(ConfigurableApplicationContext context) {  
        // 这一步也不能够获取Bean 同样会报容器还没有刷新错误  
        log.info("============================contextLoaded======================");  
        int beanDefinitionCount = context.getBeanDefinitionCount();  
        log.info("============== BeanCount is {}",beanDefinitionCount);  
    }  
  
    @Override  
    public void started(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {  
        // 应用已经启动,但是还没开始接请求  
        // 容器已经刷新 可以获取到Bean
        log.info("============================started======================");  
        Student s = context.getBean(Student.class);  
        log.info("+++++++++++++ Student is {}",s);  
    }  
  
    @Override  
    public void ready(ConfigurableApplicationContext context, @Nullable Duration timeTaken) {  
        // 应用就绪 可以接受请求  
        log.info("========================ready======================");  
        log.info("===========启动时间:{}秒=============",timeTaken.getSeconds());  
        log.info("===================Application 启动完成!======================");  
  
    }  
  
    @Override  
    public void failed(@Nullable ConfigurableApplicationContext context, Throwable exception) {  
       log.error("===============Application 启动失败!==============",exception);  
    }  
}

Spring容器监听器(ApplicationListener)

能够监听Spring容器的各个阶段

各种事件
  1. ApplicationStartingEvent // 应用开始启动
  2. ApplicationEnvironmentPreparedEvent // 环境准备完成
  3. ApplicationContextInitializedEvent // 上下文初始化完成
  4. ApplicationPreparedEvent // 上下文准备完成
  5. ContextRefreshedEvent // 上下文刷新完成,容器刷新完成
  6. ApplicationStartedEvent // 应用已启动
  7. ApplicationReadyEvent // 应用准备就绪(可处理请求)
  8. ContextClosedEvent // 上下文关闭
  9. ContextStoppedEvent // 上下文停止
通过事项ApplicationListener接口的方式进行监听
  • 实际测试时候如果使用Component注解的方式将监听器注入到容器中,那么这个applicationListener只能监听到容器刷新到容器关闭之间的事件
    • ContextRefreshedEvent
    • ApplicationStartedEvent
    • ApplicationReadyEvent
    • ContextClosedEvent
@Slf4j  
@Component  
// 也可替换成具体的事件,只监听一种事件  
// public class MyApplicationListener implements ApplicationListener<ApplicationStartingEvent>  
// 不太对 实际测试  
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {  
    @Override  
    public void onApplicationEvent(ApplicationEvent event) {  
        if(event instanceof ApplicationStartingEvent event1){  
            String name = event1.getSpringApplication().getClass().getName();  
            log.info("MyApplicationListener: application begin main class is {}",name);  
            System.out.println("MyApplicationListener: application begin");  
        }else if(event instanceof ContextRefreshedEvent event1){  
            int beanDefinitionCount = event1.getApplicationContext().getBeanDefinitionCount();  
            String[] beanDefinitionNames = event1.getApplicationContext().getBeanDefinitionNames();  
            Student bean = event1.getApplicationContext().getBean(Student.class);  
            log.info("MyApplicationListener: IOC refreshed,beanDefinitionCount is {},beanDefinitionNames is {}",beanDefinitionCount,beanDefinitionNames);  
            log.info("MyApplicationListener: IOC refreshed,get student from IOC student is {}",bean);  
        }else if(event instanceof ApplicationReadyEvent event1){  
            log.info("MyApplicationListener:--------- listen ApplicationReadyEvent");  
        }else if(event instanceof ApplicationEnvironmentPreparedEvent event1){  
            log.info("MyApplicationListener:listen ApplicationEnvironmentPreparedEvent");  
        }else if(event instanceof ApplicationContextInitializedEvent event1){  
            log.info("MyApplicationListener:--------- listen ApplicationContextInitializedEvent");  
        }else if(event instanceof ApplicationPreparedEvent event1){  
            log.info("MyApplicationListener:listen ApplicationPreparedEvent");  
        }else if(event instanceof ApplicationStartedEvent event1){  
            log.info("MyApplicationListener:--------- listen ApplicationStartedEvent");  
        }else if(event instanceof ContextClosedEvent event1){  
            log.info("MyApplicationListener:--------- listen ContextClosedEvent");  
        }else if(event instanceof ContextStoppedEvent event1){  
            log.info("MyApplicationListener:--------- listen ContextStoppedEvent");  
        }  
    }  
}
使用EventListener注解的方式进行监听(推荐)
  • 使用异步线程池处理监听事件 @Async("taskExecutor")
  • 监听多个事件
@EventListener({ContextStartedEvent.class, ContextRefreshedEvent.class})
  • 使用SpEL表达式条件监听
@EventListener(condition = "#event.applicationContext.getEnvironment().acceptsProfiles('prod')")
@Slf4j  
@Component  
public class MyApplicationListener2 {  
    @EventListener(value = ContextRefreshedEvent.class)  
    // 使用Order来指定监听器对同一事件的处理顺序  
    @Order(1)  
    public void handleContextRefreshedEvent(ContextRefreshedEvent event){  
        ApplicationContext applicationContext = event.getApplicationContext();  
        int beanDefinitionCount = applicationContext.getBeanDefinitionCount();  
        log.info("EventListener listen ContextRefreshedEvent the beanDefinitionCount is {}",beanDefinitionCount);  
        for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {  
            log.info("EventListener listen ContextRefreshedEvent the beanDefinitionName is {}",beanDefinitionName);  
        }  
        Student student = applicationContext.getBean(Student.class);  
        log.info("EventListener listen ContextRefreshedEvent the student is {}",student);  
    }  
}

Selvet监听器

主要的监听接口
  • 也就前两个监听器有点用
  1. ServletContextListener - 监听Web应用启动/关闭
  2. ServletRequestListener - 监听HTTP请求开始/结束
  3. ServletRequestAttributeListener - 监听Request属性变化
  4. HttpSessionListener - 监听Session创建/销毁
  5. HttpSessionAttributeListener - 监听Session属性变化
使用方式
  • 使用@WebListener + @SelvetComponentScan注解注入到容器
  • 使用@Component注解
  • 或者像过滤器一样使用@Bean配合ServletListenerRegistrationBean
@Slf4j  
@Component
public class MyServletListener implements ServletRequestListener {  
    private long startTime;  
    @Override  
    public void requestDestroyed(ServletRequestEvent sre) {  
        HttpServletRequest servletRequest = (HttpServletRequest) sre.getServletRequest();  
        String requestURI = servletRequest.getRequestURI();  
        log.info("servlet end request request uri is {} endTime is {},耗时 {}",requestURI, System.currentTimeMillis(),System.currentTimeMillis()-this.startTime);  
    }  
  
    @Override  
    public void requestInitialized(ServletRequestEvent sre) {  
        HttpServletRequest servletRequest = (HttpServletRequest)sre.getServletRequest();  
        this.startTime = System.currentTimeMillis();  
        log.info("servlet recv request request uri is {} startTime is {}",servletRequest.getRequestURI(), startTime);  
    }  
}

@WebListener
@Slf4j  
public class MyServletListener2 implements ServletContextListener {  
    @Override  
    public void contextInitialized(ServletContextEvent sce) {  
        log.info("ServletContextListener Servlet容器 started!!!");  
    }  
  
    @Override  
    public void contextDestroyed(ServletContextEvent sce) {  
        log.info("ServletContextListener Servlet容器 end!!!");  
    }  
}

自定义事件监听器

  • 观察者模式的一种经典实现
自定义事件
  • 继承ApplicationEvent类
public class AddStudentEvent extends ApplicationEvent {  
    private final Student student;  
  
    public AddStudentEvent(Object source,Student student) {  
        super(source);  
        this.student = student;  
    }  
  
    public Student getStudent() {  
        return student;  
    }  
}
ApplicationEventPublisher发布自定义事件
  • 直接注入即可,SpringBoot默认自动提供

@Autowired  
private final ApplicationEventPublisher publisher;
//发布事件
publisher.publishEvent(new AddStudentEvent(this,student));
EventListener监听自定义事件
@EventListener(AddStudentEvent.class)  
@Order(1)  
public void handleAddStudentEvent(AddStudentEvent event){  
    Student student = event.getStudent();  
    log.info("success add a new student student is {}",student);  
    log.info("发送电子邮件给该学生,祝贺她成功入学!");  
}

启动运行器ApplicationRunner

  • Application启动后可以运行一些初始化步骤
  • 实现ApplicationRunner接口
@Component
@Slf4j
public class MyApplicationRunner implements ApplicationRunner {  
    @Autowired  
    private StudentMapper studentMapper;  
    @Override  
    public void run(ApplicationArguments args) throws Exception {  
        // 启动之后测试数据库是否正常  
        try {  
            studentMapper.getStudentById(0);  
            log.info("test mysql connection success!");  
        }catch (Exception e){  
            log.error("cant connect to Mysql Server!",e);  
        }  
        // 初始化数据。。。。。  
    }  
}

各种事件的顺序

Spring Boot 应用启动监听器执行顺序:

  1. SpringApplicationRunListener.starting()
  2. SpringApplicationRunListener.environmentPrepared()
  3. ApplicationListener
  4. ApplicationListener
  5. SpringApplicationRunListener.contextPrepared()
  6. ApplicationListener
  7. SpringApplicationRunListener.contextLoaded()
  8. ApplicationListener
  9. SpringApplicationRunListener.started()
  10. ApplicationListener
  11. ApplicationListener
  12. SpringApplicationRunListener.ready()
  13. ApplicationListener
  14. ApplicationRunner.run() / CommandLineRunner.run()
  15. @EventListener(ApplicationReadyEvent) 方法
posted @ 2026-01-19 17:34  lyfa  阅读(0)  评论(0)    收藏  举报