理解Java注解及Spring的@Autowired是如何实现的

首先我们可以自己写一个注解:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnoSample {
    String value();
}

注解使用 @interface来标识。这个注解定义了一个属性value,只能作用于方法上,生命周期是运行时。

@Target用于指定可以放置注解的位置,这里指定的METHOD说明该注解只能放置到方法上面,还可以指定TYPE(类、接口、枚举类),FIELD实例,PARAMETER形参,CONSTRUCTOR构造器等等
@Retention用于定义注解的生命周期:SOURCE是编译期间丢弃。编译完成后,这些注释没有任何意义。CLASS类加载期间丢弃,这是默认值。RUNTIME不会丢弃,可以在运行时使用反射去获取

那么我们就使用该注解:

public class HelloWorld {

    @AnnoSample(value = "hello")
    public void hello(){
        System.out.println("hello,world");
    }
}

到此,创建一个注解并使用它我们已经完成了。

但是我们可以发现,该注解并没有带来任何的改变,有这个注解和没有这个注解区别不大。那么,我们需要知道,注解本身只能是被看作元数据,它不包含任何业务逻辑。注解更像是一个标签,一个声明,表面被注释的这个地方,将具有某种特定的逻辑

注解让这个方法有了一个标签,让我们知道应该去这个地方加一点逻辑。那么怎么去获取这个标签呢?
可以使用反射

  • 利用反射机制获取一个类的 Class 对象 通过这个 class 对象可以去获取他的每一个方法
  • method,或字段 Field 等等Method,Field 等类提供了类似于 getAnnotation() 的方法来获取这个字段或者方法的所有注解
  • 拿到注解之后,我们可以判断这个注解是否是我们要实现的注解,如果是则实现注解逻辑

具体实现如下:

public class Main {
    public static void main(String[] args) throws Exception {
        Class c=Class.forName("HelloWorld");
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            Annotation[] annotations = method.getDeclaredAnnotations();
            for (Annotation annotation : annotations) {
                if (annotation.annotationType()==AnnoSample.class) {
                    System.out.println(((AnnoSample)annotation).value());
                }
            }
        }
    }
}

上面代码就是,通过反射获得前面所写的HelloWorld类的Method数组并且遍历,并且遍历每个方法上的所有注解,如果找到我们需要判断的注解if (annotation.annotationType()==AnnoSample.class)那么就做一些逻辑处理,这里是打印出value的值

既然已经了解了注解的基础知识,那么我们去看看Spring的@Autowired是怎么实现的

@Autowired

看下源码:

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

	/**
	 * Declares whether the annotated dependency is required.
	 * <p>Defaults to {@code true}.
	 */
	boolean required() default true;

}

解读一下,该注解可以用在构造器、实例方法、形参、实例变量、注解上,生命周期是运行时。这里的 @Documented只是表明是否在Java doc中添加注解。
可以知道,@Autowired注解本身并没有什么特别的,重要的是应该是关于这个注解的特定逻辑。
逻辑所在的类,就在源码上面有提示了:

连续两次使用 Shift进行全局搜索查询这个类。

其中的buildAutowiringMetadata()方法是逻辑所在:

第一个箭头是得到当前的class,然后第二个箭头就是去判断 targetClass中的所有filed,查看是否有@Autowired。 下面的doWithLocalMethods和这里判断 filed类似。
通过了@Autowired判断之后,执行如下

currElements.add(new AutowiredFieldElement(field, required));

这是将该字段放入一个容器中去,因为使用了 @Autowired的实例变量/方法不止一个,所以全部找出之后进行判断。

在该方法的最后:

返回的是这个类和使用了@Autowired注解的实例集合。返回的是这个,那么下一步应该就是对其进行注入了。

注入的逻辑在postProcessProperties()方法中:

可以看到这个方法中的第一个就是调用 findAutowiringMetadata()方法,然后这个方法里面又调用了我们前面分析的buildAutowiringMetadata(),也就是说我们得到了类及其注解信息,然后开始调用下面的inject()方法进行注入

可以看到,对于字段,那么就调用反射类Field的set()方法设置值

field.set(target, getResourceToInject(target, requestingBeanName));

对于方法,就使用invoke去带入具体的参数值进行执行:

method.invoke(target, getResourceToInject(target, requestingBeanName));

