zoukankan      html  css  js  c++  java
  • java的注解机制

    来源:http://www.cnblogs.com/Johness/archive/2013/04/17/3026689.html

    JDK1.5加入了对注解机制的支持,实际上我学习Java的时候就已经使用JDK1.6了,而且除了@Override和@SuppressWarnings(后者还是IDE给生成的……)之外没接触过其他的。

      进入公司前的面试,技术人员就问了我关于注解的问题,我就说可以生成chm手册……现在想起来真囧,注释和注解被我搞得完全一样了。

      

      使用注解主要是在需要使用Spring框架的时候,特别是使用SpringMVC。因为这时我们会发现它的强大之处:预处理。

      注解实际上相当于一种标记,它允许你在运行时(源码、文档、类文件我们就不讨论了)动态地对拥有该标记的成员进行操作。

      实现注解需要三个条件(我们讨论的是类似于Spring自动装配的高级应用):注解声明、使用注解的元素、操作使用注解元素的代码

      

      首先是注解声明,注解也是一种类型,我们要定义的话也需要编写代码,如下:

    复制代码
     1 package annotation;
     2 
     3 import java.lang.annotation.ElementType;
     4 import java.lang.annotation.Retention;
     5 import java.lang.annotation.RetentionPolicy;
     6 import java.lang.annotation.Target;
     7 
     8 /**
     9  * 自定义注解,用来配置方法
    10  * 
    11  * @author Johness
    12  *
    13  */
    14 @Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时依然存在
    15 @Target(ElementType.METHOD) // 表示注解可以被使用于方法上
    16 public @interface SayHiAnnotation {
    17     String paramValue() default "johness"; // 表示我的注解需要一个参数 名为"paramValue" 默认值为"johness"
    18 }
    复制代码

      然后是使用我们注解的元素:

    复制代码
     1 package element;
     2 
     3 import annotation.SayHiAnnotation;
     4 
     5 /**
     6  * 要使用SayHiAnnotation的元素所在类
     7  * 由于我们定义了只有方法才能使用我们的注解,我们就使用多个方法来进行测试
     8  * 
     9  * @author Johness
    10  *
    11  */
    12 public class SayHiEmlement {
    13 
    14     // 普通的方法
    15     public void SayHiDefault(String name){
    16         System.out.println("Hi, " + name);
    17     }
    18     
    19     // 使用注解并传入参数的方法
    20     @SayHiAnnotation(paramValue="Jack")
    21     public void SayHiAnnotation(String name){
    22         System.out.println("Hi, " + name);
    23     }
    24     
    25     // 使用注解并使用默认参数的方法
    26     @SayHiAnnotation
    27     public void SayHiAnnotationDefault(String name){
    28         System.out.println("Hi, " + name);
    29     }
    30 }
    复制代码

      最后,是我们的操作方法(值得一提的是虽然有一定的规范,但您大可不必去浪费精力,您只需要保证您的操作代码在您希望的时候执行即可):

    复制代码
     1 package Main;
     2 
     3 import java.lang.reflect.InvocationTargetException;
     4 import java.lang.reflect.Method;
     5 
     6 import element.SayHiEmlement;
     7 import annotation.SayHiAnnotation;
     8 
     9 public class AnnotionOperator {
    10     public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, ClassNotFoundException {
    11         SayHiEmlement element = new SayHiEmlement(); // 初始化一个实例,用于方法调用
    12         Method[] methods = SayHiEmlement.class.getDeclaredMethods(); // 获得所有方法
    13         
    14         for (Method method : methods) {
    15             SayHiAnnotation annotationTmp = null;
    16             if((annotationTmp = method.getAnnotation(SayHiAnnotation.class))!=null) // 检测是否使用了我们的注解
    17                 method.invoke(element,annotationTmp.paramValue()); // 如果使用了我们的注解,我们就把注解里的"paramValue"参数值作为方法参数来调用方法
    18             else
    19                 method.invoke(element, "Rose"); // 如果没有使用我们的注解,我们就需要使用普通的方式来调用方法了
    20         }
    21     }
    22 }
    复制代码

      结果为:Hi, Jack
          Hi, johness
          Hi, Rose

      可以看到,注解是进行预处理的很好方式(这里的预处理和编译原理有区别)!

      接下来我们看看Spring是如何使用注解机制完成自动装配的:

      

        首先是为了让Spring为我们自动装配要进行的操作,无外乎两种:继承org.springframework.web.context.support.SpringBeanAutowiringSupport类或者添加@Component/@Controller等注解并(只是使用注解方式需要)在Spring配置文件里声明context:component-scan元素。

        我说说继承方式是如何实现自动装配的,我们打开Spring源代码查看SpringBeanAutowiringSupport类。我们会发现以下语句:

    1 public SpringBeanAutowiringSupport() {
    2         processInjectionBasedOnCurrentContext(this);
    3     }

        众所周知,Java实例构造时会调用默认父类无参构造方法,Spring正是利用了这一点,让"操作元素的代码"得以执行!(我看到第一眼就震惊了!真是奇思妙想啊。果然,高手都要善于用Java来用Java)

        后面的我就不就不多说了,不过还是要纠正一些人的观点:说使用注解的自动装配来完成注入也需要setter。这明显是错误的嘛!我们看Spring注解装配(继承方式)的方法调用顺序: org.springframework.web.context.support.SpringBeanAutowiringSupport#SpringBeanAutowiringSupport=>

            org.springframework.web.context.support.SpringBeanAutowiringSupport#processInjectionBasedOnCurrentContext=>

          org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#processInjection=>

                   org.springframework.beans.factory.annotation.InjectionMetadata#Injection(继承,方法重写)。最后看看Injection方法的方法体:

    复制代码
     1 /**
     2          * Either this or {@link #getResourceToInject} needs to be overridden.
     3          */
     4         protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {
     5             if (this.isField) {
     6                 Field field = (Field) this.member;
     7                 ReflectionUtils.makeAccessible(field);
     8                 field.set(target, getResourceToInject(target, requestingBeanName));
     9             }
    10             else {
    11                 if (checkPropertySkipping(pvs)) {
    12                     return;
    13                 }
    14                 try {
    15                     Method method = (Method) this.member;
    16                     ReflectionUtils.makeAccessible(method);
    17                     method.invoke(target, getResourceToInject(target, requestingBeanName));
    18                 }
    19                 catch (InvocationTargetException ex) {
    20                     throw ex.getTargetException();
    21                 }
    22             }
    23         }
    复制代码

    虽然不完全,但可以基本判定此种自动装配是使用了java放射机制。

  • 相关阅读:
    解决运行docker命令要用sudo的问题
    python3 http.server 本地服务支持跨域
    Linux 命令速记本
    截取某段时间内的日志
    centos7 安装postgresql10
    centos 7 安装 mail
    centos7 mail
    centos7 mysql 5.7 官网下载tar安装
    修改storm ui 默认端口
    redis-trib构建集群
  • 原文地址:https://www.cnblogs.com/IntelligentBrain/p/5111317.html
Copyright © 2011-2022 走看看