精华内容
下载资源
问答
  • @HLColumn(commont="1223") public Long getJieshouId() { [color=#FF0000] //执行这个方法时候,如何在此获取方法上的注解[/color] return jieshouId; }
  • 本文介绍了Spring Boot 通过AOP和自定义注解实现权限控制,分享给大家,具体如下:源码:https://github.com/yulc-coding/java-note/tree/master/aop思路自定义权限注解在需要验证接口加上注解,并设置具体权限...

    本文介绍了Spring Boot 通过AOP和自定义注解实现权限控制,分享给大家,具体如下:

    源码:https://github.com/yulc-coding/java-note/tree/master/aop

    思路

    自定义权限注解

    在需要验证的接口上加上注解,并设置具体权限值

    数据库权限表中加入对应接口需要的权限

    用户登录时,获取当前用户的所有权限列表放入Redis缓存中

    定义AOP,将切入点设置为自定义的权限

    AOP中获取接口注解的权限值,和Redis中的数据校验用户是否存在该权限,如果Redis中没有,则从数据库获取用户权限列表,再校验

    pom文件 引入AOP

    org.springframework.boot

    spring-boot-starter-web

    org.springframework.boot

    spring-boot-starter-aop

    自定义注解 VisitPermission

    @Target(ElementType.METHOD)

    @Retention(RetentionPolicy.RUNTIME)

    public @interface VisitPermission {

    /**

    * 用于配置具体接口的权限值

    * 在数据库中添加对应的记录

    * 用户登录时,将用户所有的权限列表放入redis中

    * 用户访问接口时,将对应接口的值和redis中的匹配看是否有访问权限

    * 用户退出登录时,清空redis中对应的权限缓存

    */

    String value() default "";

    }

    需要设置权限的接口上加入注解 @VisitPermission(value)

    @RestController

    @RequestMapping("/permission")

    public class PermissionController {

    /**

    * 配置权限注解 @VisitPermission("permission-test")

    * 只用拥有该权限的用户才能访问,否则提示非法操作

    */

    @VisitPermission("permission-test")

    @GetMapping("/test")

    public String test() {

    System.out.println("================== step 3: doing ==================");

    return "success";

    }

    }

    定义权限AOP

    设置切入点为@annotation(VisitPermission)

    获取请求中的token,校验是否token是否过期或合法

    获取注解中的权限值,校验当前用户是否有访问权限

    MongoDB 记录访问日志(IP、参数、接口、耗时等)

    @Aspect

    @Component

    public class PermissionAspect {

    /**

    * 切入点

    * 切入点为包路径下的:execution(public * org.ylc.note.aop.controller..*(..)):

    * org.ylc.note.aop.Controller包下任意类任意返回值的 public 的方法

    *

    * 切入点为注解的: @annotation(VisitPermission)

    * 存在 VisitPermission 注解的方法

    */

    @Pointcut("@annotation(org.ylc.note.aop.annotation.VisitPermission)")

    private void permission() {

    }

    /**

    * 目标方法调用之前执行

    */

    @Before("permission()")

    public void doBefore() {

    System.out.println("================== step 2: before ==================");

    }

    /**

    * 目标方法调用之后执行

    */

    @After("permission()")

    public void doAfter() {

    System.out.println("================== step 4: after ==================");

    }

    /**

    * 环绕

    * 会将目标方法封装起来

    * 具体验证业务数据

    */

    @Around("permission()")

    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

    System.out.println("================== step 1: around ==================");

    long startTime = System.currentTimeMillis();

    /*

    * 获取当前http请求中的token

    * 解析token :

    * 1、token是否存在

    * 2、token格式是否正确

    * 3、token是否已过期(解析信息或者redis中是否存在)

    * */

    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

    HttpServletRequest request = attributes.getRequest();

    String token = request.getHeader("token");

    if (StringUtils.isEmpty(token)) {

    throw new RuntimeException("非法请求,无效token");

    }

    // 校验token的业务逻辑

    // ...

    /*

    * 获取注解的值,并进行权限验证:

    * redis 中是否存在对应的权限

    * redis 中没有则从数据库中获取权限

    * 数据空中没有,抛异常,非法请求,没有权限

    * */

    Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();

    VisitPermission visitPermission = method.getAnnotation(VisitPermission.class);

    String value = visitPermission.value();

    // 校验权限的业务逻辑

    // List permissions = redis.get(permission)

    // db.getPermission

    // permissions.contains(value)

    // ...

    System.out.println(value);

    // 执行具体方法

    Object result = proceedingJoinPoint.proceed();

    long endTime = System.currentTimeMillis();

    /*

    * 记录相关执行结果

    * 可以存入MongoDB 后期做数据分析

    * */

    // 打印请求 url

    System.out.println("URL : " + request.getRequestURL().toString());

    // 打印 Http method

    System.out.println("HTTP Method : " + request.getMethod());

    // 打印调用 controller 的全路径以及执行方法

    System.out.println("controller : " + proceedingJoinPoint.getSignature().getDeclaringTypeName());

    // 调用方法

    System.out.println("Method : " + proceedingJoinPoint.getSignature().getName());

    // 执行耗时

    System.out.println("cost-time : " + (endTime - startTime) + " ms");

    return result;

    }

    }

    展开全文
  • linux系统通过new Date()获取的时间是世界时间(UTC时间)所以在获取时间时需要对时间进行时区处理操作 方案一:springboot项目在主启动类中通过注解@PostConstruct解决 public static void main(String[]...

    问题出现原因

    项目部署到linux服务器,通过new Date()获取时间和在windows本地时间不一致,通过排查问题,发现是new Date()的问题

    linux系统上通过new Date()获取的时间是世界时间(UTC时间)所以在获取时间时需要对时间进行时区的处理操作

    方案一:springboot项目在主启动类中通过注解@PostConstruct解决

    
    
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    
        /**
         *  解决通过 new Date()获取时间不一致问题,解决发送审批时间早8八个小时问题
         * @PostConstruct 是java的注解,被用来修饰一个非静态非静态的void()方法,
         *                是一种JSR-250的规范,当bean创建完成的时候,会后置执行@PostConstruct修                
                          饰的方法
         *  spring中@PostConstruct 在Bean初始化中的执行顺序
         *                Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释    
                          的方法)
         */
        @PostConstruct
        void started() {
            TimeZone.setDefault(TimeZone.getTimeZone("GMT+8"));
        }
    
    

    方案二:在通过new Date()获取时间后,将时间设置成东八区时间

            Date date=new Date();
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            // 设置成东八区时间
            dateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));

     

    展开全文
  • 自定义事务注解步骤: 第一步:自定义注解。 第二步:手动封装事务。 第三步:定义一个事务扫包AOP...1.使用java反射机制进行扫包,获取当前包下的所有类。 2.判断类是否存在注入bean的注解。 3.使用java...

    自定义事务注解步骤:

    第一步:自定义注解。

    第二步:手动封装事务。

    第三步:定义一个事务扫包AOP(具体拦截哪些方法)

    第四步:拦截方法的时候,使用反射技术判断该方法上是否有事务注解,如果有的话就开启事务,没有的话就不开启事务。

     

    自定义注解简单步骤:

    1.使用java反射机制进行扫包,获取当前包下的所有类。

    2.判断类上是否存在注入bean的注解。

    3.使用java反射机制进行初始化。

    转载于:https://www.cnblogs.com/ming-blogs/p/10865264.html

    展开全文
  • 1.概述 深入理解注解及spring对注解的增强 2. 什么是注解? 代码中注释大家都熟悉吧,注释是给开发者看,可以...比如:大家对@Override应该比较熟悉,就是一个注解,加在方法上,标注当前方法重写了父类方法,当编.

    在这里插入图片描述

    1.概述

    深入理解注解及spring对注解的增强

    2. 什么是注解?

    代码中注释大家都熟悉吧,注释是给开发者看的,可以提升代码的可读性和可维护性,但是对于java编译器和虚拟机来说是没有意义的,编译之后的字节码文件中是没有注释信息的;而注解和注释有点类似,唯一的区别就是注释是给人看的,而注解是给编译器和虚拟机看的,编译器和虚拟机在运行的过程中可以获取注解信息,然后可以根据这些注解的信息做各种想做的事情。比如:大家对@Override应该比较熟悉,就是一个注解,加在方法上,标注当前方法重写了父类的方法,当编译器编译代码的时候,会对@Override标注的方法进行验证,验证其父类中是否也有同样签名的方法,否则报错,通过这个注解是不是增强了代码的安全性。

    总的来说:注解是对代码的一种增强,可以在代码编译或者程序运行期间获取注解的信息,然后根据这些信息做各种牛逼的事情。

    3.注解如何使用?

    3个步骤:

    1. 定义注解

    2. 使用注解

    3. 获取注解信息做各种牛逼的事情

    4. 定义注解

    关于注解的定义,先来几个问题:

    1. 如何为注解定义参数?

    2. 注解可以用在哪里?

    3. 注解会被保留到什么时候?

    4.1 定义注解语法

    jdk中注解相关的类和接口都定义在java.lang.annotation包中。

    注解的定义和我们常见的类、接口类似,只是注解使用@interface来定义,如下定义一个名称为MyAnnotation的注解:

    public @interface MyAnnotation {
    }
    

    4.2 注解中定义参数

    注解有没有参数都可以,定义参数如下:

    public @interface 注解名称{
        [public] 参数类型 参数名称1() [default 参数默认值];
        [public] 参数类型 参数名称2() [default 参数默认值];
        [public] 参数类型 参数名称n() [default 参数默认值];
    }
    

    注解中可以定义多个参数,参数的定义有以下特点:

    1. 访问修饰符必须为public,不写默认为public

    2. 该元素的类型只能是基本数据类型、String、Class、枚举类型、注解类型(体现了注解的嵌套效果)以及上述类型的一位数组

    3. 该元素的名称一般定义为名词,如果注解中只有一个元素,请把名字起为value(后面使用会带来便利操作)

    4. 参数名称后面的()不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法

    5. default代表默认值,值必须和第2点定义的类型一致

    6. 如果没有默认值,代表后续使用注解时必须给该类型元素赋值

    4.3 指定注解的使用范围:@Target

    使用@Target注解定义注解的使用范围,如下:

    @Target(value = {ElementType.TYPE,ElementType.METHOD})
    public @interface MyAnnotation {
    }
    

    上面指定了MyAnnotation注解可以用在类、接口、注解类型、枚举类型以及方法上面,自定义注解上也可以不使用@Target注解,如果不使用,表示自定义注解可以用在任何地方

    看一下@Target源码:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
        ElementType[] value();
    }
    

    有一个参数value,是ElementType类型的一个数组,再来看一下ElementType,是个枚举,源码如下:

    package java.lang.annotation;
    /*注解的使用范围*/
    public enum ElementType {
           /*类、接口、枚举、注解上面*/
        TYPE,
        /*字段上*/
        FIELD,
        /*方法上*/
        METHOD,
        /*方法的参数上*/
        PARAMETER,
        /*构造函数上*/
        CONSTRUCTOR,
        /*本地变量上*/
        LOCAL_VARIABLE,
        /*注解上*/
        ANNOTATION_TYPE,
        /*包上*/
        PACKAGE,
        /*类型参数上*/
        TYPE_PARAMETER,
        /*类型名称上*/
        TYPE_USE
    }
    

    4.4 指定注解的保留策略:@Retention

    我们先来看一下java程序的3个过程

    1. 源码阶段

    2. 源码被编译为字节码之后变成class文件

    3. 字节码被虚拟机加载然后运行

    那么自定义注解会保留在上面哪个阶段呢?可以通过@Retention注解来指定,如:

    @Retention(RetentionPolicy.SOURCE)
    public @interface MyAnnotation {
    }
    

    上面指定了MyAnnotation只存在于源码阶段,后面的2个阶段都会丢失。

    来看一下@Retention

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
        RetentionPolicy value();
    }
    

    有一个value参数,类型为RetentionPolicy枚举,如下:

    public enum RetentionPolicy {
        /*注解只保留在源码中,编译为字节码之后就丢失了,也就是class文件中就不存在了*/
        SOURCE,
        /*注解只保留在源码和字节码中,运行阶段会丢失*/
        CLASS,
        /*源码、字节码、运行期间都存在*/
        RUNTIME
    }
    

    5.使用注解

    5.1 语法

    将注解加载使用的目标上面,如下:

    @注解名称(参数1=1,参数2=2,参数n=值n)
    目标对象
    

    直接来案例说明。

    5.2 无参注解

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann1 { //@1
    }
    
    
    @Ann1 //@2
    public class UseAnnotation1 {
    }
    

    @1:Ann1为无参注解

    @2:类上使用@Ann1注解,没有参数

    5.3 一个参数的注解

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann2 { //@1
        String name();
    }
    
    
    @Ann2(name = "我是路人甲java") //@2
    public class UseAnnotation2 {
    
    }
    

    5.4 一个参数为value的注解,可以省略参数名称

    只有一个参数,名称为value的时候,使用时参数名称可以省略

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann3 {
        String value();//@1
    }
    
    @Ann3("我是路人甲java") //@2
    public class UseAnnotation3 {
    
    }
    

    @1:注解之后一个参数,名称为value

    @2:使用注解,参数名称value省略了

    5.4 数组类型参数

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann4 {
        String[] name();//@1
    }
    
    @Ann4(name = {"我是路人甲java", "欢迎和我一起学spring"}) //@2
    public class UseAnnotation4 {
        @Ann4(name = "如果只有一个值,{}可以省略") //@3
        public class T1 {
        }
    }
    

    @1:name的类型是一个String类型的数组

    @2:name有多个值的时候,需要使用{}包含起来

    @3:如果name只有一个值,{}可以省略

    5.5 参数指定默认值

    通过default为参数指定默认值,用的时候如果没有设置值,则取默认值,没有指定默认值的参数,使用的时候必须为参数设置值,如下:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann5 {
        String[] name() default {"路人甲java", "spring系列"};//@1
        int[] score() default 1; //@2
        int age() default 30; //@3
        String address(); //@4
    }
    
    @Ann5(age = 32,address = "上海") //@5
    public class UseAnnotation5 {
    
    }
    

    @1:数组类型通过{}指定默认值

    @2:数组类型参数,默认值只有一个省略了{}符号

    @3:默认值为30

    @4:未指定默认值

    @5:age=32对默认值进行了覆盖,并且为address指定了值

    5.6 综合案例

    @Target(value = {
            ElementType.TYPE,
            ElementType.METHOD,
            ElementType.FIELD,
            ElementType.PARAMETER,
            ElementType.CONSTRUCTOR,
            ElementType.LOCAL_VARIABLE
    })
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann6 {
        String value();
    
        ElementType elementType();
    }
    
    @Ann6(value = "我用在类上", elementType = ElementType.TYPE)
    public class UseAnnotation6 {
        @Ann6(value = "我用在字段上", elementType = ElementType.FIELD)
        private String a;
    
        @Ann6(value = "我用在构造方法上", elementType = ElementType.CONSTRUCTOR)
        public UseAnnotation6(@Ann6(value = "我用在方法参数上", elementType = ElementType.PARAMETER) String a) {
            this.a = a;
        }
    
        @Ann6(value = "我用在了普通方法上面", elementType = ElementType.METHOD)
        public void m1() {
            @Ann6(value = "我用在了本地变量上", elementType = ElementType.LOCAL_VARIABLE) String a;
        }
    }
    

    上面演示了自定义注解在在类、字段、构造器、方法参数、方法、本地变量上的使用,@Ann6注解有个elementType参数,我想通过这个参数的值来告诉大家对应@Target中的那个值来限制使用目标的,大家注意一下上面每个elementType的值。

    5.7 @Target(ElementType.TYPE_PARAMETER)

    这个是1.8加上的,用来标注类型参数,类型参数一般在类后面声明或者方法上声明,这块需要先了解一下泛型泛型,有点难度,会让很多人懵逼,那是因为你没有看这篇文章!不然理解起来比较吃力,来个案例感受一下:

    @Target(value = {
            ElementType.TYPE_PARAMETER
    })
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann7 {
        String value();
    }
    
    public class UseAnnotation7<@Ann7("T0是在类上声明的一个泛型类型变量") T0, @Ann7("T1是在类上声明的一个泛型类型变量") T1> {
    
        public <@Ann7("T2是在方法上声明的泛型类型变量") T2> void m1() {
        }
    
        public static void main(String[] args) throws NoSuchMethodException {
            for (TypeVariable typeVariable : UseAnnotation7.class.getTypeParameters()) {
                print(typeVariable);
            }
    
            for (TypeVariable typeVariable : UseAnnotation7.class.getDeclaredMethod("m1").getTypeParameters()) {
                print(typeVariable);
            }
        }
    
        private static void print(TypeVariable typeVariable) {
            System.out.println("类型变量名称:" + typeVariable.getName());
            Arrays.stream(typeVariable.getAnnotations()).forEach(System.out::println);
        }
    }
    

    类和方法上面可以声明泛型类型的变量,上面有3个泛型类型变量,我们运行一下看看效果:

    类型变量名称:T0
    @com.javacode2018.lesson001.demo18.Ann7(value=T0是在类上声明的一个泛型类型变量)
    类型变量名称:T1
    @com.javacode2018.lesson001.demo18.Ann7(value=T1是在类上声明的一个泛型类型变量)
    类型变量名称:T2
    @com.javacode2018.lesson001.demo18.Ann7(value=T2是在方法上声明的泛型类型变量)
    
    

    5.8 @Target(ElementType.TYPE_USE)

    这个是1.8加上的,能用在任何类型名称上,来个案例感受一下:

    @Target({ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann10 {
        String value();
    }
    
    @Ann10("用在了类上")
    public class UserAnnotation10<@Ann10("用在了类变量类型V1上") V1, @Ann10("用在了类变量类型V2上") V2> {
    
        private Map<@Ann10("用在了泛型类型上") String, Integer> map;
    
        public <@Ann10("用在了参数上") T> String m1(String name) {
            return null;
        }
    
    }
    

    类后面的V1、V2都是类型名称,Map后面的尖括号也是类型名称,m1方法前面也定义了一个类型变量,名称为T

    6.注解信息的获取

    为了运行时能准确获取到注解的相关信息,Java在java.lang.reflect 反射包下新增了AnnotatedElement接口,它主要用于表示目前正在虚拟机中运行的程序中已使用注解的元素,通过该接口提供的方法可以利用反射技术地读取注解的信息,看一下UML图:

    在这里插入图片描述

    Package:用来表示包的信息

    Class:用来表示类的信息

    Constructor:用来表示构造方法信息

    Field:用来表示类中属性信息

    Method:用来表示方法信息

    Parameter:用来表示方法参数信息

    TypeVariable:用来表示类型变量信息,如:类上定义的泛型类型变量,方法上面定义的泛型类型变量

    6.1 AnnotatedElement常用方法

    在这里插入图片描述

    6.2 案例

    要解析的列如下

    package com.javacode2018.lesson001.demo18;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.util.Map;
    
    @Target({ElementType.PACKAGE,
            ElementType.TYPE,
            ElementType.FIELD,
            ElementType.CONSTRUCTOR,
            ElementType.METHOD,
            ElementType.PARAMETER,
            ElementType.TYPE_PARAMETER,
            ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann11 {
        String value();
    }
    
    @Target({ElementType.PACKAGE,
            ElementType.TYPE,
            ElementType.FIELD,
            ElementType.CONSTRUCTOR,
            ElementType.METHOD,
            ElementType.PARAMETER,
            ElementType.TYPE_PARAMETER,
            ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann11_0 {
        int value();
    }
    
    @Ann11("用在了类上")
    @Ann11_0(0)
    public class UseAnnotation11<@Ann11("用在了类变量类型V1上") @Ann11_0(1) V1, @Ann11("用在了类变量类型V2上") @Ann11_0(2) V2> {
        @Ann11("用在了字段上")
        @Ann11_0(3)
        private String name;
    
        private Map<@Ann11("用在了泛型类型上,String") @Ann11_0(4) String, @Ann11("用在了泛型类型上,Integer") @Ann11_0(5) Integer> map;
    
        @Ann11("用在了构造方法上")
        @Ann11_0(6)
        public UseAnnotation11() {
            this.name = name;
        }
    
        @Ann11("用在了返回值上")
        @Ann11_0(7)
        public String m1(@Ann11("用在了参数上") @Ann11_0(8) String name) {
            return null;
        }
    
    }
    

    6.3 解析类上的注解

    解析这部分

    @Ann11("用在了类上")
    代码
    @Test
    public void m1() {
        for (Annotation annotation : UserAnnotation10.class.getAnnotations()) {
            System.out.println(annotation);
        }
    }
    

    运行输出

    @com.javacode2018.lesson001.demo18.Ann11(value=用在了类上)
    @com.javacode2018.lesson001.demo18.Ann11_0(value=0)
    

    解析类上的类型变量

    解析类名后面的尖括号的部分,即下面的部分:

    UseAnnotation11<@Ann11("用在了类变量类型V1上") @Ann11_0(1) V1, @Ann11("用在了类变量类型V2上") @Ann11_0(2) V2>
    
    

    用例代码

    @Test
    public void m2() {
        TypeVariable<Class<UserAnnotation10>>[] typeParameters = UserAnnotation10.class.getTypeParameters();
        for (TypeVariable<Class<UserAnnotation10>> typeParameter : typeParameters) {
            System.out.println(typeParameter.getName() + "变量类型注解信息:");
            Annotation[] annotations = typeParameter.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println(annotation);
            }
        }
    }
    

    运行输出

    V1变量类型注解信息:
    @com.javacode2018.lesson001.demo18.Ann11(value=用在了类变量类型V1上)
    @com.javacode2018.lesson001.demo18.Ann11_0(value=1)
    V2变量类型注解信息:
    @com.javacode2018.lesson001.demo18.Ann11(value=用在了类变量类型V2上)
    @com.javacode2018.lesson001.demo18.Ann11_0(value=2)
    

    解析字段name上的注解

    用例代码

    @Test
    public void m3() throws NoSuchFieldException {
        Field nameField = UserAnnotation10.class.getDeclaredField("name");
        for (Annotation annotation : nameField.getAnnotations()) {
            System.out.println(annotation);
        }
    }
    

    运行输出

    @com.javacode2018.lesson001.demo18.Ann11(value=用在了字段上)
    @com.javacode2018.lesson001.demo18.Ann11_0(value=3)
    

    解析泛型字段map上的注解

    用例代码

    @Test
    public void m4() throws NoSuchFieldException, ClassNotFoundException {
        Field field = UseAnnotation11.class.getDeclaredField("map");
        Type genericType = field.getGenericType();
        Type[] actualTypeArguments = ((ParameterizedType) genericType).getActualTypeArguments();
    
        AnnotatedType annotatedType = field.getAnnotatedType();
        AnnotatedType[] annotatedActualTypeArguments = ((AnnotatedParameterizedType) annotatedType).getAnnotatedActualTypeArguments();
        int i = 0;
        for (AnnotatedType actualTypeArgument : annotatedActualTypeArguments) {
            Type actualTypeArgument1 = actualTypeArguments[i++];
            System.out.println(actualTypeArgument1.getTypeName() + "类型上的注解如下:");
            for (Annotation annotation : actualTypeArgument.getAnnotations()) {
                System.out.println(annotation);
            }
        }
    }
    

    运行输出

    java.lang.String类型上的注解如下:
    @com.javacode2018.lesson001.demo18.Ann11(value=用在了泛型类型上,String)
    @com.javacode2018.lesson001.demo18.Ann11_0(value=4)
    java.lang.Integer类型上的注解如下:
    @com.javacode2018.lesson001.demo18.Ann11(value=用在了泛型类型上,Integer)
    @com.javacode2018.lesson001.demo18.Ann11_0(value=5)
    

    解析构造函数上的注解

    用例代码

    @Test
    public void m5() {
        Constructor<?> constructor = UseAnnotation11.class.getConstructors()[0];
        for (Annotation annotation : constructor.getAnnotations()) {
            System.out.println(annotation);
        }
    }
    

    运行输出

    @com.javacode2018.lesson001.demo18.Ann11(value=用在了构造方法上)
    @com.javacode2018.lesson001.demo18.Ann11_0(value=6)
    

    解析m1方法上的注解

    用例代码

    @Test
    public void m6() throws NoSuchMethodException {
        Method method = UseAnnotation11.class.getMethod("m1", String.class);
        for (Annotation annotation : method.getAnnotations()) {
            System.out.println(annotation);
        }
    }
    

    运行输出

    @com.javacode2018.lesson001.demo18.Ann11(value=用在了返回值上)
    @com.javacode2018.lesson001.demo18.Ann11_0(value=7)
    

    解析m1方法参数注解

    用例代码

    @Test
    public void m7() throws NoSuchMethodException {
        Method method = UseAnnotation11.class.getMethod("m1", String.class);
        for (Parameter parameter : method.getParameters()) {
            System.out.println(String.format("参数%s上的注解如下:", parameter.getName()));
            for (Annotation annotation : parameter.getAnnotations()) {
                System.out.println(annotation);
            }
        }
    }
    

    运行输出

    参数arg0上的注解如下:
    @com.javacode2018.lesson001.demo18.Ann11(value=用在了参数上)
    @com.javacode2018.lesson001.demo18.Ann11_0(value=8)
    

    上面参数名称为arg0,如果想让参数名称和源码中真实名称一致,操作如下:

    如果你编译这个class的时候没有添加参数–parameters,运行的时候你会得到这个结果:

    Parameter: arg0

    编译的时候添加了–parameters参数的话,运行结果会不一样:

    Parameter: args
    
    对于有经验的Maven使用者,–parameters参数可以添加到maven-compiler-plugin的配置部分:
    
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
            <compilerArgument>-parameters</compilerArgument>
            <source>1.8</source>
            <target>1.8</target>
        </configuration>
    </plugin>
    

    7 @Inherit:实现类之间的注解继承

    7.1 用法

    来看一下这个注解的源码

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Inherited {
    }
    

    我们通过@Target元注解的属性值可以看出,这个@Inherited 是专门修饰注解的。

    作用:让子类可以继承父类中被@Inherited修饰的注解,注意是继承父类中的,如果接口中的注解也使用@Inherited修饰了,那么接口的实现类是无法继承这个注解的

    7.2 案例

    package com.javacode2018.lesson001.demo18;
    
    import java.lang.annotation.*;
    
    public class InheritAnnotationTest {
        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        @Inherited
        @interface A1{ //@1
        }
        @Target(ElementType.TYPE)
        @Retention(RetentionPolicy.RUNTIME)
        @Inherited
        @interface A2{ //@2
        }
    
        @A1 //@3
        interface I1{}
        @A2 //@4
        static class C1{}
    
        static class C2 extends C1 implements I1{} //@5
    
        public static void main(String[] args) {
            for (Annotation annotation : C2.class.getAnnotations()) { //@6
                System.out.println(annotation);
            }
        }
    }
    

    @1:定义了一个注解A1,上面使用了@Inherited,表示这个具有继承功能

    @2:定义了一个注解A2,上面使用了@Inherited,表示这个具有继承功能

    @3:定义接口I1,上面使用了@A1注解

    @4:定义了一个C1类,使用了A2注解

    @5:C2继承了C1并且实现了I1接口

    @6:获取C2上以及从父类继承过来的所有注解,然后输出

    运行输出:

    @com.javacode2018.lesson001.demo18.InheritAnnotationTest$A2()
    

    从输出中可以看出类可以继承父类上被@Inherited修饰的注解,而不能继承接口上被@Inherited修饰的注解,这个一定要注意

    8.@Repeatable重复使用注解

    来看一段代码:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @interface Ann12{}
    
    @Ann12
    @Ann12
    public class UseAnnotation12 {
    }
    

    上面代码会报错,原因是:UseAnnotation12上面重复使用了@Ann12注解,默认情况下@Ann12注解是不允许重复使用的。

    像上面这样,如果我们想重复使用注解的时候,需要用到@Repeatable注解

    8.2 使用步骤

    先定义容器注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.FIELD})
    @interface Ann12s {
        Ann12[] value(); //@1
    }
    

    容器注解中必须有个value类型的参数,参数类型为子注解类型的数组。

    8.3 为注解指定容器

    要让一个注解可以重复使用,需要在注解上加上@Repeatable注解,@Repeatable中value的值为容器注解,如下代码中的@2

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.FIELD})
    @Repeatable(Ann12s.class)//@2
    @interface Ann12 {
        String name();
    }
    

    8.4 使用注解

    重复使用相同的注解有2种方式,如下面代码

    1. 重复使用注解,如下面的类上重复使用@Ann12注解

    2. 通过容器注解来使用更多个注解,如下面的字段v1上使用@Ann12s容器注解

    @Ann12(name = "路人甲Java")
    @Ann12(name = "Spring系列")
    public class UseAnnotation12 {
        @Ann12s(
                {@Ann12(name = "Java高并发系列,见公众号"),
                        @Ann12(name = "mysql高手系列,见公众号")}
        )
        private String v1;
    }
    

    获取注解信息

    com.javacode2018.lesson001.demo18.UseAnnotation12
    
    @Test
    public void test1() throws NoSuchFieldException {
        Annotation[] annotations = UseAnnotation12.class.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        System.out.println("-------------");
        Field v1 = UseAnnotation12.class.getDeclaredField("v1");
        Annotation[] declaredAnnotations = v1.getDeclaredAnnotations();
        for (Annotation declaredAnnotation : declaredAnnotations) {
            System.out.println(declaredAnnotation);
        }
    }
    

    运行输出:

    @com.javacode2018.lesson001.demo18.Ann12s(value=[@com.javacode2018.lesson001.demo18.Ann12(name=路人甲Java), @com.javacode2018.lesson001.demo18.Ann12(name=Spring系列)])
    -------------
    @com.javacode2018.lesson001.demo18.Ann12s(value=[@com.javacode2018.lesson001.demo18.Ann12(name=Java高并发系列,见公众号), @com.javacode2018.lesson001.demo18.Ann12(name=mysql高手系列,见公众号)])
    

    上面就是java中注解的功能,下面我们来介绍spring对于注解方面的支持。

    9.先来看一个问题

    代码如下:

    package com.javacode2018.lesson001.demo18;
    
    import org.junit.Test;
    import org.springframework.core.annotation.AnnotatedElementUtils;
    import org.springframework.core.annotation.AnnotationUtils;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface A1 {
        String value() default "a";//@0
    }
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @A1
    @interface B1 { //@1
        String value() default "b";//@2
    }
    
    @B1("路人甲Java") //@3
    public class UseAnnotation13 {
        @Test
        public void test1() {
            //AnnotatedElementUtils是spring提供的一个查找注解的工具类
            System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation13.class, B1.class));
            System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation13.class, A1.class));
        }
    }
    

    @0:A1注解value参数值默认为a

    @1:B1注解上使用到了@A1注解

    @2:B1注解value参数值默认为b

    @2:UseAnnotation13上面使用了@B1注解,value参数的值为:路人甲java

    test1方法中使用到了spring中的一个类AnnotatedElementUtils,通过这个工具类可以很方便的获取注解的各种信息,方法中的2行代码用于获取UseAnnotation13类上B1注解和A1注解的信息。

    运行test1方法输出:

    @com.javacode2018.lesson001.demo18.B1(value=路人甲Java)
    @com.javacode2018.lesson001.demo18.A1(value=a)
    

    上面用法很简单,没什么问题。

    此时有个问题:此时如果想在UseAnnotation13上给B1上的A1注解设置值是没有办法的,注解定义无法继承导致的,如果注解定义上面能够继承,那用起来会爽很多,spring通过@Aliasfor方法解决了这个问题。

    10. Spring @AliasFor:对注解进行增强

    直接上案例,然后解释代码。

    10.1 案例1:通过@AliasFor解决刚才难题

    package com.javacode2018.lesson001.demo18;
    
    import org.junit.Test;
    import org.springframework.core.annotation.AliasFor;
    import org.springframework.core.annotation.AnnotatedElementUtils;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface A14 {
        String value() default "a";//@0
    }
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @A14 //@6
    @interface B14 { //@1
    
        String value() default "b";//@2
    
        @AliasFor(annotation = A14.class, value = "value") //@5
        String a14Value();
    }
    
    @B14(value = "路人甲Java",a14Value = "通过B14给A14的value参数赋值") //@3
    public class UseAnnotation14 {
        @Test
        public void test1() {
            //AnnotatedElementUtils是spring提供的一个查找注解的工具类
            System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation14.class, B14.class));
            System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation14.class, A14.class));
        }
    }
    

    运行输出:

    @com.javacode2018.lesson001.demo18.B14(a14Value=通过B14给A14的value参数赋值, value=路人甲Java)
    @com.javacode2018.lesson001.demo18.A14(value=通过B14给A14的value参数赋值)
    

    注意上面diam的@3只使用了B14注解,大家认真看一下,上面输出汇总可以看出A14的value值和B14的a14Value参数值一样,说明通过B14给A14设置值成功了。

    重点在于代码@5,这个地方使用到了@AliasFor注解:

    @AliasFor(annotation = A14.class, value = "value")
    

    这个相当于给某个注解指定别名,即将B1注解中a14Value参数作为A14中value参数的别名,当给B1的a14Value设置值的时候,就相当于给A14的value设置值,有个前提是@AliasFor注解的annotation参数指定的注解需要加载当前注解上面,如:@6

    10.2 案例2:同一个注解中使用@AliasFor

    package com.javacode2018.lesson001.demo18;
    
    import org.junit.Test;
    import org.springframework.core.annotation.AliasFor;
    import org.springframework.core.annotation.AnnotatedElementUtils;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.TYPE, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface A15 {
        @AliasFor("v2")//@1
        String v1() default "";
    
        @AliasFor("v1")//@2
        String v2() default "";
    }
    
    @A15(v1 = "我是v1") //@3
    public class UseAnnotation15 {
    
        @A15(v2 = "我是v2") //@4
        private String name;
    
        @Test
        public void test1() throws NoSuchFieldException {
            //AnnotatedElementUtils是spring提供的一个查找注解的工具类
            System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation15.class, A15.class));
            System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation15.class.getDeclaredField("name"), A15.class));
        }
    }
    

    注意上面代码,A15注解中(@1和@2)的2个参数都设置了@AliasFor,@AliasFor如果不指定annotation参数的值,那么annotation默认值就是当前注解,所以上面2个属性互为别名,当给v1设置值的时候也相当于给v2设置值,当给v2设置值的时候也相当于给v1设置值。

    运行输出

    @com.javacode2018.lesson001.demo18.A15(v1=我是v1, v2=我是v1)
    @com.javacode2018.lesson001.demo18.A15(v1=我是v2, v2=我是v2)
    

    从输出中可以看出v1和v2的值始终是相等的,上面如果同时给v1和v2设置值的时候运行代码会报错。

    我们回头来看看@AliasFor的源码:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    @Documented
    public @interface AliasFor {
    
        @AliasFor("attribute")
        String value() default "";
    
        @AliasFor("value")
        String attribute() default "";
    
        Class<? extends Annotation> annotation() default Annotation.class;
    
    }
    

    AliasFor注解中value和attribute互为别名,随便设置一个,同时会给另外一个设置相同的值。

    10.3 案例2:@AliasFor中不指定value和attribute

    当@AliasFor中不指定value或者attribute的时候,自动将@AliasFor修饰的参数作为value和attribute的值,如下@AliasFor注解的value参数值为name

    package com.javacode2018.lesson001.demo18;
    
    import org.junit.Test;
    import org.springframework.core.annotation.AliasFor;
    import org.springframework.core.annotation.AnnotatedElementUtils;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface A16 {
        String name() default "a";//@0
    }
    
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @A16
    @interface B16 { //@1
    
        @AliasFor(annotation = A16.class) //@5
        String name() default "b";//@2
    }
    
    @B16(name="我是v1") //@3
    public class UseAnnotation16 {
    
    
        @Test
        public void test1() throws NoSuchFieldException {
            //AnnotatedElementUtils是spring提供的一个查找注解的工具类
            System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation16.class, A16.class));
            System.out.println(AnnotatedElementUtils.getMergedAnnotation(UseAnnotation16.class, B16.class));
        }
    }
    

    运行输出:

    @com.javacode2018.lesson001.demo18.A16(name=我是v1)
    @com.javacode2018.lesson001.demo18.B16(name=我是v1)
    
    展开全文
  • System.out.println("获取当前系统时间"+now);// new Date()为获取当前系统时间 System.out.println("获取自定义时间"+time);//获取自定义时间 /*System.out.println("总条数"+service.getCount());*/ ...
  • JAVA上百实例源码以及开源项目

    千次下载 热门讨论 2016-01-03 17:37:40
    6个目标文件,EJB来模拟银行ATM机流程及操作:获取系统属性,初始化JNDI,取得Home对象引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象count()方法,保证Bean正常被激活和钝化,EJB对象是用...
  • EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机流程及操作:获取系统属性,初始化JNDI,取得Home对象引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象count()方法,...
  • 1.JDK的元注解:就是专门用来声明其他注解的注解 作用:通过元注解了解其他注解的使用特点,还可以自定义注解 2.元注解: 1. @Target @Target 作用 用来限制...
  • 作用:用在方法上,表示当前方法会在控制器方法执行之前执行;用在参数上获取指定数据给参数赋值。 常用属性 属性 功能 value 用于获取数据key 应用场景:当表单提交数据不是完整实体类数据时,...
  • Spring-注解方式测试

    2018-02-04 12:02:54
    便于运行Spring代码,否则就要像Spring开篇教程那样在main方法里写一大堆准备代码来获取相关bean了 jar 注解方式用到了junit,所以需要在右角下载: junit-4.12.jar和hamcrest-all-1.3.jar导入到当前项目中 把...
  • 简单说,就是一次大操作由不同小操作组成,这些小操作分布在不同服务器,且属于不同应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质来说,分布式事务就是为了保证不同数据库...
  • 简单说,就是一次大操作由不同小操作组成,这些小操作分布在不同服务器,且属于不同应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质来说,分布式事务就是为了保证不同数据库...
  • jwx是开源的java公众号开发MVC框架,基于spring配置文件和微信消息或事件注解,通过微信下文处理一个或多个微信公众号服务请求。目的主要有两个,其一生封装微信请求xml消息为java实体对象,将返回对象转换为xml...
  • java开源包1

    千次下载 热门讨论 2013-06-28 09:14:34
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包12

    热门讨论 2013-06-28 10:14:45
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • Java资源包01

    2016-08-31 09:16:25
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包101

    2016-07-13 10:11:08
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包11

    热门讨论 2013-06-28 10:10:38
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包2

    热门讨论 2013-06-28 09:17:39
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包3

    热门讨论 2013-06-28 09:20:52
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包6

    热门讨论 2013-06-28 09:48:32
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包5

    热门讨论 2013-06-28 09:38:46
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包10

    热门讨论 2013-06-28 10:06:40
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包4

    热门讨论 2013-06-28 09:26:54
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • Java EE常用框架.xmind

    2020-06-19 16:08:35
    注解式:通过在执行的Java方法上放置相应的注解完成 Spring与Shiro整合 在web.xml配置拦截器 在Shiro配置文件上配置在web.xml对应的bean 配置安全管理器 配置自定义的realm Shiro过滤器 ...
  • java开源包8

    热门讨论 2013-06-28 09:55:26
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...
  • java开源包9

    热门讨论 2013-06-28 09:58:55
    ftp4j是一个FTP客户端Java类库,实现了FTP客户端应具有的大部分功能文件(包括上传和下 载),浏览远程FTP服务器上的目录和文件,创建、删除、重命,移动远程目录和文件。ftp4j提供多种方式连接到远程FTP服务器包括...

空空如也

空空如也

1 2 3 4
收藏数 74
精华内容 29
关键字:

java获取当前方法上的注解

java 订阅