自定义注解的应用

一、基本介绍

        注解(Annotation) 其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。在Java技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。其中三个基本的 Annotation:

  • @Override: 限定重写父类方法, 该注解只能用于方法
  • @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
  • @SuppressWarnings: 抑制编译器警告.

二、自定义注解

1、基本语法

1.注解的定义    

      定义新的 Annotation 类型使用 @interface 关键字(myeclipase有模板)

public @interface DbInfo {
      //内容
}

2.注解属性的声明  

      注解属性的作用是,原来写在配置文件中的信息,可以通过注解的属性进行描述。注解(Annotation) 的属性声明方式:String name();属性默认值声明方式:String name() default “xxx”;

public @interface MyAnnotation {
​
    //注解可以使用如下类型配置注解包含的信息
    String name();//字符串
    String password() default "123";//带默认值的字符串
    double age() default 12;//double型
    Gender gender() default Gender.FEMALE;//枚举型
    Class clazz();//类类型
    MyAnnotation2 my2();//注解类型,(在注解中包含注解)
    int[] arr() default {1,2,3};//一元数组类型
    Gender[] gs();

}
​
/*
​
 <x>
    <name>xxx</name>
    <y>
        <password>
    </y>
 </x>

*/

引用:

    @MyAnnotation(name="老张",age=37,gender=Gender.MALE,clazz=String.class,my2=@MyAnnotation2(name="xxx"),arr={2,3,4},gs={Gender.FEMALE,Gender.MALE})
    public void doaa(){

    }

附加:

public enum Gender {
    MALE,FEMALE;
}

注意:

