Java自定义注解一般使用场景:自定义注解+拦截器或者AOP,使用自定义注解自己设计框架,让代码看起来很优雅。本文将从自定义注解的基本概念入手,然后开始实战,写一小段代码实现自定义注解+拦截器,自定义注解+AOP。一、什么是注解(Annotation)什么是Java注解?Java语言中的类、方法、变量、参数、包都可以被标记。与Javadoc不同,Java注解可以通过反射获取注解内容。当编译器生成类文件时,可以在字节码中嵌入注释。Java虚拟机可以保留注解内容,注解内容可以在运行时获取。当然它也支持自定义Java注解。2、注解系统元注解:java.lang.annotation提供了元注解,你可以使用这些注解来定义自己的注解。主要用到Target和Retention注解的注解处理类:既然上面定义了注解,那肯定有办法获取到我们定义的注解。java.lang.reflect.AnnotationElement接口提供了这个功能。注解处理是通过java反射来处理的。如下,反射相关的类Class、Method、Field都实现了AnnotationElement接口。因此,我们只要通过反射获取Class、Method、Field类,就可以通过getAnnotation(Class)获取到我们想要的注解,获取值。搜索Java知音公众号,回复“后端面试”,送你Java面试题集3.常用元注解对象:描述注解修饰对象的范围。其中:METHOD:用于描述方法PACKAGE:用于描述封装PARAMETER:用于描述方法变量TYPE:用于描述类、接口或枚举类型Retention:表示注解的保留时间。该值在java.lang.annotation.RetentionPolicy中,取值为:SOURCE:在源文件中有效,编译时会被忽略CLASS:在class文件中用源文件编译,运行时忽略RUNTIME:运行时Valid只有定义为RetentionPolicy.RUNTIME时,我们才能通过注解反射获取注解。那么,假设我们要自定义一个注解,用在字段上,可以通过反射获取。功能是描述字段的长度和功能。@Target(ElementType.FIELD)//在字段上使用注解@Retention(RetentionPolicy.RUNTIME)//保留到运行时,public@interfaceMyField{Stringdescription();intlength();}可以通过注解获取4.Example-反射获取注解,首先定义一个注解:@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public@interfaceMyField{Stringdescription();intlength();}通过反射获取注解publicclassMyFieldTest{//使用我们自定义的注解@MyField(description="username",length=12)privateStringusername;@TestpublicvoidtestMyField(){//获取类模板Classc=MyFieldTest.class;//获取所有字段for(Fieldf:c.getDeclaredFields()){//判断这个字段是否有MyField注解description:["+annotation.description()+"],length:["+annotation.length()+"]");}}}}运行结果应用场景一:自定义annotation+拦截器实现登录验证接口接下来我们使用springboot拦截器来实现这样一个功能。如果在方法中添加@LoginRequired,则提示用户需要登录才能访问界面,否则不需要登录。先定义一个LoginRequired注解@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceLoginRequired{}然后写两个简单的接口访问sourceA,sourceB资源@RestControllerpublicclassIndexController{@GetMapping("/sourceA")publicStringsourceA(){return"YouareaccessingsourceAresource";}@GetMapping("/sourceB")publicStringsourceB(){return"YouareaccessingsourceBresource";}}添加拦截器前成功访问实现spring的HandlerInterceptor类。Implementinterceptionfirst器,但不拦截,只是简单打印日志,如下:publicclassSourceAccessInterceptorimplementsHandlerInterceptor{@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{System.out.println("进入拦截器了");returntrue;}@OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{}@OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{}}实现spring类WebMvcConfigurer,创建构建配置类,将拦截器添加到拦截器链@ConfigurationpublicclassInterceptorTrainConfigurerimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(newSourceAccessInterceptor()).addPathPatterns("/**");}}拦截成功如下添加我们sourceB方法登录注解@LoginRequired@RestControllerpublicclassIndexController{@GetMapping("/sourceA")publicStringsourceA(){return"你正在访问sourceA资源";}@LoginRequired@GetMapping("/sourceB")publicStringsourceB(){return"你areaccessingsourceBResources";}}登录拦截逻辑的简单实现@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{System.out.println("进入拦截器");//反射获取方法LoginRequred注解HandlerMethodhandlerMethod=(HandlerMethod)处理程序;LoginRequiredloginRequired=handlerMethod.getMethod().getAnnotation(LoginRequired.class);if(loginRequired==null){returntrue;}//有一个LoginRequired注解表示需要登录,提示用户登录response.setContentType("application/json;charset=utf-8");response.getWriter().print("Youneedtologintoaccesstheresources");returnfalse;}操作成功,访问sourceB时需要登录,并且访问sourceA不需要登录应用场景二:自定义注解+AOP实现日志打印首先导入切面需要的依赖包org.springframework.bootspring-boot-starter-aop定义一个注解@MyLog@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceMyLog{}定义一个切面类,见下文代码注解理解:@Aspect//1.表示这是一个切面类@ComponentpublicclassMyLogAspect{//2.PointCut表示这是一个切点,@annotation表示这个切点切到一个注解,后面是fullclassnameofannotation//切入点最重要的是切入点,所有的故事都围绕着切点周围//logPointCut()表示切点名称@Pointcut("@annotation(me.zebin.demo.annotationdemo.aoplog.MyLog)")publicvoidlogPointCut(){};//3.环绕通知@Around("logPointCut()")publicvoidlogAround(ProceedingJoinPointjoinPoint){//获取方法名StringmethodName=joinPoint.getSignature().getName();//获取入参Object[]param=joinPoint.getArgs();StringBuildersb=newStringBuilder();for(Objecto:param){sb.append(o+";"t;);}System.out.println("进入["+methodName+"]方法,参数为:"+sb.toString());//继续执行方法try{joinPoint.proceed();}catch(Throwablethrowable){throwable.printStackTrace();}System.out.println(methodName+"MethodExecutionEnd");}}在第2步的IndexController中,写一个sourceC进行测试,加上我们自定义的注解:@MyLog@GetMapping("/sourceC/{source_name}")publicStringsourceC(@PathVariable("source_name")StringsourceName){return"您正在访问sourceC资源";}启动springbootweb项目,输入访问地址