getResourceToInject()方法的参数就是要注入的 bean 的名字,这个方法的功能就是根据这个 bean 的名字去拿到它。

到此这篇关于理解Java注解及Spring的@Autowired是如何实现的的文章就介绍到这了,更多相关java注解Spring的@Autowired内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 解决Springboot @Autowired 无法注入问题

    特别提醒:一定要注意文件结构 WebappApplication 一定要在包的最外层,否则Spring无法对所有的类进行托管,会造成@Autowired 无法注入. 1. 添加工具类获取在 Spring 中托管的 Bean (1)工具类 package com.common; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionE

  • 详解SpringBoot 多线程处理任务 无法@Autowired注入bean问题解决

    在多线程处理问题时,无法通过@Autowired注入bean,报空指针异常, 在线程中为了线程安全,是防注入的,如果要用到这个类,只能从bean工厂里拿个实例. 解决方法如下: 1.创建一个工具类代码: package com.hqgd.pms.common; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.spri

  • java 注解默认值操作

    我就废话不多说了,大家还是直接看代码吧~ package com.zejian.annotationdemo; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by wuzejian on 2017

  • 详解Spring @Autowired 注入小技巧

    今天和同事讨论到Spring自动注入时,发现有这么一段代码特别地困惑,当然大致的原理还是可以理解的,只不过以前从来没有这么用过.想到未来可能会用到,或者未来看别人写的代码时不至于花时间解决同样的困惑,所以小编还是觉得有必要研究记录一下. 一.同一类型注入多次为同一实例 首先让我们先看下这段代码是什么? @Autowired private XiaoMing xiaoming; @Autowired private XiaoMing wanger; XiaoMing.java package co

  • 因Spring AOP导致@Autowired依赖注入失败的解决方法

    发现问题: 之前用springAOP做了个操作日志记录,这次在往其他类上使用的时候,service一直注入失败,找了网上好多内容,发现大家都有类似的情况出现,但是又和自己的情况不太符合.后来总结自己的情况发现:方法为private修饰的,在AOP适配的时候会导致service注入失败,并且同一个service在其他的public方法中就没有这种情况,十分诡异. 解决过程: 结合查阅的资料进行了分析:在org.springframework.aop.support.AopUtils中: publi

  • Java中lombok的@Builder注解的解析与简单使用详解

    Lombok中@Builder用法 1.建造者模式简介:Builder 使用创建者模式又叫建造者模式.简单来说,就是一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程. 2.注解类Builder.java注释: * The builder annotation creates a so-called 'builder' aspect to the class that is annotated or the class  * that contains a mem

  • 解决SpringBoot项目使用多线程处理任务时无法通过@Autowired注入bean问题

    最近在做一个"温湿度控制"的项目,项目要求通过用户设定的温湿度数值和实时采集到的数值进行比对分析,因为数据的对比与分析是一个通过前端页面控制的定时任务,经理要求在用户开启定时任务时,单独开启一个线程进行数据的对比分析,并将采集到的温湿度数值存入数据库中的历史数据表,按照我们正常的逻辑应该是用户在请求开启定时任务时,前端页面通过调用后端接口,创建一个新的线程来执行定时任务,然后在线程类中使用 @Autowired 注解注入保存历史数据的service层,在线程类中调用service层保存

  • 理解Java注解及Spring的@Autowired是如何实现的

    首先我们可以自己写一个注解: @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AnnoSample { String value(); } 注解使用 @interface来标识.这个注解定义了一个属性value,只能作用于方法上,生命周期是运行时. @Target用于指定可以放置注解的位置,这里指定的METHOD说明该注解只能放置到方法上面,还可以指定TYPE(类.接口.枚举类),

  • 深入理解Java注解类型(@Annotation)

    Java注解是在JDK5时引入的新特性,鉴于目前大部分框架(如spring)都使用了注解简化代码并提高编码的效率,因此掌握并深入理解注解对于一个Java工程师是来说是很有必要的事.本篇我们将通过以下几个角度来分析注解的相关知识点 理解Java注解 实际上Java注解与普通修饰符(public.static.void等)的使用方式并没有多大区别,下面的例子是常见的注解: public class AnnotationDemo { //@Test注解修饰方法A @Test public static

  • 深入理解 Java注解及实例

     Java注解 什么是注解? Java中的注解就是Java源代码的元数据,也就是说注解是用来描述Java源代码的. 基本语法就是:@后面跟注解的名称. ①Override:标识某一个方法是否正确覆盖了它的父类的方法. ②Deprecated:表示已经不建议使用这个类成员了. 它是一个标记注解. ③SuppressWarnings:用来抑制警告信息 等等. 要更好的理解注解,我们可以自己写一个注解 @Target : 用来限制注解可以用到那几个地方.比方可以用到类上,可以用到方法胜都可以用@Tar

  • 深入理解Java注解的使用方法

    注解是jdk1.5新增的特性.大家都知道,jdk1.5在java的发展史上有着划时代的意义.而注解的出现,在某种程度上颠覆了框架的设计.比如,spring在注解出现后,改善了原先五大组件的模式,增加了基于注解的实现方式.现在重点讲讲注解的使用. 元注解: jdk1.5定义了4个元注解,元注解的作用是注解其他的注解. 1.@Retention 2.@Target 3.@Documented 4.@Inherited @Retention用于指明该注解存在的时机.参数有三个值可选:Retention

  • 使用Java注解模拟spring ioc容器过程解析

    使用注解,简单模拟spring ioc容器.通过注解给对象属性注入值. 项目结构 annotation 包,用于存放自定义注解 Component 注解表示该类为组件类,并需要声明名字 package priv.haidnor.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy;

  • Java注解Annotation与自定义注解详解

    一:Java注解简介 开发中经常使用到注解,在项目中也偶尔会见到过自定义注解,今天就来探讨一下这个注解是什么鬼,以及注解的应用场景和如何自定义注解. 下面列举开发中常见的注解 @Override:用于标识该方法继承自超类, 当父类的方法被删除或修改了,编译器会提示错误信息(我们最经常看到的toString()方法上总能看到这货) @Deprecated:表示该类或者该方法已经不推荐使用,已经过期了,如果用户还是要使用,会生成编译的警告 @SuppressWarnings:用于忽略的编译器警告信息

  • java注解的类型知识点总结

    提到java里的注解,和我们平时的注释还是有很大的区别,主要是作为java特性来使用的,跟我们常见的类是同一个使用的层面.关于java注解的类型,我们可以简单分为:自定义注解和元注解.其中元注解里的JDK又有5中注解的类型,下面一起来看看具体的内容讲解吧. 1.自定义注解 定义注解使用关键字: @interface // #1 定义注解 public @interface MyAnno1{ } 2.元注解 用于修饰注解的注解. JDK提供的5种元注解: (1)@Target:用于确定被修饰的自定

  • Spring中的注解之@Override和@Autowired

    一.Override 首先,@Override 注解是伪代码,表示子类重写父类的方法.这个注解不写也是可以的,但是写了有如下好处: 1. 可以当注释用,方便阅读(注解很重要的一个作用就是注释): 2. 编译器和 IDE 可以验证 @Override 下面的方法名是否是父类中所有的,如果没有的话就会报错.如果没有加 @Override ,而子类中的方法名又写错了,这个时候编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法. 下面来验证一下,首先有一个 IPay 的父类,包含一

  • Spring使用@Autowired注解静态实例对象方式

    目录 Spring @Autowired注解静态实例对象 问题 原因 解决方案 方式一 方式二 方式三 方式四 总结 @Autowired注解和静态方法 一.业务场景 二.原理剖析 三.解决方法 1.将@Autowire加到构造方法上 2.用@PostConstruct注解 Spring @Autowired注解静态实例对象 问题 最近项目小组在重新规划工程的业务缓存,其中涉及到部分代码重构,过程中发现有些工具类中的静态方法需要依赖别的对象实例(该实例已配置在xml成Spring bean,非静

  • Java @Async注解导致spring启动失败解决方案详解

    前言 在这篇文章里,最后总结处,我说了会讲讲循环依赖中,其中一个类添加@Async有可能会导致注入失败而抛异常的情况,今天就分析一下. 一.异常表现,抛出内容 1.1循环依赖的两个class 1.CycleService1 @Service public class CycleService1 { @Autowired private CycleService2 cycleService2; @WangAnno @Async public void doThings() { System.out

随机推荐