专业的JAVA编程教程与资源

网站首页 > java教程 正文

spring原生实现拦截器&java agent实现拦截器

temp10 2024-11-04 14:08:13 java教程 10 ℃ 0 评论

在Spring框架中,拦截器是一种强大的机制,它允许我们在请求到达处理程序之前或处理程序返回响应之后对请求进行拦截和处理。在拦截器中,preHandle方法是其中一个最常用的方法之一,它用于在请求到达处理程序之前对请求进行预处理。以下是关于preHandle方法的解释:

preHandle方法是在请求到达处理程序之前被调用的,它返回一个布尔值。如果该方法返回true,则请求将继续被处理程序处理;如果该方法返回false,则请求将被拦截并停止继续处理。

spring原生实现拦截器&java agent实现拦截器

在preHandle方法中,可以进行很多有用的操作,例如:

  1. 记录请求日志,用于跟踪请求的处理过程;
  2. 对请求进行验证,例如检查请求参数是否合法;
  3. 检查当前用户是否有权限访问该请求,如果没有,则可以返回一个错误响应;
  4. 在请求到达处理程序之前设置一些通用的属性,例如请求的Locale。

在preHandle方法中,可以通过方法的参数来访问请求对象和响应对象,例如HttpServletRequest和HttpServletResponse对象。此外,我们还可以通过返回一个ModelAndView对象来指定要渲染的视图和视图的模型。

以下是一个使用preHandle方法的例子:

