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

SpringBoot中利用AOP和攔截器實(shí)現(xiàn)自定義注解

 更新時(shí)間:2022年06月27日 11:38:57   作者:WX7251  
本文將通過(guò)攔截器+AOP實(shí)現(xiàn)自定義注解,在這里攔截器充當(dāng)在指定注解處要執(zhí)行的方法,aop負(fù)責(zé)將攔截器的方法和要注解生效的地方做一個(gè)織入,感興趣的可以嘗試一下

前言

最近遇到了這樣一個(gè)工作場(chǎng)景,需要寫一批dubbo接口,再將dubbo接口注冊(cè)到網(wǎng)關(guān)中,但是當(dāng)dubbo接口異常的時(shí)候會(huì)給前端返回非常不友好的異常。所以就想要對(duì)異常進(jìn)行統(tǒng)一捕獲處理,但是對(duì)于這種service接口使用@ExceptionHandler注解進(jìn)行異常捕獲也是捕獲不到的,應(yīng)為他不是Controller的接口。這時(shí)就想到了自定義一個(gè)注解去實(shí)現(xiàn)異常捕獲的功能。

Spring實(shí)現(xiàn)自定義注解

通過(guò)攔截器+AOP實(shí)現(xiàn)自定義注解的實(shí)現(xiàn),在這里攔截器充當(dāng)在指定注解處要執(zhí)行的方法,aop負(fù)責(zé)將攔截器的方法和要注解生效的地方做一個(gè)織入(通過(guò)動(dòng)態(tài)注解生成代理類實(shí)現(xiàn))。

1.引入相關(guān)依賴

spring-boot-starter:spring的一些核心基礎(chǔ)依賴

spring-boot-starter-aop:spring實(shí)現(xiàn)Aop的一些相關(guān)依賴

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

2.相關(guān)類

1.自定義注解類

@Target({ElementType.TYPE})  //說(shuō)明了Annotation所修飾的對(duì)象范圍,這里,的作用范圍是類、接口(包括注解類型) 或enum
@Retention(RetentionPolicy.RUNTIME)  //自定義注解的有效期,Runtime:注解不僅被保存到class文件中,jvm加載class文件之后,仍然存在
@Documented //標(biāo)注生成javadoc的時(shí)候是否會(huì)被記錄
public @interface EasyExceptionResult {
}

2.攔截器類

/**
 * MethodInterceptor是AOP項(xiàng)目中的攔截器(注:不是動(dòng)態(tài)代理攔截器),
 * 區(qū)別與HandlerInterceptor攔截目標(biāo)時(shí)請(qǐng)求,它攔截的目標(biāo)是方法。
 */
public class EasyExceptionIntercepter implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        AnnotatedElement element=invocation.getThis().getClass();
        EasyExceptionResult easyExceptionResult=element.getAnnotation(EasyExceptionResult.class);
        if (easyExceptionResult == null) {
            return invocation.proceed();
        }
        try {
            return invocation.proceed();
        } catch (Exception rpcException) {
            //不同環(huán)境下的一個(gè)異常處理
            System.out.println("發(fā)生異常了");
            return null;
        }
    }
}

3.切點(diǎn)切面類

MethodInterceptor的實(shí)現(xiàn)類能作為切面的執(zhí)行方式是應(yīng)為Interceptor的父類是Advice。

@Configuration
public class EasyExceptionAdvisor {
 
    /**
     * 放在最后執(zhí)行
     * 等待ump/日志等記錄結(jié)束
     *
     * @return {@link DefaultPointcutAdvisor}對(duì)象
     */
    @Bean
    @Order(Integer.MIN_VALUE)
    public DefaultPointcutAdvisor easyExceptionResultAdvisor() {
        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
        //針對(duì)EasyExceptionResult注解創(chuàng)建切點(diǎn)
        AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(EasyExceptionResult.class, true);
        EasyExceptionIntercepter interceptor = new EasyExceptionIntercepter();
        advisor.setPointcut(annotationMatchingPointcut);
        //在切點(diǎn)執(zhí)行interceptor中的invoke方法
        advisor.setAdvice(interceptor);
        return advisor;
    }
 
}

