1,监听器

Java事件监听器是由事件类和监听接口组成,自定义一个事件前,必须提供一个事件的监听接口以及一个事件类。JAVA中监听接口是继承java.util.EventListener的类,事件类继承java.util.EventObject的类。

ApplicationListener是Spring框架提供的一个接口,它可以在Spring容器初始化完成或销毁之后,进行一系列的自定义操作。通过实现ApplicationListener接口,我们可以在程序启动或关闭时进行一些特定的操作,比如初始化一些资源、启动缓存、配置日志、关闭数据库连接等。通过监听Spring容器的启动和关闭消息,我们可以在应用启动时完成初始化操作,而在应用关闭时完成销毁操作。

通过spring的监听器,我们不仅可以实现自己相关的业务,还可以通过这个机制将我们自己的组件和spring进行整合,比如阿里的nacos就是通过ApplicationListener与spring整合的.

:多租户多数据源初始化

@Slf4j
@Configuration
public class MyNacosConfigListening implements ApplicationListener<EnvironmentChangeEvent> {
    @Autowired
    private EnvironmentManager environmentManager;
    @Autowired
    private DataSource dataSource;

    @Override
    public void onApplicationEvent(EnvironmentChangeEvent event) {
        Set<String> keys = event.getKeys();
        DynamicRoutingDataSource dynamicRoutingDataSource = (DynamicRoutingDataSource) this.dataSource;
        for (String key : keys) {
            if("dynamic.tenantId".equals(key)){
                String val = (String) environmentManager.getProperty(key);
                String[] tenantDataSourceKeys = val.split(",");
            }
        }
    }
}

nacos配置:

2,过滤器

Filter是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。

例:将请求头的header信息如登录的账号信息,请求唯一标识traceId等存入ThreadLocal中以便取值

package com.yixin.saas.tb.configure;

import com.yixin.auth.UserInfo;
import com.yixin.auth.UserSessionContext;
import org.springframework.context.annotation.Configuration;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Configuration
public class UserSessionFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
        try {
            //登录账号信息
            String account = httpRequest.getHeader("account");
            String name = httpRequest.getHeader("name");
            UserSessionContext.setUserSession(new UserInfo(account, name));

            //请求唯一标识
            String traceId = httpRequest.getHeader("traceId");
            TraceIdSessionContext.setTraceIdSession(traceId);

            filterChain.doFilter(servletRequest, servletResponse);
        } finally {
            UserSessionContext.clearUserSession();
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void destroy() {
    }
}

3,拦截器

Interceptor 在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。比如日志,安全等。一般拦截器方法都是通过动态代理的方式实现。可以通过它来进行权限验证,或者判断用户是否登陆,或者是像12306 判断当前时间是否是购票时间。

例:使用feign做服务间调用的时候,修改请求的头部信息

package com.yixin.auth;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

@Component
@Slf4j
public class FeignInterceptorConfiguration implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        try {
            //登录账号信息
            if (UserSessionContext.getUserSession() != null) {
                requestTemplate.header("account", UserSessionContext.getAccount());
                requestTemplate.header("name", UserSessionContext.getCnName());
            }
            //请求唯一标识
            if (StringUtils.isNotBlank(TraceIdSessionContext.getTraceIdSession())) {
                requestTemplate.header("traceId", TraceIdSessionContext.getTraceIdSession());
            }
        } catch (Exception e) {
            log.error("feign interceptor header error: {}", e.getMessage());
        }
    }
}