Java的注解是什么?及现实中的应用

1、注解是什么?

  1. 注解是往源代码中添加描述信息的机制,这些信息可由编译器测试和验证。
  2. 该信息后续可通过反射机制提取。然后根据描述,可定义不同的业务逻辑,实现丰富多彩的功能。
    注意:注解是静态的,是描述性的,没有任何功能。是注解处理器给了注解强大的力量。

2、注解怎么用?

  1. 关键词 @interface,表现也更新一个接口,属性按方法用。
  2. 注解2要素:要明确@Target(作用在类、还是方法)、@Retention(在哪一级,如SOURCE、CLASS、RUNTIME即程序执行时也可提出)。
  3. 注解中包含一些元素,处理注解时会用到(注解处理器)。
  4. 用注解处理器,根据标签填写业务逻辑,很强大。
  5. 注解常用对象:
    Object.getAnnotation():从目标对象获取注解对象。
    Field.getDeclaredAnnotations():从对象属性获取注解对象。
    anns[0] instanceof SQLInteger:注解类型判断。

如,我们定义一个注解。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
    
    
//    注解包含2个信息,且标记了类型,可由编译器检查,是比外部文档好用的地方
    public int id();
    public String description() default "no descriptino";
}

请看:

  1. @Target:指这是修饰什么的注解。这里是指描述方法的。
  2. @Retention:指注解保存在哪里。这里是保存到运行时,也就是会保存到class文件中。
  3. @interface:是关键字
  4. name():注解的属性表现的更新方法。
  5. 但看注解有什么用呢?没用!

注解处理器

有个业务场景,我写了个模块,需求里有n个场景需要覆盖。有没有办法检测我到底覆盖全场景了吗?可以使用上述的注解了。
业务代码:

public class PasswordUtils {
    
    
    @UseCase(id = 47, description = "Please must contain at least on numric")
    public boolean validatePassword(String password) {
    
    
        return (password.matches("\\w*\\d\\w*"));
    }

    @UseCase(id = 48)
    public String encryptPassword(String password) {
    
    
        return new StringBuffer(password).reverse().toString();
    }

    @UseCase(id = 49, description = "New password can't equal previously used ones")
    public boolean checkForNewPassword(List<String> prevPasswords, String password) {
    
    
        return !prevPasswords.contains(password);
    }
}

注解是静态的,还是没用啊。该注解处理器出厂了。

public class UseCaseTracker {
    
    

    public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
    
    
//        cl是目标类,找目标类的方法
        for (Method m : cl.getDeclaredMethods()) {
    
    
//            找目标类方法上指定类型的注解
            UseCase uc = m.getAnnotation(UseCase.class);
            if (uc != null) {
    
    
                System.out.println("Found Use Case:"+uc.id()+" "+uc.description());
                useCases.remove(new Integer(uc.id()));
            }
        }
        for (int i : useCases) {
    
    
            System.out.println("Warning:Missing use case=" + i);
        }

        /*通过这个例子,得到:
        1、注解与源代码关联起来了
        2、注解有结构化的数据
        3、注解可通过反射机制获取
        4、注解处理器可以实现业务逻辑,如这里的代码覆盖案例的情况  */

    }

    public static void main(String[] args) {
    
    
        List<Integer> useCases=new ArrayList<Integer>();
        Collections.addAll(useCases, 47, 48, 49,50);
        trackUseCases(useCases,PasswordUtils.class);
    }
}

输出:

Found Use Case:49 New password can't equal previously used ones
Found Use Case:47 Please must contain at least on numric
Found Use Case:48 no descriptino
Warning:Missing use case=50

3、注解的好处,相对xml配置文件?

	1.简化配置,不需要额外的解析工具
	2.编译器及可验证正确,防止xml手误,排查半天
	缺点:
	1.因为是编译进class文件,故修改了文件要重新编译;xml只重启应用即可;
	一般:
	1.可能修改的如数据源等,用xml配置;
	2.ioc用注解。

4、注解实例:

4.1.用注解标记测试用例覆盖度

见上述的例子。

4.2.用注解提起SQL的DDL

注解:

@Target(ElementType.TYPE) //只能注解class
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
    
    
    public String name() default "";
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
    
    
    String name() default "";
    Constrains constraints() default  @Constrains;
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
    
    
    int value() default 0;
    String name() default "";
    Constrains constraints() default @Constrains;
}

业务代码或配置:

@DBTable(name = "MEMBER")
public class Member {
    
    
    @SQLString(30) String firstName;
    @SQLString(50) String lastName;
    @SQLInteger Integer age;
    @SQLString(value = 30,constraints = @Constrains(primaryKey = true))
    String handle;
    static int memberCount;