4.自定義注解的使用

@Service
@EasyExceptionResult  //自定義異常捕獲注解
public class EasyServiceImpl {
 
    public void testEasyResult(){
        throw new NullPointerException("測(cè)試自定義注解");
    }
 
}

5.效果

@SpringBootApplication
public class JdStudyApplication {
 
    public static void main(String[] args) {
        ConfigurableApplicationContext context=SpringApplication.run(JdStudyApplication.class, args);
        EasyServiceImpl easyService=context.getBean(EasyServiceImpl.class);
        easyService.testEasyResult();
    }
 
}

至此就實(shí)現(xiàn)了通過(guò)spring實(shí)現(xiàn)自定義注解。

Java實(shí)現(xiàn)自定義注解

雖然通過(guò)Spring實(shí)現(xiàn)了自定義注解但是還有辦法讓我們不通過(guò)Spring也能實(shí)現(xiàn)自定義注解,畢竟注解是早于Spring的。

JDK中有一些元注解,主要有@Target,@Retention,@Document,@Inherited用來(lái)修飾注解,如下為一個(gè)自定義注解。

@Target({ElementType.TYPE})  //說(shuō)明了Annotation所修飾的對(duì)象范圍,這里,的作用范圍是類、接口(包括注解類型) 或enum
@Retention(RetentionPolicy.RUNTIME)  //自定義注解的有效期,Runtime:注解不僅被保存到class文件中,jvm加載class文件之后,仍然存在
@Documented //標(biāo)注生成javadoc的時(shí)候是否會(huì)被記錄
public @interface EasyExceptionResult {
}

@Target

表明該注解可以應(yīng)用的java元素類型

Target類型描述
ElementType.TYPE應(yīng)用于類、接口(包括注解類型)、枚舉
ElementType.FIELD應(yīng)用于屬性(包括枚舉中的常量)
ElementType.METHOD應(yīng)用于方法
ElementType.PARAMETER應(yīng)用于方法的形參
ElementType.CONSTRUCTOR應(yīng)用于構(gòu)造函數(shù)
ElementType.LOCAL_VARIABLE應(yīng)用于局部變量
ElementType.ANNOTATION_TYPE應(yīng)用于注解類型
ElementType.PACKAGE應(yīng)用于包
ElementType.TYPE_PARAMETER1.8版本新增,應(yīng)用于類型變量)
ElementType.TYPE_USE1.8版本新增,應(yīng)用于任何使用類型的語(yǔ)句中(例如聲明語(yǔ)句、泛型和強(qiáng)制轉(zhuǎn)換語(yǔ)句中的類型)

@Retention

表明該注解的生命周期

生命周期類型描述
RetentionPolicy.SOURCE編譯時(shí)被丟棄,不包含在類文件中
RetentionPolicy.CLASSJVM加載時(shí)被丟棄,包含在類文件中,默認(rèn)值
RetentionPolicy.RUNTIME由JVM 加載,包含在類文件中,在運(yùn)行時(shí)可以被獲取到

@Document

表明該注解標(biāo)記的元素可以被Javadoc 或類似的工具文檔化

@Inherited

表明使用了@Inherited注解的注解,所標(biāo)記的類的子類也會(huì)擁有這個(gè)注解

通過(guò)Cglib實(shí)現(xiàn)

在我們定義好注解之后就需要考慮如何將注解和類綁定到一起,在運(yùn)行期間達(dá)到我們想要的效果,這里就可以引入動(dòng)態(tài)代理的機(jī)制,將注解想要做的操作在方法執(zhí)行前,類編譯時(shí)就進(jìn)行一個(gè)織入的操作如下。  

