Java自定义注解及使用场景

参考博客

1.常用元注解

Target:注解修饰的对象范围

  • METHOD:用于描述方法
  • PACKAGE:用于描述
  • PARAMETER:用于描述方法变量
  • TYPE:用于描述类、接口或enum类型

Retention:注解保留时间长短

  • SOURCE:在源文件中有效,编译过程中会被忽略
  • CLASS:随源文件一起编译在class文件中,运行时忽略
  • RUNTIME:在运行时有效

2.利用反射获取注解信息

@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String desc();

    int length();
}
public class Test {

    @MyAnnotation(desc = "用户名",length = 10)
    String username;

    @MyAnnotation(desc = "hello方法",length = 100)
    public void hello(String msg){
        System.out.println("hello:"+msg);
    }

    @Override
    public String toString() {
        return "Test{" +
                "username='" + username + '\'' +
                '}';
    }

    public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        Test test = new Test();
        Class<Test> clazz = Test.class;
        //获取属性上的注解
        Field field = clazz.getDeclaredField("username");
        MyAnnotation myAnnotation = field.getDeclaredAnnotation(MyAnnotation.class);
        System.out.println("myAnnotation.desc() = " + myAnnotation.desc());
        System.out.println("myAnnotation.length() = " + myAnnotation.length());
        //获取方法上的注解
        Method hello = clazz.getDeclaredMethod("hello", String.class);
        MyAnnotation myAnnotation1 = hello.getDeclaredAnnotation(MyAnnotation.class);
        System.out.println("myAnnotation1.desc() = " + myAnnotation1.desc());

    }
}

结果如下:

myAnnotation.desc() = 用户名
myAnnotation.length() = 10
myAnnotation1.desc() = hello方法

3.自定义注解+拦截器

拦截器:

public class SourceAccessInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle方法在业务处理器处理请求之前被调用");
        HandlerMethod method = (HandlerMethod) handler;
        LoginRequired loginRequired = method.getMethodAnnotation(LoginRequired.class);
        //方法上没有自定义注解
        if (loginRequired == null){
            return true;
        }
        //方法上有自定义注解
        response.setContentType("application/json;charset=utf-8");
        response.getWriter().write("你访问的资源需要先进行登录");
        response.flushBuffer();
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle方法在业务处理器处理请求执行完成后,生成视图之前执行");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion方法在DispatcherServlet完全处理完请求后被调用,可用于清理资源等");
    }
}

注册拦截器:

@Configuration
public class WebMVCConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new SourceAccessInterceptor()).addPathPatterns("/**");
    }
}

web层:

@RestController
public class LoginController {

    @LoginRequired
    @GetMapping("/a")
    public String a(){
        System.out.println("你正在访问资源A---前");
        System.out.println("a");
        System.out.println("你正在访问资源A---后");
        return "你正在访问资源A";
    }
    @GetMapping("/b")
    public String b(){
        System.out.println("你正在访问资源b---前");
        System.out.println("b");
        System.out.println("你正在访问资源b---后");
        return "你正在访问资源b";
    }
}

访问b资源:
Java自定义注解及使用场景_第1张图片
访问a资源:
Java自定义注解及使用场景_第2张图片

自定义注解+AOP

添加AOP依赖:

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-aopartifactId>
        dependency>

自定义注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
}

AOP配置类:

@Aspect
@Component
public class MyLogAspect {

    //@annotation表示这个切点在一个注解上,后面带上这个注解的全类名
    @Pointcut("@annotation(MyLog)")
    public void logPointCut(){

    }

    @Around("logPointCut()")
    public Object logAround(ProceedingJoinPoint joinPoint){
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();
        System.out.println("joinPoint.getThis():" + joinPoint.getThis());
        System.out.println("joinPoint.getTarget():" + joinPoint.getTarget());

        //获取入参
        Object[] params = joinPoint.getArgs();
        StringBuilder sb = new StringBuilder();
        for (Object param : params) {
            sb.append(param).append("; ");
        }

        System.out.println("进入[" + methodName + "]方法,参数为:" + sb.toString());

        Object object = null;

        try {
            //接收方法的返回值
            object = joinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }

        System.out.println(methodName + "方法执行结束");
        return object;
    }
    
}

添加web层接口:

    @MyLog
    @GetMapping(value = "/c/{source_name}")
    public String sourceC(@PathVariable("source_name") String sourceName){
        System.out.println("你正在访问资源C,sourceName:"+sourceName);
        System.out.println("你正在访问资源C---前");
        System.out.println("你正在访问资源C---后");
        return "你正在访问资源C";
    }

打印信息如下:
Java自定义注解及使用场景_第3张图片

preHandle方法在业务处理器处理请求之前被调用
joinPoint.getThis():com.fanle.LoginController@3827ed1d
joinPoint.getTarget():com.fanle.LoginController@3827ed1d
进入[sourceC]方法,参数为:helloworld; 
你正在访问资源C,sourceName:helloworld
你正在访问资源C---前
你正在访问资源C---后
sourceC方法执行结束
postHandle方法在业务处理器处理请求执行完成后,生成视图之前执行
afterCompletion方法在DispatcherServlet完全处理完请求后被调用,可用于清理资源等

你可能感兴趣的:(SpringBoot,javase,java,开发语言)