SpringBoot中怎么利用AOP和拦截器实现自定义注解(aop,springboot,开发技术)

时间:2024-05-06 05:02:02 作者 : 石家庄SEO 分类 : 开发技术
  • TAG :

    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@interfaceEasyExceptionResult{}

    2.拦截器类

    /***MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器),*区别与HandlerInterceptor拦截目标时请求,它拦截的目标是方法。*/publicclassEasyExceptionIntercepterimplementsMethodInterceptor{@OverridepublicObjectinvoke(MethodInvocationinvocation)throwsThrowable{AnnotatedElementelement=invocation.getThis().getClass();EasyExceptionResulteasyExceptionResult=element.getAnnotation(EasyExceptionResult.class);if(easyExceptionResult==null){returninvocation.proceed();}try{returninvocation.proceed();}catch(ExceptionrpcException){//不同环境下的一个异常处理System.out.println("发生异常了");returnnull;}}}

    3.切点切面类

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

    @ConfigurationpublicclassEasyExceptionAdvisor{/***放在最后执行*等待ump/日志等记录结束**@return{@linkDefaultPointcutAdvisor}对象*/@Bean@Order(Integer.MIN_VALUE)publicDefaultPointcutAdvisoreasyExceptionResultAdvisor(){DefaultPointcutAdvisoradvisor=newDefaultPointcutAdvisor();//针对EasyExceptionResult注解创建切点AnnotationMatchingPointcutannotationMatchingPointcut=newAnnotationMatchingPointcut(EasyExceptionResult.class,true);EasyExceptionIntercepterinterceptor=newEasyExceptionIntercepter();advisor.setPointcut(annotationMatchingPointcut);//在切点执行interceptor中的invoke方法advisor.setAdvice(interceptor);returnadvisor;}}

    4.自定义注解的使用

    @Service@EasyExceptionResult//自定义异常捕获注解publicclassEasyServiceImpl{publicvoidtestEasyResult(){thrownewNullPointerException("测试自定义注解");}}

    5.效果

    @SpringBootApplicationpublicclassJdStudyApplication{publicstaticvoidmain(String[]args){ConfigurableApplicationContextcontext=SpringApplication.run(JdStudyApplication.class,args);EasyServiceImpleasyService=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@interfaceEasyExceptionResult{}

    @Target

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

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

    @Retention

    表明该注解的生命周期

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

    @Document

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

    @Inherited

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

    通过Cglib实现

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

    publicstaticvoidmain(String[]args){ClasseasyServiceImplClass=EasyServiceImpl.class;//判断该对象是否有我们自定义的@EasyExceptionResult注解if(easyServiceImplClass.isAnnotationPresent(EasyExceptionResult.class)){finalEasyServiceImpleasyService=newEasyServiceImpl();//cglib的字节码加强器Enhancerenhancer=newEnhancer();将目标对象所在的类作为Enhaner类的父类enhancer.setSuperclass(EasyServiceImpl.class);通过实现MethodInterceptor实现方法回调,MethodInterceptor继承了Callbackenhancer.setCallback(newMethodInterceptor(){@OverridepublicObjectintercept(Objectproxy,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{try{method.invoke(easyService,args);System.out.println("事务结束...");}catch(Exceptione){System.out.println("发生异常了");}returnproxy;}});Objectobj=enhancer.create();;EasyServiceImpleasyServiceProxy=(EasyServiceImpl)obj;easyServiceProxy.testEasyResult();}}

    运行效果:

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

    通过JDk动态代理实现

    publicclassEasyServiceImplProxyimplementsInvocationHandler{privateEasyServiceImpltarget;publicvoidsetTarget(EasyServiceImpltarget){this.target=target;}@OverridepublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{//这里可以做增强System.out.println("已经是代理类啦");try{returnmethod.invoke(proxy,args);}catch(Exceptione){System.out.println("发生异常了");returnnull;}}/***生成代理类*@return代理类*/publicObjectCreatProxyedObj(){returnProxy.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配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

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

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

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

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

     </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
    本文:SpringBoot中怎么利用AOP和拦截器实现自定义注解的详细内容,希望对您有所帮助,信息来源于网络。
    上一篇:C#怎么对桌面应用程序自定义鼠标光标下一篇:

    7 人围观 / 0 条评论 ↓快速评论↓

    (必须)

    (必须,保密)

    阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18