public static void main(String[] args) {
        Class easyServiceImplClass=EasyServiceImpl.class;
        //判斷該對(duì)象是否有我們自定義的@EasyExceptionResult注解
        if(easyServiceImplClass.isAnnotationPresent(EasyExceptionResult.class)){
            final EasyServiceImpl easyService=new EasyServiceImpl();
            //cglib的字節(jié)碼加強(qiáng)器
            Enhancer enhancer=new Enhancer();
            將目標(biāo)對(duì)象所在的類作為Enhaner類的父類
            enhancer.setSuperclass(EasyServiceImpl.class);
            通過(guò)實(shí)現(xiàn)MethodInterceptor實(shí)現(xiàn)方法回調(diào),MethodInterceptor繼承了Callback
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    try{
                        method.invoke(easyService, args);
                        System.out.println("事務(wù)結(jié)束...");
                    }catch (Exception e){
                        System.out.println("發(fā)生異常了");
                    }
                    return proxy;
                }
            });
 
            Object obj= enhancer.create();;
            EasyServiceImpl easyServiceProxy=(EasyServiceImpl)obj;
            easyServiceProxy.testEasyResult();
        }
 
    }

運(yùn)行效果:

通過(guò)JDk動(dòng)態(tài)代理實(shí)現(xiàn)

public class EasyServiceImplProxy implements InvocationHandler {
 
    private EasyServiceImpl target;
 
