欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringAop自定義切面注解、自定義過濾器及ThreadLocal詳解

 更新時(shí)間:2024年01月10日 10:38:13   作者:苦糖果與忍冬  
這篇文章主要介紹了SpringAop自定義切面注解、自定義過濾器及ThreadLocal詳解,Aspect(切面)通常是一個(gè)類,里面可以定義切入點(diǎn)和通知(切面 = 切點(diǎn)+通知),execution()是最常用的切點(diǎn)函數(shù),需要的朋友可以參考下

一、切面表達(dá)式

execution()是最常用的切點(diǎn)函數(shù),其語法如下所示:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?)

execution(<修飾符模式>? <返回類型模式><聲明類型模式><方法名模式>(<參數(shù)模式>) <異常模式>?) 除了返回類型模式、方法名模式和參數(shù)模式外,其它項(xiàng)都是可選的

返回類型模式確定方法的返回類型必須是什么,以便匹配連接點(diǎn)。*最常用作返回類型模式。它匹配任何返回類型。只有當(dāng)方法返回給定類型時(shí),完全限定的類型名稱才匹配。

參數(shù)模式稍微復(fù)雜一些:

()匹配一個(gè)不帶參數(shù)的方法,而(..)匹配任意數(shù)量(零個(gè)或更多)的參數(shù)。

(*)模式匹配采用任意類型的一個(gè)參數(shù)的方法。(*,String)匹配采用兩個(gè)參數(shù)的方法。第一個(gè)可以是任何類型,而第二個(gè)必須是字符串。

二、實(shí)戰(zhàn)代碼

Controller

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.CustomizableThreadCreator;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@RequestMapping("/controller")
public class TestController implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    @Resource
    private ApplicationEventPublisher applicationEventPublisher;
    @GetMapping("/test")
    public String test(@RequestParam String name){
        System.out.println("TestController請求進(jìn)來了:"+Thread.currentThread().getName());
        TestEvent event = new TestEvent(this,name);
//        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
//        for (int i = 0; i <beanDefinitionNames.length ; i++) {
//            System.out.println(beanDefinitionNames[i]);
//        }
        applicationEventPublisher.publishEvent(event);
        System.out.println("TestController請求出去了:"+Thread.currentThread().getName());
        CustomizableThreadCreator bean = applicationContext.getBean(CustomizableThreadCreator.class);
        System.out.println("CustomizableThreadCreator:"+bean.getThreadNamePrefix());
        return "success";
    }
    @PostMapping("/test2")
    @LogAespect
    public String test2(@RequestBody TestRequest request){
        System.out.println("TestController請求進(jìn)來了:"+Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
            System.out.println("hobby:"+request.getHobby());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("TestController請求出去了:"+Thread.currentThread().getName());
        return "success";
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        TestController.applicationContext=applicationContext;
    }
}

定義切面

常用的兩種:一種是基于表達(dá)式,另一種是基于注解的。

注解十分靈活,所以編程中使用的較多。在你需要攔截的方法上面加上自定義注解@LogAespect即可。

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class TestAspect {
    @Pointcut("execution(public * com.test.realname.controller.TestController.test(..))")
    public void pointCut(){
        //這里一般無實(shí)際意義
    }
    @Before("pointCut()")
    public void before()
    {
        System.out.println("===before====");
    }
    @AfterReturning("pointCut()")
    public void afterReturning()
    {
        System.out.println("===afterReturning===");
    }
    @Around("@annotation(com.test.realname.controller.LogAespect)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long l = System.currentTimeMillis();
        HttpServletRequest request = MyFilter.CURRENT_REQUEST.get();
        String requestURI = request.getRequestURI();
        Object proceed = joinPoint.proceed();
        String s=null;
        if(proceed instanceof String){
            s = (String) proceed;
        }
        System.out.println("請求路徑"+requestURI);
        System.out.println("響應(yīng)"+s);
        System.out.println("cost time"+(System.currentTimeMillis()-l));
        return proceed;
    }
}

定義切面注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAespect {
}

request

import java.io.Serializable;

public class TestRequest implements Serializable {

    private String hobby;
    private String streamNo;

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public String getStreamNo() {
        return streamNo;
    }

    public void setStreamNo(String streamNo) {
        this.streamNo = streamNo;
    }

    @Override
    public String toString() {
        return "TestRequest{" +
                "hobby='" + hobby + '\'' +
                ", streamNo='" + streamNo + '\'' +
                '}';
    }
}

request請求中的RequestBody只能讀取一次,因?yàn)镽equestBody是流ServletInputStream,只能讀取一次,所以需要對request請求進(jìn)行包裝,使其能多次重復(fù)讀取。

import org.springframework.util.StreamUtils;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class HttpRequestWrapper extends HttpServletRequestWrapper {
    private final byte[] body;
    public HttpRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body= StreamUtils.copyToByteArray(request.getInputStream());
    }
    @Override
    public BufferedReader getReader() throws IOException{
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
    @Override
    public ServletInputStream getInputStream() throws IOException{
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) {
            }
            @Override
            public int read() throws IOException {
                return byteArrayInputStream.read();
            }
        };
    }
}