特殊属性value:如果注解中有一个名称value的属性,那么使用注解时可以省略value=部分,如@MyAnnotation(“xxx")

public @interface MyAnnotation3 {
    String[] value();
}

在引用时

    //名称为value的属性可以直接赋值
    @MyAnnotation3("bb")
    public void dobb(){

    }

2、元注解

     元 Annotation指修饰Annotation的Annotation。JDK中定义了如下元Annotation:

1.@Retention

   @Retention 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留的域, @Rentention 包含一个 RetentionPolicy 类型的成员变量, 通过这个变量指定域。

RetentionPolicy.CLASS 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解. 这是默认值
RetentionPolicy.RUNTIME 编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注释
RetentionPolicy.SOURCE 编译器直接丢弃这种策略的注释

2.@Target

     @Target指定注解用于修饰类的哪个成员. @Target 包含了一个名为 value,类型为ElementType的成员变量。

如:指定某个注解注解只能用来修饰方法

@Target({ElementType.METHOD})
public @interface DbInfo {
​
}

那么在使用该注解时只能在方法中使用,如果不指定,那么在哪都能用(具体,查文档ElementType)

3.@Documented

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

4.@Inherited

            @Inherited: 被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation, 则其子类将自动具有该注解,即即使不写该注解,因为它继承于一个被该注解修饰的类,所以它依然有该注解内容。

如:

@Inherited
public @interface DbInfo {
​
    String url() default "jdbc:mysql://localhost:3306/test";
    String username() default "root";
    String password() default "root";

}

引用该注解的类:

public class JdbcUtils {
​
    @DbInfo(url="jdbc:mysql://localhost:3306/test",username="flx",password="root")
    public void aa(){

    }

}

继承该类的类:

public class JdbcUtils2 extends JdbcUtils {
​
    @Override
    public void aa() {//该方法中依然有父类中的注解
        // TODO Auto-generated method stub
        super.aa();
    }   
}

三、应用

1、通过注解的方法进行数据库的连接

自定义注解:

//java--->class--->jvm()
​
@Retention(RetentionPolicy.RUNTIME)//这句话一定要加,不然在程序运行时获取不到注解内容
public @interface DbInfo {
​
    String url() default "jdbc:mysql://localhost:3306/test";
    String username() default "root";
    String password() default "root";

}

数据库连接类:

public class JdbcUtils {
    @DbInfo(url="jdbc:mysql://localhost:3306/test",username="flx",password="root")
    public static Connection getConnection(String url,String username,String password){
        //在这里不写具体代码,该方法就是连接数据库的方法
        System.out.println(url);
        System.out.println(username);
        System.out.println(password);

        return null;
    }

}

通过反射机制获取注解中的内容:

public class Demo {
​
    /**
     * @param args
     * @throws Exception 
     * @throws SecurityException 
     */
    public static void main(String[] args) throws SecurityException, Exception {

        Class clazz = JdbcUtils.class;
        Method method = clazz.getMethod("getConnection", String.class,String.class,String.class);

        DbInfo di = method.getAnnotation(DbInfo.class);
        String url = di.url();
        String username = di.username();
        String password = di.password();


        method.invoke(null, url,username,password);//运行进行数据库连接的方法

​
    }
​
}

2、注入bean的属性

其中bean为:

public class Person {

    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

定义的注解为:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
​
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectPerson {
​
    String name();
​
    int age();
​
}

注入代码为:

public class PersonDao {
​
        //1.将其注入到属性中
    @InjectPerson(name="老王",age=23)
    private Person person;
​
    public Person getPerson() {
        return person;
    }
        
        //2.将其注入到set方法中
    @InjectPerson(name="老张",age=23)
    public void setPerson(Person person) {
        this.person = person;
    }

}

1.将其注入到属性中

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
​
public class Test2 {
​
    public static void main(String[] args) throws Exception {

        //1.得到需要注入的属性
        Field f = PersonDao.class.getDeclaredField("person");

        //2.得到属性需要的 类型
        Class clazz = f.getType();

        //3.创建person
        Person person = (Person) clazz.newInstance();

        //4.反射属性的注解,
        InjectPerson inject = f.getAnnotation(InjectPerson.class);

        //5.并用注解的信息填充person
        Method ms [] = inject.getClass().getMethods();
        for(Method m : ms){
            String methodName = m.getName();  //name( ) age()
            //看person对象上有没有注解与之对应的属性
            try{
                PropertyDescriptor pd = new PropertyDescriptor(methodName,Person.class);
                Method set = pd.getWriteMethod();  //setname setage
                set.invoke(person, m.invoke(inject, null));
            }catch (Exception e) {
                continue;
            }
        }

        //6.把person赋给dao
        PersonDao dao = new PersonDao();
        f.setAccessible(true);  //person
        f.set(dao, person);


        System.out.println(dao.getPerson().getAge());
        System.out.println(dao.getPerson().getName());

    }
}

2.将其注入到set方法中

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
​
public class Test {
​
    public static void main(String[] args) throws Exception {

        //1.得到要注入的属性
        PropertyDescriptor pd = new PropertyDescriptor("person",PersonDao.class);

        //2.得到要注入的属性需要的类型
        Class clazz = pd.getPropertyType();  //Person

        //3.创健属性需要的对象
        Object person = clazz.newInstance();

        //4.得到属性的写方法
        Method setPerosn = pd.getWriteMethod();

        //5.反射出方法上声明的注解
        InjectPerson inject = setPerosn.getAnnotation(InjectPerson.class);

        //6.得到注解上声明的信息,填充person对象
        Method[] methods = inject.getClass().getMethods();
        for(Method m : methods){
            String methodName = m.getName();  //name or age
            try{
                Field f = Person.class.getDeclaredField(methodName);
                Object value = m.invoke(inject, null);  //得到注解上配置的属性的值
                f.setAccessible(true);
                f.set(person, value);
            }catch (Exception e) {
                continue;
            }

        }


        //7.把填充了数据的person通过setPerson方法整到personDao对象上
        PersonDao dao = new PersonDao();
        setPerosn.invoke(dao, person);

        System.out.println(dao.getPerson().getName());

    }
​
}

猜你喜欢

转载自blog.csdn.net/qq_22172133/article/details/81174310