    public String getHandle() {
    
    
        return handle;
    }

    public String getFirstName() {
    
    
        return firstName;
    }
    public String getLastName(){
    
    
        return  lastName;
    }
    public String toString(){
    
    
        return handle;
    }

    public Integer getAge() {
    
    
        return age;
    }
}

注解处理器:

public class TableCreator {
    
    


    public static void main(String[] args) throws Exception{
    
    
        if (args.length < 1) {
    
    
            System.out.println("Arguments:annotaed classes");
            System.exit(0);
        }

        for (String className : args) {
    
    
            Class<?> cl = Class.forName(className);
                /*从目标对象cl获取注解对象*/
                DBTable annoDbTable = cl.getAnnotation(DBTable.class);
                if (annoDbTable == null) {
    
    
                    System.out.println("No DBTable annotations in class "+className);
                    continue;
            }

            String tableName=annoDbTable.name();
            if(tableName.length()<1){
    
    
                tableName = cl.getName().toUpperCase();
            }
            System.out.println("tableName:"+tableName);


            List<String> columnDefs=new ArrayList<String>();
            for(Field field:cl.getDeclaredFields()){
    
    
                String columnName=null;
                Annotation[] anns=field.getDeclaredAnnotations();
                if(anns.length<1)
                    continue;

                if (anns[0] instanceof SQLInteger) {
    
    
                    SQLInteger sInt=(SQLInteger)anns[0];
                    if (sInt.name().length() < 1) {
    
    
                        columnName = field.getName().toUpperCase();
                    } else {
    
    
                        columnName=sInt.name();
                    }
                    columnDefs.add(columnName + " INT" + getConstraints(sInt.constraints()));
                }

                if (anns[0] instanceof SQLString) {
    
    
                    SQLString sString=(SQLString)anns[0];
                    if (sString.name().length() < 1) {
    
    
                        columnName = field.getName().toUpperCase();
                    } else {
    
    
                        columnName=sString.name();
                    }
                    columnDefs.add(columnName + " varchar(" + sString.value() + ")" + getConstraints(sString.constraints()));
                }
                StringBuilder createCommand=new StringBuilder("create table "+tableName+"(");
                for(String columnDef:columnDefs)
                    createCommand.append("\n " + columnDef + ",");

                String tableCreate = createCommand.substring(0, createCommand.length() - 1) + ");";
                System.out.println("Table creation sql for "+className+" is :\n"+tableCreate);

            }

        }
    }

    private static String getConstraints(Constrains con) {
    
    
        String constraints="";
        if(!con.allowNull()) constraints += " not null";
        if(!con.primaryKey()) constraints += " primary key";
        if(con.unique()) constraints += " unique";
        return constraints;
    }
}

输出:

Table creation sql for com.master.Member is :
create table MEMBER(
 FIRSTNAME varchar(30) primary key,
 LASTNAME varchar(50) primary key,
 AGE INT primary key,
 HANDLE varchar(30));

是不配合处理起可以衍生出精彩的功能!

5、注解spring框架中的应用

1.注解实现IOC

注册Bean

@Component("myServiceB")
public class ServiceB implements IService {
    
    
    @Value("serviceB")
    private String name;
    @Value("12")
    private int age;

    public ServiceB() {
    
    
        System.out.println("========New a ServiceB without parameters");
    }

    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;
    }


    @Override
    public String toString() {
    
    
        return this.name+";"+this.age;
    }
}

spring获取管理的Bean

public class Test {
    
    
    public static void main(String[] args) {
    
    
        ApplicationContext ac = new ClassPathXmlApplicationContext("ApplicationContext.xml");
        /*IService serviceA=(ServiceA)ac.getBean("myServiceA");
        System.out.println(serviceA);*/
        ServiceB serviceB = (ServiceB) ac.getBean("myServiceB");
        System.out.println(serviceB);
    }
}

就这么简单。

2.注解实现IOC的原理

实现过程分解的很细,但大概原理与上边的例子类似。
简介下别人的总结:
第一步,初始化时设置了Component类型过滤器;
第二步,根据指定扫描包扫描.class文件,生成Resource对象;
第三步、解析.class文件并注解归类,生成MetadataReader对象;
第四步、使用第一步的注解过滤器过滤出有@Component类;
第五步、生成BeanDefinition对象;
第六步、把BeanDefinition注册到Spring容器。以上是@Component注解原理,@Service、@Controller和@Repository上都有@Component修饰,所以原理是一样的。

参考:

https://www.cnblogs.com/wolf-bin/p/11667208.html
《think in java 》第四版

猜你喜欢

转载自blog.csdn.net/heroicpoem/article/details/104826320
今日推荐