搜索
首页Javajava教程SpringBoot中怎么利用AOP和拦截器实现自定义注解

    Spring实现自定义注解

    通过拦截器+AOP实现自定义注解的实现,在这里拦截器充当在指定注解处要执行的方法,aop负责将拦截器的方法和要注解生效的地方做一个织入(通过动态注解生成代理类实现)。

    1.引入相关依赖

    spring-boot-starter:spring的一些核心基础依赖

    spring-boot-starter-aop:spring实现Aop的一些相关依赖

            <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.相关类

    1.自定义注解类

    @Target({ElementType.TYPE})  //说明了Annotation所修饰的对象范围,这里,的作用范围是类、接口(包括注解类型) 或enum
    @Retention(RetentionPolicy.RUNTIME)  //自定义注解的有效期,Runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
    @Documented //标注生成javadoc的时候是否会被记录
    public @interface EasyExceptionResult {
    }

    2.拦截器类

    /**
     * MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器),
     * 区别与HandlerInterceptor拦截目标时请求,它拦截的目标是方法。
     */
    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) {
                //不同环境下的一个异常处理
                System.out.println("发生异常了");
                return null;
            }
        }
    }

    3.切点切面类

    MethodInterceptor的实现类能作为切面的执行方式是应为Interceptor的父类是Advice。

    @Configuration
    public class EasyExceptionAdvisor {
     
        /**
         * 放在最后执行
         * 等待ump/日志等记录结束
         *
         * @return {@link DefaultPointcutAdvisor}对象
         */
        @Bean
        @Order(Integer.MIN_VALUE)
        public DefaultPointcutAdvisor easyExceptionResultAdvisor() {
            DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
            //针对EasyExceptionResult注解创建切点
            AnnotationMatchingPointcut annotationMatchingPointcut = new AnnotationMatchingPointcut(EasyExceptionResult.class, true);
            EasyExceptionIntercepter interceptor = new EasyExceptionIntercepter();
            advisor.setPointcut(annotationMatchingPointcut);
            //在切点执行interceptor中的invoke方法
            advisor.setAdvice(interceptor);
            return advisor;
        }
     
    }

    4.自定义注解的使用

    @Service
    @EasyExceptionResult  //自定义异常捕获注解
    public class EasyServiceImpl {
     
        public void testEasyResult(){
            throw new NullPointerException("测试自定义注解");
        }
     
    }

    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();
        }
     
    }

    SpringBoot中怎么利用AOP和拦截器实现自定义注解

    至此就实现了通过spring实现自定义注解。

    Java实现自定义注解

    虽然通过Spring实现了自定义注解但是还有办法让我们不通过Spring也能实现自定义注解,毕竟注解是早于Spring的。

    JDK中有一些元注解,主要有@Target,@Retention,@Document,@Inherited用来修饰注解,如下为一个自定义注解。

    @Target({ElementType.TYPE})  //说明了Annotation所修饰的对象范围,这里,的作用范围是类、接口(包括注解类型) 或enum
    @Retention(RetentionPolicy.RUNTIME)  //自定义注解的有效期,Runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在
    @Documented //标注生成javadoc的时候是否会被记录
    public @interface EasyExceptionResult {
    }

    @Target

    表明该注解可以应用的java元素类型

    Target类型 描述
    ElementType.TYPE 应用于类、接口(包括注解类型)、枚举
    ElementType.FIELD 应用于属性(包括枚举中的常量)
    ElementType.METHOD 应用于方法
    ElementType.PARAMETER 应用于方法的形参
    ElementType.CONSTRUCTOR 应用于构造函数
    ElementType.LOCAL_VARIABLE 应用于局部变量
    ElementType.ANNOTATION_TYPE 应用于注解类型
    ElementType.PACKAGE 应用于包
    ElementType.TYPE_PARAMETER 1.8版本新增,应用于类型变量)
    ElementType.TYPE_USE 1.8版本新增,应用于任何使用类型的语句中(例如声明语句、泛型和强制转换语句中的类型)

    @Retention

    表明该注解的生命周期

    生命周期类型 描述
    RetentionPolicy.SOURCE 编译时被丢弃,不包含在类文件中
    RetentionPolicy.CLASS JVM加载时被丢弃,包含在类文件中,默认值
    RetentionPolicy.RUNTIME 由JVM 加载,包含在类文件中,在运行时可以被获取到

    @Document

    表明该注解标记的元素可以被Javadoc 或类似的工具文档化

    @Inherited

    表明使用了@Inherited注解的注解,所标记的类的子类也会拥有这个注解

    通过Cglib实现

    在我们定义好注解之后就需要考虑如何将注解和类绑定到一起,在运行期间达到我们想要的效果,这里就可以引入动态代理的机制,将注解想要做的操作在方法执行前,类编译时就进行一个织入的操作如下。  

    public static void main(String[] args) {
            Class easyServiceImplClass=EasyServiceImpl.class;
            //判断该对象是否有我们自定义的@EasyExceptionResult注解
            if(easyServiceImplClass.isAnnotationPresent(EasyExceptionResult.class)){
                final EasyServiceImpl easyService=new EasyServiceImpl();
                //cglib的字节码加强器
                Enhancer enhancer=new Enhancer();
                将目标对象所在的类作为Enhaner类的父类
                enhancer.setSuperclass(EasyServiceImpl.class);
                通过实现MethodInterceptor实现方法回调,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("事务结束...");
                        }catch (Exception e){
                            System.out.println("发生异常了");
                        }
                        return proxy;
                    }
                });
     
                Object obj= enhancer.create();;
                EasyServiceImpl easyServiceProxy=(EasyServiceImpl)obj;
                easyServiceProxy.testEasyResult();
            }
     
        }

    运行效果:

    SpringBoot中怎么利用AOP和拦截器实现自定义注解

    通过JDk动态代理实现

    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 {
            // 这里可以做增强
            System.out.println("已经是代理类啦");
            try{
                return  method.invoke(proxy, args);
            }catch (Exception e){
                System.out.println("发生异常了");
                return null;
            }
        }
     
     
        /**
         * 生成代理类
         * @return 代理类
         */
        public Object CreatProxyedObj()
        {
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        }
    }

    Cglib和JDK动态代理的区别

    java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

    而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

    1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 

    2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP 

    3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

    如何强制使用CGLIB实现AOP?

    (1)添加CGLIB库,SPRING_HOME/cglib/*.jar

    (2)在spring配置文件中加入9126954461102e7e6f4001917512b798

    JDK动态代理和CGLIB字节码生成的区别?

    (1)JDK动态代理只能对实现了接口的类生成代理,而不能针对类

    (2)CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法

    因为是继承,所以该类或方法最好不要声明成final 

    以上是SpringBoot中怎么利用AOP和拦截器实现自定义注解的详细内容。更多信息请关注PHP中文网其他相关文章!

    声明
    本文转载于:亿速云。如有侵权,请联系admin@php.cn删除
    怎么使用SpringBoot+Canal实现数据库实时监控怎么使用SpringBoot+Canal实现数据库实时监控May 10, 2023 pm 06:25 PM

    Canal工作原理Canal模拟MySQLslave的交互协议,伪装自己为MySQLslave,向MySQLmaster发送dump协议MySQLmaster收到dump请求,开始推送binarylog给slave(也就是Canal)Canal解析binarylog对象(原始为byte流)MySQL打开binlog模式在MySQL配置文件my.cnf设置如下信息:[mysqld]#打开binloglog-bin=mysql-bin#选择ROW(行)模式binlog-format=ROW#配置My

    Spring Boot怎么使用SSE方式向前端推送数据Spring Boot怎么使用SSE方式向前端推送数据May 10, 2023 pm 05:31 PM

    前言SSE简单的来说就是服务器主动向前端推送数据的一种技术,它是单向的,也就是说前端是不能向服务器发送数据的。SSE适用于消息推送,监控等只需要服务器推送数据的场景中,下面是使用SpringBoot来实现一个简单的模拟向前端推动进度数据,前端页面接受后展示进度条。服务端在SpringBoot中使用时需要注意,最好使用SpringWeb提供的SseEmitter这个类来进行操作,我在刚开始时使用网上说的将Content-Type设置为text-stream这种方式发现每次前端每次都会重新创建接。最

    SpringBoot怎么实现二维码扫码登录SpringBoot怎么实现二维码扫码登录May 10, 2023 pm 08:25 PM

    一、手机扫二维码登录的原理二维码扫码登录是一种基于OAuth3.0协议的授权登录方式。在这种方式下,应用程序不需要获取用户的用户名和密码,只需要获取用户的授权即可。二维码扫码登录主要有以下几个步骤:应用程序生成一个二维码,并将该二维码展示给用户。用户使用扫码工具扫描该二维码,并在授权页面中授权。用户授权后,应用程序会获取一个授权码。应用程序使用该授权码向授权服务器请求访问令牌。授权服务器返回一个访问令牌给应用程序。应用程序使用该访问令牌访问资源服务器。通过以上步骤,二维码扫码登录可以实现用户的快

    SpringBoot/Spring AOP默认动态代理方式是什么SpringBoot/Spring AOP默认动态代理方式是什么May 10, 2023 pm 03:52 PM

    1.springboot2.x及以上版本在SpringBoot2.xAOP中会默认使用Cglib来实现,但是Spring5中默认还是使用jdk动态代理。SpringAOP默认使用JDK动态代理,如果对象没有实现接口,则使用CGLIB代理。当然,也可以强制使用CGLIB代理。在SpringBoot中,通过AopAutoConfiguration来自动装配AOP.2.Springboot1.xSpringboot1.xAOP默认还是使用JDK动态代理的3.SpringBoot2.x为何默认使用Cgl

    spring boot怎么对敏感信息进行加解密spring boot怎么对敏感信息进行加解密May 10, 2023 pm 02:46 PM

    我们使用jasypt最新版本对敏感信息进行加解密。1.在项目pom文件中加入如下依赖:com.github.ulisesbocchiojasypt-spring-boot-starter3.0.32.创建加解密公用类:packagecom.myproject.common.utils;importorg.jasypt.encryption.pbe.PooledPBEStringEncryptor;importorg.jasypt.encryption.pbe.config.SimpleStrin

    使用Java SpringBoot集成POI实现Word文档导出使用Java SpringBoot集成POI实现Word文档导出Apr 21, 2023 pm 12:19 PM

    知识准备需要理解ApachePOI遵循的标准(OfficeOpenXML(OOXML)标准和微软的OLE2复合文档格式(OLE2)),这将对应着API的依赖包。什么是POIApachePOI是用Java编写的免费开源的跨平台的JavaAPI,ApachePOI提供API给Java程序对MicrosoftOffice格式档案读和写的功能。POI为“PoorObfuscationImplementation”的首字母缩写,意为“简洁版的模糊实现”。ApachePOI是创建和维护操作各种符合Offic

    springboot怎么整合shiro实现多验证登录功能springboot怎么整合shiro实现多验证登录功能May 10, 2023 pm 04:19 PM

    1.首先新建一个shiroConfigshiro的配置类,代码如下:@ConfigurationpublicclassSpringShiroConfig{/***@paramrealms这儿使用接口集合是为了实现多验证登录时使用的*@return*/@BeanpublicSecurityManagersecurityManager(Collectionrealms){DefaultWebSecurityManagersManager=newDefaultWebSecurityManager();

    Springboot如何实现视频上传及压缩功能Springboot如何实现视频上传及压缩功能May 10, 2023 pm 05:16 PM

    一、定义视频上传请求接口publicAjaxResultvideoUploadFile(MultipartFilefile){try{if(null==file||file.isEmpty()){returnAjaxResult.error("文件为空");}StringossFilePrefix=StringUtils.genUUID();StringfileName=ossFilePrefix+"-"+file.getOriginalFilename(

    See all articles

    热AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智能驱动的应用程序,用于创建逼真的裸体照片

    AI Clothes Remover

    AI Clothes Remover

    用于从照片中去除衣服的在线人工智能工具。

    Undress AI Tool

    Undress AI Tool

    免费脱衣服图片

    Clothoff.io

    Clothoff.io

    AI脱衣机

    AI Hentai Generator

    AI Hentai Generator

    免费生成ai无尽的。

    热门文章

    R.E.P.O.能量晶体解释及其做什么(黄色晶体)
    2 周前By尊渡假赌尊渡假赌尊渡假赌
    仓库:如何复兴队友
    1 个月前By尊渡假赌尊渡假赌尊渡假赌
    Hello Kitty Island冒险:如何获得巨型种子
    4 周前By尊渡假赌尊渡假赌尊渡假赌

    热工具

    Dreamweaver CS6

    Dreamweaver CS6

    视觉化网页开发工具

    禅工作室 13.0.1

    禅工作室 13.0.1

    功能强大的PHP集成开发环境

    EditPlus 中文破解版

    EditPlus 中文破解版

    体积小,语法高亮,不支持代码提示功能

    SublimeText3 英文版

    SublimeText3 英文版

    推荐:为Win版本,支持代码提示!

    ZendStudio 13.5.1 Mac

    ZendStudio 13.5.1 Mac

    功能强大的PHP集成开发环境