自定義過濾器,將request緩存到ThreadLocal中,方便在切面中使用。

ThreadLocal記得在finally中清空,防止內(nèi)存泄漏。

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StreamUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
@Component
public class MyFilter extends OncePerRequestFilter {
    public static final ThreadLocal<HttpServletRequest> CURRENT_REQUEST = new ThreadLocal<>();
    public static boolean isJsonRequest(HttpServletRequest request){
        if(request==null){
            return false;
        }
        return StringUtils.contains(request.getContentType(),"json");
    }
    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        boolean jsonRequest = isJsonRequest(httpServletRequest);
        try {
            if(jsonRequest){
                HttpRequestWrapper wrapper = new HttpRequestWrapper(httpServletRequest);
                CURRENT_REQUEST.set(wrapper);
                String s = StreamUtils.copyToString(wrapper.getInputStream(), StandardCharsets.UTF_8);
                Map map = JSON.parseObject(s, Map.class);
                System.out.println(map);
                filterChain.doFilter(wrapper,httpServletResponse);
            }else {
                CURRENT_REQUEST.set(httpServletRequest);
                filterChain.doFilter(httpServletRequest,httpServletResponse);
            }
        }finally {
            CURRENT_REQUEST.remove();
        }
    }
}

正常返回

{hobby=ball}
TestController請求進(jìn)來了:http-nio-8080-exec-1
hobby:ball
TestController請求出去了:http-nio-8080-exec-1
請求路徑/controller/test2
響應(yīng)success
cost time1009

如果取消包裝的話,就會(huì)直接報(bào)錯(cuò)

{hobby=ball} 2023-01-03 15:45:31.664 WARN 13596 — [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public java.lang.String com.test.realname.controller.TestController.test2(com.test.realname.controller.TestRequest)]

到此這篇關(guān)于SpringAop自定義切面注解、自定義過濾器及ThreadLocal詳解的文章就介紹到這了,更多相關(guān)SpringAop自定義切面注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Quarkus篇入門創(chuàng)建項(xiàng)目搭建debug環(huán)境

    Quarkus篇入門創(chuàng)建項(xiàng)目搭建debug環(huán)境

    這篇文章主要為大家介紹了Quarkus篇入門創(chuàng)建項(xiàng)目搭建debug環(huán)境,先來一套hello?world,來搭建基本的運(yùn)行及調(diào)試環(huán)境吧
    2022-02-02
  • Spring Boot集成Redis實(shí)戰(zhàn)操作功能

    Spring Boot集成Redis實(shí)戰(zhàn)操作功能

    這篇文章主要介紹了Spring Boot集成Redis實(shí)戰(zhàn)操作,包括如何集成redis以及redis的一些優(yōu)點(diǎn),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-11-11
  • 多模塊maven的deploy集成gitlab?ci自動(dòng)發(fā)版配置

    多模塊maven的deploy集成gitlab?ci自動(dòng)發(fā)版配置

    這篇文章主要為大家介紹了多模塊maven項(xiàng)目deploy集成gitlab?ci自動(dòng)發(fā)版的配置流程步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-02-02
  • 大數(shù)組元素差異removeAll與Map效率對比

    大數(shù)組元素差異removeAll與Map效率對比

    這篇文章主要介紹了大數(shù)組元素差異removeAll與Map效率對比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • java簡單解析xls文件的方法示例【讀取和寫入】

    java簡單解析xls文件的方法示例【讀取和寫入】

    這篇文章主要介紹了java簡單解析xls文件的方法,結(jié)合實(shí)例形式分析了java針對xls文件的讀取和寫入相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下
    2017-06-06
  • Java中的MapStruct實(shí)現(xiàn)詳解

    Java中的MapStruct實(shí)現(xiàn)詳解

    這篇文章主要介紹了Java中的MapStruct實(shí)現(xiàn)詳解,MapStruct 是一個(gè)代碼生成器,它基于約定優(yōu)先于配置的方法大大簡化了 JavaBean 類型之間映射的實(shí)現(xiàn),生成的映射代碼使用普通方法調(diào)用,需要的朋友可以參考下
    2023-11-11
  • Spring 自動(dòng)裝配的二義性實(shí)例解析

    Spring 自動(dòng)裝配的二義性實(shí)例解析

    這篇文章主要介紹了Spring 自動(dòng)裝配的二義性實(shí)例解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Struts 2 數(shù)據(jù)校驗(yàn)功能及校驗(yàn)問題的解決方案

    Struts 2 數(shù)據(jù)校驗(yàn)功能及校驗(yàn)問題的解決方案

    這篇文章主要介紹了Struts 2 數(shù)據(jù)校驗(yàn)功能及校驗(yàn)問題的解決方案的相關(guān)資料,需要的朋友可以參考下
    2016-09-09
  • Response如何實(shí)現(xiàn)重定向

    Response如何實(shí)現(xiàn)重定向

    這篇文章主要介紹了Response如何實(shí)現(xiàn)重定向方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Java泛型通配符的使用詳解

    Java泛型通配符的使用詳解

    本文主要介紹了Java泛型通配符的使用詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01

最新評(píng)論