最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2024年01月10日 10:38:13   作者:苦糖果與忍冬  
這篇文章主要介紹了SpringAop自定義切面注解、自定義過濾器及ThreadLocal詳解,Aspect(切面)通常是一個類,里面可以定義切入點(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ù)模式稍微復(fù)雜一些:

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

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

二、實(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

如果取消包裝的話,就會直接報錯

{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)文章

  • Java線程通信及線程虛假喚醒知識總結(jié)

    Java線程通信及線程虛假喚醒知識總結(jié)

    今天給大家?guī)淼氖顷P(guān)于Java線程的相關(guān)知識,文章圍繞著Java線程通信及線程虛假喚醒的知識展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • MyBatisPlus中@TableField注解的基本使用

    MyBatisPlus中@TableField注解的基本使用

    這篇文章主要介紹了MyBatisPlus中@TableField注解的基本使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • SpringBoot Admin的簡單使用的方法步驟

    SpringBoot Admin的簡單使用的方法步驟

    本文主要介紹了SpringBoot Admin的簡單使用的方法步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • JavaMail實(shí)現(xiàn)郵件發(fā)送的方法

    JavaMail實(shí)現(xiàn)郵件發(fā)送的方法

    這篇文章主要介紹了JavaMail實(shí)現(xiàn)郵件發(fā)送的方法,實(shí)例分析了java實(shí)現(xiàn)郵件發(fā)送的相關(guān)技巧,非常具有實(shí)用價值,需要的朋友可以參考下
    2015-04-04
  • 使用Java visualVM監(jiān)控遠(yuǎn)程JVM的流程分析

    使用Java visualVM監(jiān)控遠(yuǎn)程JVM的流程分析

    我們經(jīng)常需要對我們的開發(fā)的軟件做各種測試, 軟件對系統(tǒng)資源的使用情況更是不可少,JDK1.6開始自帶的VisualVM就是不錯的監(jiān)控工具,本文給大家分享使用Java visualVM監(jiān)控遠(yuǎn)程JVM的問題,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • Java數(shù)據(jù)結(jié)構(gòu)及算法實(shí)例:快速計算二進(jìn)制數(shù)中1的個數(shù)(Fast Bit Counting)

    Java數(shù)據(jù)結(jié)構(gòu)及算法實(shí)例:快速計算二進(jìn)制數(shù)中1的個數(shù)(Fast Bit Counting)

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)及算法實(shí)例:快速計算二進(jìn)制數(shù)中1的個數(shù)(Fast Bit Counting),本文直接給出實(shí)現(xiàn)代碼,代碼中包含詳細(xì)注釋,需要的朋友可以參考下
    2015-06-06
  • Springboot整合多數(shù)據(jù)源代碼示例詳解

    Springboot整合多數(shù)據(jù)源代碼示例詳解

    這篇文章主要介紹了Springboot整合多數(shù)據(jù)源代碼示例詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-08-08
  • 淺聊一下Java中的鎖機(jī)制

    淺聊一下Java中的鎖機(jī)制

    Java中的鎖機(jī)制是保證多線程并發(fā)訪問共享資源安全性的重要手段之一。Java提供了兩種類型的鎖機(jī)制:synchronized關(guān)鍵字和Lock接口。本文將介紹這兩種鎖機(jī)制的原理及使用方法,并通過代碼示例講解它們的使用
    2023-03-03
  • Java中json處理工具JsonPath的使用教程

    Java中json處理工具JsonPath的使用教程

    JsonPath類似于XPath,是一種json數(shù)據(jù)結(jié)構(gòu)節(jié)點(diǎn)定位和導(dǎo)航表達(dá)式語言,這篇文章主要為大家介紹了JsonPath的基本使用,需要的小伙伴可以參考下
    2023-08-08
  • SpringBoot整合MD5加密完成注冊和登錄方式

    SpringBoot整合MD5加密完成注冊和登錄方式

    MD5(MessageDigestAlgorithm5)是一種常見的哈希算法,用于生成固定長度(128位)的哈希值,主要應(yīng)用于數(shù)據(jù)完整性校驗(yàn)和密碼存儲,MD5具有快速計算、不可逆性和抗碰撞性等特點(diǎn),盡管存在碰撞漏洞,MD5仍廣泛應(yīng)用于文件下載校驗(yàn)和數(shù)字簽名等場景
    2024-10-10

最新評論

岳阳县| 双柏县| 桐庐县| 隆昌县| 胶州市| 抚松县| 高雄县| 成都市| 重庆市| 郸城县| 泸西县| 舞阳县| 溧水县| 龙江县| 临漳县| 攀枝花市| 梁山县| 通辽市| 娱乐| 东光县| 丰城市| 修文县| 兴仁县| 平顶山市| 新安县| 东兴市| 华宁县| 青神县| 和田县| 南充市| 苏尼特右旗| 白朗县| 周至县| 临清市| 东辽县| 班戈县| 大丰市| 四会市| 临颍县| 乌鲁木齐县| 博客|