    public void setTarget(EasyServiceImpl target)
    {
        this.target = target;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 這里可以做增強(qiáng)
        System.out.println("已經(jīng)是代理類啦");
        try{
            return  method.invoke(proxy, args);
        }catch (Exception e){
            System.out.println("發(fā)生異常了");
            return null;
        }
    }
 
 
    /**
     * 生成代理類
     * @return 代理類
     */
    public Object CreatProxyedObj()
    {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

Cglib和JDK動(dòng)態(tài)代理的區(qū)別

java動(dòng)態(tài)代理是利用反射機(jī)制生成一個(gè)實(shí)現(xiàn)代理接口的匿名類,在調(diào)用具體方法前調(diào)用InvokeHandler來(lái)處理。

而cglib動(dòng)態(tài)代理是利用asm開源包,對(duì)代理對(duì)象類的class文件加載進(jìn)來(lái),通過(guò)修改其字節(jié)碼生成子類來(lái)處理。

1、如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,默認(rèn)情況下會(huì)采用JDK的動(dòng)態(tài)代理實(shí)現(xiàn)AOP 

2、如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,可以強(qiáng)制使用CGLIB實(shí)現(xiàn)AOP 

3、如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)了接口,必須采用CGLIB庫(kù),spring會(huì)自動(dòng)在JDK動(dòng)態(tài)代理和CGLIB之間轉(zhuǎn)換

如何強(qiáng)制使用CGLIB實(shí)現(xiàn)AOP?

(1)添加CGLIB庫(kù),SPRING_HOME/cglib/*.jar

(2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

JDK動(dòng)態(tài)代理和CGLIB字節(jié)碼生成的區(qū)別?

(1)JDK動(dòng)態(tài)代理只能對(duì)實(shí)現(xiàn)了接口的類生成代理,而不能針對(duì)類

(2)CGLIB是針對(duì)類實(shí)現(xiàn)代理,主要是對(duì)指定的類生成一個(gè)子類,覆蓋其中的方法

因?yàn)槭抢^承,所以該類或方法最好不要聲明成final 

寫在最后

@ExceptionHandler注解的使用可參考文章Java實(shí)現(xiàn)優(yōu)雅的參數(shù)校驗(yàn)方法詳解

到此這篇關(guān)于SpringBoot中利用AOP和攔截器實(shí)現(xiàn)自定義注解的文章就介紹到這了,更多相關(guān)SpringBoot自定義注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA MyBatis Plugins自動(dòng)生成實(shí)體類和mapper.xml

    IDEA MyBatis Plugins自動(dòng)生成實(shí)體類和mapper.xml

    這篇文章主要介紹了IDEA MyBatis Plugins自動(dòng)生成實(shí)體類和mapper.xml,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • springboot接收J(rèn)SON實(shí)現(xiàn)示例解析

    springboot接收J(rèn)SON實(shí)現(xiàn)示例解析

    這篇文章主要為大家介紹了springboot如何接收J(rèn)SON的實(shí)現(xiàn)示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 詳解Java實(shí)現(xiàn)批量壓縮圖片裁剪壓縮多種尺寸縮略圖一鍵批量上傳圖片

    詳解Java實(shí)現(xiàn)批量壓縮圖片裁剪壓縮多種尺寸縮略圖一鍵批量上傳圖片

    這篇文章主要介紹了Java實(shí)現(xiàn)批量壓縮圖片裁剪壓縮多種尺寸縮略圖一鍵批量上傳圖片,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • 詳解java 對(duì)象鎖與類鎖

    詳解java 對(duì)象鎖與類鎖

    這篇文章主要介紹了java 對(duì)象鎖與類鎖的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-09-09
  • 教你1秒將本地SpringBoot項(xiàng)目jar包部署到Linux環(huán)境(超詳細(xì)!)

    教你1秒將本地SpringBoot項(xiàng)目jar包部署到Linux環(huán)境(超詳細(xì)!)

    spring Boot簡(jiǎn)化了Spring應(yīng)用的開發(fā)過(guò)程,遵循約定優(yōu)先配置的原則提供了各類開箱即用(out-of-the-box)的框架配置,下面這篇文章主要給大家介紹了關(guān)于1秒將本地SpringBoot項(xiàng)目jar包部署到Linux環(huán)境的相關(guān)資料,超級(jí)詳細(xì),需要的朋友可以參考下
    2023-04-04
  • Java String類詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java String類詳解_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了Java String類詳解,本文經(jīng)多方資料的收集整理和歸納,最終撰寫成文,非常不錯(cuò),值得收藏,需要的的朋友參考下
    2017-04-04
  • 詳解如何在spring boot中使用spring security防止CSRF攻擊

    詳解如何在spring boot中使用spring security防止CSRF攻擊

    這篇文章主要介紹了詳解如何在spring boot中使用spring security防止CSRF攻擊,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • 自定義BufferedReader的實(shí)例

    自定義BufferedReader的實(shí)例

    下面小編就為大家分享一篇自定義BufferedReader的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • Java后端實(shí)現(xiàn)MD5加密的方法

    Java后端實(shí)現(xiàn)MD5加密的方法

    有的時(shí)候因?yàn)闃I(yè)務(wù)的需要,我們要制作關(guān)于密碼的修改功能。而關(guān)于密碼的加密一般都是用MD5,那么這篇文章將介紹如何在Java的后端實(shí)現(xiàn)MD5加密,有需要的可以參考借鑒。
    2016-08-08
  • SpringBoot后端進(jìn)行數(shù)據(jù)校驗(yàn)JSR303的使用詳解

    SpringBoot后端進(jìn)行數(shù)據(jù)校驗(yàn)JSR303的使用詳解

    這篇文章主要介紹了SpringBoot后端進(jìn)行數(shù)據(jù)校驗(yàn)JSR303的使用詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03

最新評(píng)論

温泉县| 台州市| 长葛市| 巫山县| 桐乡市| 静安区| 肇东市| 大关县| 天等县| 达孜县| 昭苏县| 泊头市| 石楼县| 吴桥县| 富锦市| 桐柏县| 沐川县| 马关县| 改则县| 横山县| 银川市| 星座| 大理市| 开封市| 长乐市| 章丘市| 江山市| 青浦区| 玉树县| 思茅市| 调兵山市| 沈阳市| 泸西县| 海城市| 双流县| 安达市| 永州市| 丰原市| 九龙坡区| 余庆县| 密云县|