假设我们有一个网站,用户在登录后可以访问一些需要登录才能访问的页面,如果用户没有登录,访问这些页面将会被重定向到登录页面。我们可以使用preHandle方法来实现这个功能。具体步骤如下:

  1. 创建一个拦截器类,并实现HandlerInterceptor接口。
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
            response.sendRedirect("/login");
            return false;
        }
        return true;
    }
}
  1. 在Spring的配置文件中,配置该拦截器。
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/admin/**"/>
        <bean class="com.example.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

在上述配置中,我们指定了要拦截的URL模式(/admin/**),以及要使用的拦截器类(com.example.interceptor.LoginInterceptor)。

在preHandle方法中,我们首先获取当前会话中保存的用户信息。如果用户信息为空,说明用户没有登录,我们将会重定向到登录页面,并返回false。如果用户信息不为空,说明用户已经登录,我们将会返回true,请求将继续被处理程序处理。

这样,当用户访问需要登录才能访问的页面时,该拦截器将会拦截请求,检查用户是否已经登录,如果没有登录,将会重定向到登录页面。


怎么通过preHandle实现对所有请求先判断是否有访问权限

  1. 创建一个拦截器类,并实现HandlerInterceptor接口。
public class AccessInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
            response.sendRedirect("/login");
            return false;
        }
        String uri = request.getRequestURI();
        // 根据uri判断用户是否有权限访问
        boolean hasAccess = checkAccess(user, uri);
        if (!hasAccess) {
            response.sendRedirect("/403");
            return false;
        }
        return true;
    }

    private boolean checkAccess(User user, String uri) {
        // 判断用户是否有权限访问uri
        // 这里可以从数据库或者其他地方获取用户的权限信息,并进行判断
        return true;
    }
}
  1. 在Spring的配置文件中,配置该拦截器。
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.example.interceptor.AccessInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>

在上述配置中,我们指定了要拦截的URL模式(/**),也就是所有的请求都会被拦截,以及要使用的拦截器类(com.example.interceptor.AccessInterceptor)。

在preHandle方法中,我们首先获取当前会话中保存的用户信息。如果用户信息为空,说明用户没有登录,我们将会重定向到登录页面,并返回false。

如果用户信息不为空,我们根据请求的URI来判断用户是否有权限访问该请求。如果用户没有权限访问该请求,我们将会重定向到403页面,并返回false。如果用户有权限访问该请求,我们将会返回true,请求将继续被处理程序处理。

介绍下HandlerInterceptor

HandlerInterceptor是Spring框架中的一个拦截器接口,用于在控制器方法(Controller)执行前后以及视图渲染之前提供拦截功能。它是Spring MVC框架的一部分,可以被用来对请求进行拦截,进行一些预处理、后处理和业务逻辑处理等。

HandlerInterceptor接口包括了三个方法:

  1. preHandle:在控制器方法执行前执行。在该方法中可以对请求进行拦截、校验等操作,可以决定请求是否继续进行。
  2. postHandle:在控制器方法执行后但是视图渲染之前执行。在该方法中可以对ModelAndView对象进行操作,可以在返回视图之前对数据进行修改。
  3. afterCompletion:在视图渲染之后执行。在该方法中可以对请求执行一些资源清理操作,如释放数据库连接等。

在Spring MVC框架中,我们可以通过实现HandlerInterceptor接口,自定义拦截器来实现对请求的拦截处理。在实现HandlerInterceptor接口后,我们需要在Spring的配置文件中配置拦截器,指定拦截的URL模式等相关信息。配置完成后,拦截器将会对符合URL模式的请求进行拦截处理。

下面是一个简单的拦截器实现示例:

public class AccessInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        if (user == null) {
            response.sendRedirect("/login");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在这里对ModelAndView进行一些处理,如添加公共数据等
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在这里进行一些资源清理操作,如释放数据库连接等
    }
}

在上述示例中,我们实现了HandlerInterceptor接口,并重写了其中的三个方法:preHandle、postHandle和afterCompletion。在preHandle方法中,我们通过检查Session中是否保存了用户信息,判断用户是否已经登录。如果用户没有登录,我们将会重定向到登录页面,并返回false,请求将会被拦截。如果用户已经登录,我们将会返回true,请求将会继续被处理程序处理。

在postHandle方法中,我们可以对ModelAndView进行一些处理,比如添加一些公共数据等,以便于在视图渲染时使用。在afterCompletion方法中,我们可以进行一些资源清理操作,如释放数据库连接等。

要使用自定义的拦截器,我们需要在Spring的配置文件中进行配置,如下所示:

<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.example.inter>

springboot怎么使用HandlerInterceptor

在Spring Boot中使用HandlerInterceptor需要以下步骤:

  1. 创建自定义拦截器类实现HandlerInterceptor接口
@Component
public class CustomInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在请求处理之前进行调用(Controller方法调用之前)
        // 返回true才会继续向下执行,返回false取消当前请求
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在整个请求结束之后被调用,也就是在DispatcherServlet渲染了对应的视图之后执行(主要是用于进行资源清理工作)
    }
}
  1. 注册自定义拦截器类
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private CustomInterceptor customInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加自定义拦截器
        registry.addInterceptor(customInterceptor)
                // 添加需要拦截的路径
                .addPathPatterns("/**")
                // 排除不需要拦截的路径
                .excludePathPatterns("/login", "/register");
    }
}

在上述代码中,我们创建了一个名为CustomInterceptor的自定义拦截器类,实现了HandlerInterceptor接口,并重写了其三个方法preHandle()、postHandle()和afterCompletion()。接着,我们在WebConfig类中注册了该拦截器,并指定需要拦截的路径和需要排除的路径。

其中,addPathPatterns()方法用于添加需要拦截的路径,excludePathPatterns()方法用于排除不需要拦截的路径。

这样,我们就完成了在Spring Boot中使用HandlerInterceptor的配置。在这个例子中,所有请求都会被CustomInterceptor拦截,但是排除了/login和/register这两个路径的请求。在CustomInterceptor中,我们可以编写具体的业务逻辑来实现对请求的拦截和处理。

WebMvcConfigurer

WebMvcConfigurer是一个接口,用于配置Spring MVC的行为,其中定义了很多方法可以供开发人员自定义MVC配置。通过实现该接口,我们可以在Spring MVC的默认配置基础上添加、修改或删除一些配置。

一般情况下,我们可以通过继承WebMvcConfigurerAdapter来实现WebMvcConfigurer接口,因为WebMvcConfigurerAdapter已经提供了默认的空实现,这样我们只需要重写我们需要的方法即可,避免了我们需要实现所有接口方法的麻烦。

WebMvcConfigurer包含了多个方法,常用的方法有:

  • addInterceptors(InterceptorRegistry registry):用于注册拦截器。
  • configureViewResolvers(ViewResolverRegistry registry):用于配置视图解析器。
  • addResourceHandlers(ResourceHandlerRegistry registry):用于配置静态资源处理器。
  • configureContentNegotiation(ContentNegotiationConfigurer configurer):用于配置内容协商处理器。
  • configurePathMatch(PathMatchConfigurer configurer):用于配置URL路径匹配规则。

除此之外,还有很多其他的方法,开发人员可以根据需要进行选择和实现。

在Spring Boot中,我们可以通过实现WebMvcConfigurer接口来自定义Spring MVC配置,例如添加自定义拦截器、配置视图解析器、配置静态资源处理器等。在Spring Boot中,我们可以在@Configuration注解的类中实现WebMvcConfigurer接口,通过重写其中的方法来完成配置。

@Configuration
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加自定义拦截器
        registry.addInterceptor(new CustomInterceptor())
                // 添加需要拦截的路径
                .addPathPatterns("/**")
                // 排除不需要拦截的路径
                .excludePathPatterns("/login", "/register");
    }
}

在上述代码中,我们创建了一个名为MvcConfig的配置类,实现了WebMvcConfigurer接口,并重写了其中的addInterceptors()方法,用于添加自定义拦截器并指定需要拦截的路径和需要排除的路径。这样,我们就完成了在Spring Boot中使用WebMvcConfigurer配置拦截器的操作。

通过java agent实现请求拦截的方案

Java Agent是一种特殊的Java程序,可以在JVM启动时动态地将字节码注入到已加载的类中,从而改变类的行为。利用Java Agent,我们可以实现许多Java代码层面上无法实现的功能,例如监控、调试、性能分析等。

在实现请求拦截的方案中,我们可以通过Java Agent来实现。具体来说,我们可以利用Java Agent将字节码注入到Servlet容器中,从而拦截和记录所有的HTTP请求和响应信息。这种方式相对于使用Servlet Filter或者Spring拦截器等方式,具有更高的性能和更全面的覆盖范围。

下面是一种基于Java Agent实现请求拦截的方案:

  1. 定义拦截器类

定义一个实现javax.servlet.Filter接口的拦截器类,用于拦截HTTP请求并记录请求信息。在实现doFilter()方法时,可以在请求前后分别记录请求信息和响应信息。

  1. 编写Java Agent

编写一个Java Agent程序,在Agent的premain()方法中将拦截器类的字节码注入到Servlet容器中。在注入字节码时,需要将拦截器类的实例传递给Servlet容器,以便在Servlet容器中调用拦截器类的方法。

  1. 配置Java Agent

在启动Servlet容器时,通过Java Agent参数指定上述编写的Java Agent程序,并设置需要拦截的Servlet容器的启动类路径。

  1. 启动Servlet容器

启动Servlet容器,当有HTTP请求时,Java Agent会将拦截器类的字节码注入到Servlet容器中,从而拦截HTTP请求并记录请求信息。

这种方案虽然实现起来比较复杂,但是具有较高的可扩展性和灵活性,可以满足更加复杂和严格的请求拦截需求。同时,由于利用Java Agent实现,因此对原有应用程序没有侵入性,也不会对应用程序的性能造成过大的影响。

面是一个基于Java Agent实现请求拦截的示例:

  1. 定义拦截器类
public class RequestInterceptor implements Filter {
 
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // 初始化方法
    }
 
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 记录请求信息
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        String method = httpServletRequest.getMethod();
        String uri = httpServletRequest.getRequestURI();
        String queryString = httpServletRequest.getQueryString();
        String remoteAddr = httpServletRequest.getRemoteAddr();
        String userAgent = httpServletRequest.getHeader("User-Agent");
        System.out.printf("Received %s request %s%s from %s using %s\n", method, uri, queryString != null ? "?" + queryString : "", remoteAddr, userAgent);
 
        // 执行请求处理链
        chain.doFilter(request, response);
 
        // 记录响应信息
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        int statusCode = httpServletResponse.getStatus();
        String contentType = httpServletResponse.getContentType();
        System.out.printf("Sent response with status code %d and content type %s\n", statusCode, contentType);
    }
 
    @Override
    public void destroy() {
        // 销毁方法
    }
}
  1. 编写Java Agent
public class RequestInterceptorAgent {
 
    public static void premain(String agentArgs, Instrumentation inst) {
        Class<?>[] classes = inst.getAllLoadedClasses();
        for (Class<?> clazz : classes) {
            if (clazz.getName().equals("org.apache.catalina.core.ApplicationFilterChain")) {
                try {
                    Field filtersField = clazz.getDeclaredField("filters");
                    filtersField.setAccessible(true);
                    Object filtersObj = filtersField.get(null);
                    List<Filter> filters = (List<Filter>) filtersObj;
                    filters.add(new RequestInterceptor());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  1. 配置Java Agent

在启动Servlet容器时,通过-javaagent参数指定上述编写的Java Agent程序。

  1. 启动Servlet容器

启动Servlet容器,当有HTTP请求时,Java Agent会将拦截器类的字节码注入到Servlet容器中,从而拦截HTTP请求并记录请求信息。

注意,此示例是基于Tomcat的实现,对于其他Servlet容器的实现可能会有所不同。

介绍下premain方法及其参数

premain方法是Java Agent的启动方法,当使用-javaagent参数启动Java虚拟机时,虚拟机会在执行main方法之前调用该方法。其定义如下:

public static void premain(String agentArgs, Instrumentation inst);

其中,agentArgs是一个字符串类型的参数,用于传递给Java Agent的启动参数。inst是java.lang.instrument.Instrumentation类型的对象,它提供了一些操作当前Java虚拟机的方法,例如:

  • addTransformer方法:用于向当前Java虚拟机添加一个java.lang.instrument.ClassFileTransformer类型的类转换器;
  • redefineClasses方法:用于重新定义一个或多个已加载的类的字节码;
  • getAllLoadedClasses方法:返回当前Java虚拟机中所有已加载的类的数组;
  • appendToBootstrapClassLoaderSearch方法:用于向启动类加载器的搜索路径中添加一个或多个JAR文件。

通过premain方法和Instrumentation对象,Java Agent可以在程序运行期间对类进行动态修改,添加拦截器等增强功能。通常情况下,Java Agent会先使用addTransformer方法向当前Java虚拟机添加一个类转换器,在转换器中对目标类进行修改,例如添加拦截器,然后再通过redefineClasses方法重新定义该类的字节码。

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表