SpringBoot中怎么利用AOP和拦截器实现自定义注解
导读:本文共4793字符,通常情况下阅读需要16分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: Spring实现自定义注解通过拦截器+AOP实现自定义注解的实现,在这里拦截器充当在指定注解处要执行的方法,aop负责将拦截器的方法和要注解生效的地方做一个织入(通过动态注解生成代理类实现)。1.引入相关依赖spring-boot-starter:spring的一些核心基础依赖spring-boot-starter-aop:spring实现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@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();}}
至此就实现了通过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元素类型
@Retention
表明该注解的生命周期
@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();}}
运行效果:
通过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和拦截器实现自定义注解的详细内容,希望对您有所帮助,信息来源于网络。