精华内容
下载资源
问答
  • 深入JAVA注解(Annotation):自定义注解

    万次阅读 多人点赞 2019-07-31 18:40:53
    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法。 元注解:  元注解的作用就是负责注解其他注解。Java5.0定义了4...

    一、基础知识:元注解

     

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法。

    元注解:

      元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
        1.@Target,
        2.@Retention,
        3.@Documented,
        4.@Inherited
      这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。

      @Target:

       @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

      作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

      取值(ElementType)有:

        1.CONSTRUCTOR:用于描述构造器
        2.FIELD:用于描述域
        3.LOCAL_VARIABLE:用于描述局部变量
        4.METHOD:用于描述方法
        5.PACKAGE:用于描述包
        6.PARAMETER:用于描述参数
        7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

      使用实例:  

    复制代码

    @Target(ElementType.TYPE)
    public @interface Table {
        /**
         * 数据表名称注解,默认值为类名称
         * @return
         */
        public String tableName() default "className";
    }
    
    @Target(ElementType.FIELD)
    public @interface NoDBColumn {
    
    }

    复制代码

      注解Table 可以用于注解类、接口(包括注解类型) 或enum声明,而注解NoDBColumn仅可用于注解类的成员变量。

      @Retention:

      @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

      作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

      取值(RetentionPoicy)有:

        1.SOURCE:在源文件中有效(即源文件保留)
        2.CLASS:在class文件中有效(即class保留)
        3.RUNTIME:在运行时有效(即运行时保留)

      Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。具体实例如下:

    复制代码

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Column {
        public String name() default "fieldName";
        public String setFuncName() default "setField";
        public String getFuncName() default "getField"; 
        public boolean defaultDBValue() default false;
    }

    复制代码

       Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理

      @Documented:

      @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

    复制代码

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Column {
        public String name() default "fieldName";
        public String setFuncName() default "setField";
        public String getFuncName() default "getField"; 
        public boolean defaultDBValue() default false;
    }

    复制代码

      @Inherited:

      @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

      注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

      当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

     

    实例代码:

    复制代码

    /**
     * 
     * @author peida
     *
     */
    @Inherited
    public @interface Greeting {
        public enum FontColor{ BULE,RED,GREEN};
        String name();
        FontColor fontColor() default FontColor.GREEN;
    }

    二、基础知识:自定义注解

     

    使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

      定义注解格式:
      public @interface 注解名 {定义体}

      注解参数的可支持数据类型:

        1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
        2.String类型
        3.Class类型
        4.enum类型
        5.Annotation类型
        6.以上所有类型的数组

      Annotation类型里面的参数该怎么设定: 
      第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;   
      第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;  
      第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。

      简单的自定义注解和使用注解实例:

    复制代码

    package annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 水果名称注解
     * @author peida
     *
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FruitName {
        String value() default "";
    }

    复制代码

    复制代码

    package annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 水果颜色注解
     * @author peida
     *
     */
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface FruitColor {
        /**
         * 颜色枚举
         * @author peida
         *
         */
        public enum Color{ BULE,RED,GREEN};
        
        /**
         * 颜色属性
         * @return
         */
        Color fruitColor() default Color.GREEN;
    
    }

    复制代码

    复制代码

    package annotation;
    
    import annotation.FruitColor.Color;
    
    public class Apple {
        
        @FruitName("Apple")
        private String appleName;
        
        @FruitColor(fruitColor=Color.RED)
        private String appleColor;
        
        
        
        
        public void setAppleColor(String appleColor) {
            this.appleColor = appleColor;
        }
        public String getAppleColor() {
            return appleColor;
        }
        
        
        public void setAppleName(String appleName) {
            this.appleName = appleName;
        }
        public String getAppleName() {
            return appleName;
        }
        
        public void displayName(){
            System.out.println("水果的名字是:苹果");
        }
    }

    复制代码


    注解元素的默认值:

      注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。

    三、自定义注解实例

         以上都是一些注解的基础知识,这里讲一下自定义注解的使用。一般,注解都是搭配反射的解析器共同工作的,然后利用反射机制查看类的注解内容。如下:

     

    复制代码

     1 package testAnnotation;
     2 
     3 import java.lang.annotation.Documented;
     4 import java.lang.annotation.Retention;
     5 import java.lang.annotation.RetentionPolicy;
     6 
     7 @Documented
     8 @Retention(RetentionPolicy.RUNTIME)
     9 public @interface Person{
    10     String name();
    11     int age();
    12 }

    复制代码

     

     package testAnnotation;
     2 
     3 @Person(name="xingoo",age=25)
     4 public class test3 {
     5     public static void print(Class c){
     6         System.out.println(c.getName());
     7         
     8         //java.lang.Class的getAnnotation方法,如果有注解,则返回注解。否则返回null
     9         Person person = (Person)c.getAnnotation(Person.class);
    10         
    11         if(person != null){
    12             System.out.println("name:"+person.name()+" age:"+person.age());
    13         }else{
    14             System.out.println("person unknown!");
    15         }
    16     }
    17     public static void main(String[] args){
    18         test3.print(test3.class);
    19     }
    20 }

     

    运行结果:

    testAnnotation.test3
    name:xingoo age:25

    接下来再讲一个工作中的例子就可以收篇啦!

    LoginVerify注解是用于对标注的方法在进行请求访问时进行登录判断。

     

    package com.newsee.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 是否已登录判断
     *
     */
    @Documented
    @Target(ElementType.METHOD)
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    public @interface LoginVerify {
    
    }

     

    ScanningLoginVerifyAnnotation里的scanning()方法被@PostConstruct修饰,说明它在服务器加载Servlet的时候运行,并且只会被服务器执行一次。

     

    这里再科普一下:

     

    @PostConstruct和@PreDestroy。这两个注解被用来修饰一个非静态的void()方法 。写法有如下两种方式:

    @PostConstruct

    Public void someMethod() {}                                                                       
    或者

    public @PostConstruct void someMethod(){}

    被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct会在构造函数之后,init()方法之前执行。PreDestroy()方法在destroy()方法执行之后执行

     

    scanning方法是在servlet加载完毕后获取所有被加载类,遍历其中的方法,如果有被LoginVerify注解修饰,则该方法名放到一个static的map中存储起来。

     

     

    package com.newsee.annotation;
    
    import java.io.IOException;
    import java.lang.reflect.Method;
    import javax.annotation.PostConstruct;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.core.io.support.ResourcePatternResolver;
    import org.springframework.stereotype.Component;
    import org.springframework.util.ClassUtils;
    import com.newsee.constant.LoginVerifyMapping;
    
    @Component
    public class ScanningLoginVerifyAnnotation {
    	private static final String PACKAGE_NAME = "com.newsee.face";
    
    	private static final String RESOURCE_PATTERN = "/**/*.class";
    
    	@PostConstruct
    	public void scanning() throws IOException, SecurityException,
    			ClassNotFoundException {
    		String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
    				+ ClassUtils.convertClassNameToResourcePath(PACKAGE_NAME)
    				+ RESOURCE_PATTERN;
    		ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
    		Resource[] resources = resourcePatternResolver.getResources(pattern);
    		for (Resource resource : resources) {
    			if (resource.isReadable()) {
    				String className = getClassName(resource.getURL().toString());
    				Class cls = ScanningRequestCodeAnnotation.class.getClassLoader().loadClass((className));
    				for (Method method : cls.getMethods()) {
    					LoginVerify requestCode = method.getAnnotation(LoginVerify.class);
    					if (requestCode != null) {
    						</span>LoginVerifyMapping.add(className + "."+ method.getName());
    					}
    				}
    			}
    		}
    	}
    
    	private String getClassName(String resourceUrl) {
    		String url = resourceUrl.replace("/", ".");
    		url = url.replace("\\", ".");
    		url = url.split("com.newsee")[1];
    		url = url.replace(".class", "");
    		return "com.newsee" + url.trim();
    	}
    }
    

    LoginVerifyMapping就是存放被LoginVerify注解修饰的方法名的。

    public class LoginVerifyMapping {
    	private static Map<String, Boolean> faceFunctionIsNeedLoginVerify = new HashMap<String, Boolean>();
    
    	public static void add(String functionName) {
    		faceFunctionIsNeedLoginVerify.put(functionName, Boolean.TRUE);
    	}
    
    	public static Boolean getFaceFunctionIsNeedLoginVerify(String functionName) {
    		return faceFunctionIsNeedLoginVerify.get(functionName);
    	}
    }

    以下方法就是请求过来时判断请求的方法是不是在LoginVerifyMapping中,如果是,则需要进行登录校验。

    private ResponseContent handleRequests(RequestContent requestContent) throws ClassNotFoundException,
    			NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
    			InvocationTargetException {
    		String requestCode = requestContent.getRequest().getHead().getNWCode();
    		String className = RequestCodeMapping.getClassName(requestCode);
    		String beanName = RequestCodeMapping.getBeanName(requestCode);
    		String functionName = RequestCodeMapping.getFunctionName(requestCode);
    		Boolean loginVerify = LoginVerifyMapping.getFaceFunctionIsNeedLoginVerify(className + "." + functionName);
    		if (loginVerify != null && loginVerify) {//需要进行登录校验
    			boolean isAuthenticated = SecurityUtils.getSubject().isAuthenticated();
    			if (!isAuthenticated) {
    				String exId=requestContent.getRequest().getHead().getNWExID();
    				SystemMobileTokenKeyServiceInter systemMobileTokenKeyServiceInter = (SystemMobileTokenKeyServiceInter) SpringContextUtil
    					.getBean("systemMobileTokenKeyServiceInter");
    				SystemMobileTokenKey systemMobileTokenKey=systemMobileTokenKeyServiceInter.getByExId(exId);
    				if(systemMobileTokenKey==null)
    					throw new BaseException(ResponseCodeEnum.NO_LOGIN);
    				Date keyTime = systemMobileTokenKey.getKeyTime();
    				if (System.currentTimeMillis() - keyTime.getTime() > 1000 * 60 * 60 * 24 * 3)
    					throw new BaseException(ResponseCodeEnum.NO_LOGIN);
    			}
    		}
    		if (className == null || beanName == null || functionName == null)
    			throw new BaseException(ResponseCodeEnum.REQUEST_CODE_NOT_EXIST);
    		Object object = SpringContextUtil.getBean(beanName);
    		Class cls = Class.forName(className);
    		Method method = cls.getMethod(functionName, RequestContent.class);
    		Object response = method.invoke(object, requestContent);
    		return (ResponseContent) response;
    	}
    }

     

     

     

     

    展开全文
  • 自定义注解

    2018-11-28 10:32:26
    自定义注解,元注解介绍,注解的反射.
  • Java中的注解以及自定义注解

    万次阅读 多人点赞 2019-05-30 16:21:53
    注意标红的反射两个字,反射在注解里相当重要,写完你的自定义注解类后没啥用,必须要用反射才能让它动起来!所以需要对反射有了解,感兴趣的小可爱可以看下这篇:Java中的反射机制介绍 (2)、从 JDK 5.0 开...

    铁子们,快扫码关注啦!或 wx搜索:“聊5毛钱的java”,关注可领取博主的Java学习视频+资料,保证都是干货

    1、Annotation(注解) 概述

    (1)、注解起到标识做用,比如Junit的@Test注解。

    Junit会在运行时检查方法上是否存在此注解,如果存在,就通过 反射 来运行你的方法。注意标红的反射两个字,反射在注解里相当重要,写完你的自定义注解类后没啥用,必须要用反射才能让它动起来!所以需要对反射有了解,感兴趣的小可爱可以看下这篇:用最直接的大白话来聊一聊Java中的反射机制

    (2)、从 JDK 5.0 开始,Java 增加了对 Annotation(注解)的支持。

    (3)、 注解其实就是代码里的特殊标记,它可以用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。用了注解以后,可以减少项目的配置文件,使代码看起来更优雅。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。

    (4)、注解可以代替配置文件会被大量的应用到实际项目中去,又由于注解看起很简洁,因此如果对注解的知识了解的不够的话,到项目应用中,有时候你会一头雾水,不知道咋回事,会比较懵。所以,学好注解非常重要

    (5)、掌握注解技术的要点: 如何定义注解、如何反射注解,并根据反射的注解信息,决定如何去运行类

    2、自定义 Annotation

    2.1、定义注解本身

    使用关键字@interface定义一个类而已,这个类就是注解。

    和之前定义一个类的不同是:之前定义类使用的是class关键字,现在定义注解使用的是@interface

    比如:

    public @interface MyAnnotation{ 
    
    }

    2.2、定义注解中的属性

    基本形式:类型 属性名称();    

                     比如:String name(); 

    特别注意:(1)属性值后边有一个括号!!!这个是和之前定义属性不一样的地方

                      (2)注解的属性的类型只能是:基本类型、String、Class、枚举、注解类型及以上类型的一维数组。

    定义注解属性的默认值:类型 属性名称() default 默认值;

                          比如:String name() default "zhangsan";

    举例:定义注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface MyAnnotation {
    
        String value() default "abc";
    
        String name() default "zhangsan";
    
    }

    注解属性定义完以后,使用注解:@MyAnnotation(value = "123",name = "lisi")

    举例:使用注解

    public class Test {
        
        @MyAnnotation(value = "123",name = "lisi")
        public static void test(){
            System.out.println("这是test");
        }
    
    }

    举例:利用反射获取方法上的注解,并获取对应的值

    public class Test {
    
        public static void main(String[] args) throws Exception {
    
            Class clazz = Class.forName("com.fours.intercepter.Test");
            Method[] ms = clazz.getMethods();
            for (Method m : ms) {
                if(m.isAnnotationPresent(MyAnnotation.class)){
                    String value = m.getAnnotation(MyAnnotation.class).value();
                    String name = m.getAnnotation(MyAnnotation.class).name();
                    System.out.println("value:"+value);
                    System.out.println("name:"+name);
                }
            }
        }
    
        @MyAnnotation(value = "123",name = "lisi")
        public static void test(){
            System.out.println("这是test");
        }
    
    }

    最后看下输出打印的结果

    可以看到,我们自定义个一个注解,然后在方法上使用了自己的注解,最后通过反射拿到这个方法上的注解和属性值

    由于这里只是个demo,所以只是拿到值后进行了打印,并没有一些复杂的操作

    但是,在实际应用中,拿到了方法上自定义的注解和属性值后,那就可以根据你具体的业务逻辑进行一些对应的操作

    等下咱们会用自定义的注解来模拟实现一个 @Test单元测试的功能

    2.3、注解中的特殊属性

    (1)、特殊属性value:如果注解中只有一个属性,而且这个属性的名称是value的话,那么使用注解时可以省略value=部分,可以直接写成这样@MyAnnotation(“xxx");

    (2)、特殊类型[] value():如果注解中只有一个属性,而且这个属性名称是value且数据类型是数组,那么
    使用方式:四种都ok,根据情况而定
    @MyAnnotationDemo1(value={"a","b"})
    @MyAnnotationDemo1({"a","b"})
    @MyAnnotationDemo1({"a"})
    @MyAnnotationDemo1("a")

    以上就是注解的基本语法了,下面通过代码写一个真实的小案例,来感受一下注解

    3、写一个自定义注解的真实案例

    了解了上述的内容后,咱们按照上边介绍的语法,开始自定义一个注解来模拟实现 @Test单元测试的功能

    package com.cj.study.annotation.app1;
    
    public @interface MyTest {
    	
    }
    
    package com.cj.study.annotation.app1;
    
    public class DemoTest1 {
    	
    	@MyTest
    	public void test1(){
    		System.out.println("test1执行了");
    	}
    	
    	public void test2(){
    		System.out.println("test2执行了");
    	}
    }
    
    package com.cj.study.annotation.app1;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    //反射注解:
    	//取得类的字节码
    	//反射其中的成员,此处就是方法成员
    	//看谁的上面有MyTest注解
    	//谁有,就执行谁
    public class MyJunitRunner {
    
    	public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
    		//取得类的字节码
    		Class clazz = DemoTest1.class;
    		//反射其中的成员,此处就是方法成员
    		Method methods[] = clazz.getMethods();//得到DemoTest1中的所有公有的方法
    		//看谁的上面有MyTest注解
    		for(Method m:methods){
    			//谁有,就执行谁
    			boolean b = m.isAnnotationPresent(MyTest.class);
    			System.out.println(b+"==="+m.getName());
    			if(b){
    				m.invoke(clazz.newInstance(), null);
    			}
    		}
    	}
    
    }
    

    如果运行结果出现test1方法执行了,test2方法没执行的话,就对了。

    运行看下运行结果:

    但是从结果可以看出和咱们预期的并不一样,那到底怎么回事呢?

    原因是:定义注解的时候除了上边说的语法,还需要一个东西,那就是“元注解”

    那什么是元注解呢?

    简单的来说服务于注解的注解就是元注解,它主要用来标识你写的注解保留范围(作用范围)以及出现的位置

    JDK中定义了四种元注解:

    @Retention:注解的保留范围,是个枚举,有如下可选值
            RetentionPolicy.SOURCE:注解存在于源文件中
            RetentionPolicy.CLASS:注解存在于源字节码文件中
            RetentionPolicy.RUNTIME:注解存在于运行时

    @Target:注解出现的位置(比如字段上、方法上等),也是个枚举,有如下可选值

            ElementType.TYPE

            ElementType.FIELD:字段

            ElementType.METHOD:方法

            ElementType.PARAMETER

            ElementType.CONSTRUCTOR

            ElementType.LOCAL_VARIABLE

            ElementType.ANNOTATION_TYPE

            ElementType.PACKAGE

            ElementType.TYPE_PARAMETER

            ElementType.TYPE_USE

    @Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档.

    @Inherited: 被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解

    常用的是前两种,了解了元注解后,下面把咱们的代码加上元注解再试一下

    package com.cj.study.annotation.app1;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)//注解存在于运行时
    @Target(ElementType.METHOD)//说明MyTest注解只能用在方法上
    public @interface MyTest {
    	
    }
    package com.cj.study.annotation.app1;
    
    public class DemoTest1 {
    	
    	@MyTest
    	public void test1(){
    		System.out.println("test1执行了");
    	}
    	
    	public void test2(){
    		System.out.println("test2执行了");
    	}
    }
    
    package com.cj.study.annotation.app1;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    //反射注解:
    	//取得类的字节码
    	//反射其中的成员,此处就是方法成员
    	//看谁的上面有MyTest注解
    	//谁有,就执行谁
    public class MyJunitRunner {
    
    	public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException {
    		//取得类的字节码
    		Class clazz = DemoTest1.class;
    		//反射其中的成员,此处就是方法成员
    		Method methods[] = clazz.getMethods();//得到DemoTest1中的所有公有的方法
    		//看谁的上面有MyTest注解
    		for(Method m:methods){
    			//谁有,就执行谁
    			boolean b = m.isAnnotationPresent(MyTest.class);
    			System.out.println(b+"==="+m.getName());
    			if(b){
    				m.invoke(clazz.newInstance(), null);
    			}
    		}
    	}
    
    }
    

    运行结果

    发现test1方法执行了, test2方法没执行,和预期的一样。

    OK,以上就是本人对注解的一些简单的理解和总结,欢迎大家一起留言一起学习

    铁子们,如果觉得文章对你有所帮助,可以点关注,点赞

    也可以关注下公众号:扫码或 wx搜索:“聊5毛钱的java”,欢迎一起学习交流,关注公众号可领取博主的Java学习视频+资料,保证都是干货

    3Q~

    展开全文
  • 自定义注解需要注意 元注解 使用自定义注解 解析注解 自定义注解需要注意 1-使用@interface来定义注解 2-成员变量使用的是无参数、无异常的方式进行声明 例如 想要声明变量,正常方式是String name,而注解中...

     

    目录

    自定义注解需要注意

    元注解

    使用自定义注解 

    解析注解 

    自定义注解工作中的使用 多数据源的动态切换 


    自定义注解需要注意

    1-使用@interface来定义注解

    2-成员变量使用的是无参数、无异常的方式进行声明 例如 想要声明变量,正常方式是String name,而注解中需要 String name();来定义成员变量

    3-使用default来给成员变量设置默认值

    4-成员变量的类型。可以是基本数据类型。还可以是String ,class ,annotation ,enumerate

    5-如果注解中只有一个成员变量,则必须起名为 value(),这样的话用的时候可以忽略 变量名 = 

    6-可以没有任何成员变量,没有成员变量的成为标识注解

    元注解

     @Tarage

    @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

    @Retention

    生命周期

    @Retention定义了该Annotation被保留的时间长短:

    1.某些Annotation仅出现在源代码中,而被编译器丢弃;

    2.另一些却被编译在class文件中,注解保留在class文件中,在加载到JVM虚拟机时丢弃,这是默认行为,所以没有用Retention注解的注解,都会采用这种策略

    3.而另一些在class被装载时将被读取,注解保留在程序运行期间,此时可以通过反射获得定义在某个类上的所有注解

    运行时注解例如@Autowired

    使用自定义注解 

     

    解析注解 

    找到类上的注解。

    1、通过反射获取到类。

    2、判断类上是否含有注解

    3、获取注解 类,得到对应的成员变量

    获取方法上的注解 

    1、通过反射获取到类,

    2、获取到类中所有的方法 集合

    3、循环方法集合

    自定义注解工作中的使用 多数据源的动态切换 

    https://blog.csdn.net/qq_32786139/article/details/107064413这是一个多数据源的切换示例。里面用的是Aop面向切面,来切注解。然后通过反射,解析注解。进行多数据源的切换操作 

    展开全文
  • java自定义注解是什么,难吗?在没有接触过自定义注解之前,我会认为,哇,注解好厉害,就@加上一段字符就可以实现各种功能,告诉你们,spring的@Controller @Service @Commont 其实只是名字不同,功能完全一样,不...

    0a4a2cb6a50f1afa441cb0000c14c8c0.png

    java自定义注解是什么,难吗?

    在没有接触过自定义注解之前,我会认为,哇,注解好厉害,就@加上一段字符就可以实现各种功能,告诉你们,spring的@Controller @Service @Commont 其实只是名字不同,功能完全一样,不信你试试,哈哈。或者扒一下源码。说回到正题,自定义注解是什么,难吗。自定义注解基本分为,注释到方法上的,注释到实体私有属性的,注解到形参的,大多经常使用的就这样了吧。

    先说注解到方法上的,能干嘛,怎么干,比如你自定义了一个注解,想要让他实现对系统中某些接口签名校验绕过,也就是加了你这个注解,该方法不会进行签名校验。先说下签名校验一般会怎么做,一般你们是不是定义一个拦截器,拦截所有请求,然后取header的签名值和自己把请求的参数拿出来的值算完之后进行比较,相同校验就通过,不同就不通过,这时候,老板说某个接口不需要签名校验,你可以拿到方法名做白名单过滤,但是越来越多的方法需要白名单呢,这时候,加个注解吧,放在方法上,拦截器在校验时,判断方法上有没有不需签名校验的注解,如果有,直接就过了,没有再去校验就OK了。

    这是一种方法,在拦截器层面使用注解,你也可以在aop中使用,去切那些注释了某些注解的方法,再拿到注解上的一些属性做操作。比如想记录日志的自定义Log注解。

    未完待续。。。先写代码去了

    展开全文
  • 我们常常有扫描项目里带有指定注解的class, 下面是利用spring扫描自定义注解的方法, 还是比较灵活的我这里将扫描到的class放到map, 你可以放到其他地方,以便后期使用import lombok.extern.slf4j.Slf4j;import org....
  • 除了Java内置注解,我们也可以自定义注解。以下就是一个自定义注解的例子:@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface Msg {String DEFAULT_MSG...
  • 自定义注解上需要添加 @Retention(RetentionPolicy.RUNTIME)注解 否则项目启动does not have runtime retention
  • 1. 自定义注解简单说明2. 自定义注解-简单应用1. 自定义注解简单说明1. 对于Java中的注解可以看做是一个标签。这个标签可以用来标注在某一个方法上。 2. 不管是Java自带的注解,还是我们自定义的注解-->这些注解...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,947
精华内容 11,178
关键字:

自定义注解