autowired_autowired注解 - CSDN
精华内容
参与话题
  • @Autowired用法详解

    万次阅读 多人点赞 2019-09-02 22:05:41
    @Autowire是用在JavaBean中的注解,目的只是为了自动生成属性的getter和setter方法而不用手写。 而autowire似乎跟@Autowire没多大的关系,autowire是在xml文件中进行配置的,可以设置byName、byType、constructor和...
    • 首先要知道另一个东西,default-autowire,它是在xml文件中进行配置的,可以设置为byName、byType、constructor和autodetect;比如byName,不用显式的在bean中写出依赖的对象,它会自动的匹配其它bean中id名与本bean的set**相同的,并自动装载。
    • @Autowired是用在JavaBean中的注解,通过byType形式,用来给指定的字段或方法注入所需的外部资源。
    • 两者的功能是一样的,就是能减少或者消除属性或构造器参数的设置,只是配置地方不一样而已。
    • autowire四种模式的区别:
      这里写图片描述
    • 先看一下bean实例化和@Autowired装配过程:
    1. 一切都是从bean工厂的getBean方法开始的,一旦该方法调用总会返回一个bean实例,无论当前是否存在,不存在就实例化一个并装配,否则直接返回。(Spring MVC是在什么时候开始执行bean的实例化过程的呢?其实就在组件扫描完成之后)

    2. 实例化和装配过程中会多次递归调用getBean方法来解决类之间的依赖。

    3. Spring几乎考虑了所有可能性,所以方法特别复杂但完整有条理。

    4. @Autowired最终是根据类型来查找和装配元素的,但是我们设置了<beans default-autowire="byName"/>后会影响最终的类型匹配查找。因为在前面有根据BeanDefinition的autowire类型设置PropertyValue值得一步,其中会有新实例的创建和注册。就是那个autowireByName方法。

    • 下面通过@Autowired来说明一下用法

    • Setter 方法中的 @Autowired
      你可以在 JavaBean中的 setter 方法中使用 @Autowired 注解。当 Spring遇到一个在 setter 方法中使用的 @Autowired 注解,它会在方法中执行 byType 自动装配。
      这里是 TextEditor.java 文件的内容:

    package com.tutorialspoint;
    import org.springframework.beans.factory.annotation.Autowired;
    public class TextEditor {
       private SpellChecker spellChecker;
       @Autowired
       public void setSpellChecker( SpellChecker spellChecker ){
          this.spellChecker = spellChecker;
       }
       public SpellChecker getSpellChecker( ) {
          return spellChecker;
       }
       public void spellCheck() {
          spellChecker.checkSpelling();
       }
    }
    

    下面是另一个依赖的类文件 SpellChecker.java 的内容:

    package com.tutorialspoint;
    public class SpellChecker {
       public SpellChecker(){
          System.out.println("Inside SpellChecker constructor." );
       }
       public void checkSpelling(){
          System.out.println("Inside checkSpelling." );
       }  
    }
    

    下面是 MainApp.java 文件的内容:

    package com.tutorialspoint;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    public class MainApp {
       public static void main(String[] args) {
          ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
          TextEditor te = (TextEditor) context.getBean("textEditor");
          te.spellCheck();
       }
    }
    

    下面是配置文件 Beans.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
       <context:annotation-config/>
    
       <!-- Definition for textEditor bean without constructor-arg  -->
       <bean id="textEditor" class="com.tutorialspoint.TextEditor">
       </bean>
    
       <!-- Definition for spellChecker bean -->
       <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
       </bean>
    
    </beans>
    

    一旦你已经完成的创建了源文件和 bean 配置文件,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:

    Inside SpellChecker constructor.
    Inside checkSpelling.

    • 属性中的 @Autowired
      你可以在属性中使用 @Autowired 注解来除去 setter 方法。当时使用 为自动连接属性传递的时候,Spring 会将这些传递过来的值或者引用自动分配给那些属性。所以利用在属性中 @Autowired 的用法,你的 TextEditor.java 文件将变成如下所示:
    package com.tutorialspoint;
    import org.springframework.beans.factory.annotation.Autowired;
    public class TextEditor {
       @Autowired
       private SpellChecker spellChecker;
       public TextEditor() {
          System.out.println("Inside TextEditor constructor." );
       }  
       public SpellChecker getSpellChecker( ){
          return spellChecker;
       }  
       public void spellCheck(){
          spellChecker.checkSpelling();
       }
    }
    

    下面是配置文件 Beans.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
       <context:annotation-config/>
    
       <!-- Definition for textEditor bean -->
       <bean id="textEditor" class="com.tutorialspoint.TextEditor">
       </bean>
    
       <!-- Definition for spellChecker bean -->
       <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
       </bean>
    
    </beans>
    

    一旦你在源文件和 bean 配置文件中完成了上面两处改变,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:

    Inside TextEditor constructor.
    Inside SpellChecker constructor.
    Inside checkSpelling.

    • 构造函数中的 @Autowired
      你也可以在构造函数中使用 @Autowired。一个构造函数 @Autowired 说明当创建 bean 时,即使在 XML 文件中没有使用 元素配置 bean ,构造函数也会被自动连接。让我们检查一下下面的示例。

    这里是 TextEditor.java 文件的内容:

    package com.tutorialspoint;
    import org.springframework.beans.factory.annotation.Autowired;
    public class TextEditor {
       private SpellChecker spellChecker;
       @Autowired
       public TextEditor(SpellChecker spellChecker){
          System.out.println("Inside TextEditor constructor." );
          this.spellChecker = spellChecker;
       }
       public void spellCheck(){
          spellChecker.checkSpelling();
       }
    }
    

    下面是配置文件 Beans.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
       <context:annotation-config/>
    
       <!-- Definition for textEditor bean without constructor-arg  -->
       <bean id="textEditor" class="com.tutorialspoint.TextEditor">
       </bean>
    
       <!-- Definition for spellChecker bean -->
       <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
       </bean>
    
    </beans>
    

    一旦你在源文件和 bean 配置文件中完成了上面两处改变,让我们运行一下应用程序。如果你的应用程序一切都正常的话,这将会输出以下消息:

    Inside TextEditor constructor.
    Inside SpellChecker constructor.
    Inside checkSpelling.

    • @Autowired 的(required=false)选项
      默认情况下,@Autowired 注解意味着依赖是必须的,它类似于 @Required 注解,然而,你可以使用 @Autowired 的 (required=false) 选项关闭默认行为。

    即使你不为 age 属性传递任何参数,下面的示例也会成功运行,但是对于 name 属性则需要一个参数。你可以自己尝试一下这个示例,因为除了只有 Student.java 文件被修改以外,它和 @Required 注解示例是相似的。

    package com.tutorialspoint;
    import org.springframework.beans.factory.annotation.Autowired;
    public class Student {
       private Integer age;
       private String name;
       @Autowired(required=false)
       public void setAge(Integer age) {
          this.age = age;
       }  
       public Integer getAge() {
          return age;
       }
       @Autowired
       public void setName(String name) {
          this.name = name;
       }   
       public String getName() {
          return name;
       }
    }
    

    Quote:
    http://my.oschina.net/HeliosFly/blog/203902
    http://wiki.jikexueyuan.com/project/spring/annotation-based-configuration/spring-autowired-annotation.html

    展开全文
  • @Autowired 的作用是什么?

    万次阅读 多人点赞 2020-02-04 15:45:19
    @Autowired 的作用是什么? @Autowired 是一个注释,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。 @Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 ...

    @Autowired 的作用是什么?

    @Autowired 是一个注释,它可以对类成员变量、方法及构造函数进行标注,让 spring 完成 bean 自动装配的工作。
    @Autowired 默认是按照类去匹配,配合 @Qualifier 指定按照名称去装配 bean。

    常见用法

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    import blog.service.ArticleService;
    import blog.service.TagService;
    import blog.service.TypeService;
    
    @Controller
    public class TestController {
    
    	//成员属性字段使用 @Autowired,无需字段的 set 方法
    	@Autowired
    	private TypeService typeService;
    	
    	
    	//set 方法使用 @Autowired
    	private ArticleService articleService;
    	@Autowired
    	public void setArticleService(ArticleService articleService) {
    		this.articleService = articleService;
    	}
    
    	//构造方法使用 @Autowired
    	private TagService tagService;
    	@Autowired
    	public TestController(TagService tagService) {
    		this.tagService = tagService; 
    	}
    	
    }

     


    【Java面试题与答案】整理推荐

     

    展开全文
  • @Resource与@Autowired注解的区别

    万次阅读 多人点赞 2020-07-03 15:24:45
    同事:没错,但是现在都使用@Autowired。我:我研究一下。 在大学,学习J2EE实训时一直使用的是@Resource注解,后来我就养成习惯了。现在对这两个注解做一下解释: @Resource默认按照名称方式进行bean匹配,@A

    一、写本博文的原因

     

    年初刚加入到现在的项目时,在使用注解时我用的@Resource。后来,同事:你怎么使用@Resource注解?我:使用它有错吗?同事:没错,但是现在都使用@Autowired。我:我研究一下。

    在大学,学习J2EE实训时一直使用的是@Resource注解,后来我就养成习惯了。现在对这两个注解做一下解释:

     

    • @Resource默认按照名称方式进行bean匹配,@Autowired默认按照类型方式进行bean匹配
    • @Resource(import javax.annotation.Resource;)是J2EE的注解,@Autowired( import org.springframework.beans.factory.annotation.Autowired;)是Spring的注解

    @Autowired注解默认按类型(byType)装配依赖对象,它要求依赖对象必须存在;若允许依赖对象不存在,可设:@Autowired(required = false) 。
    @Autowired也可以按名称(byName)装配,需要结合@Qualifier:
    @Autowired
    @Qualifier("manImpl")

    @Resource默认按名称(byName)装配,也可按类型装配,装配顺序如下: 

    • 如果同时指定name(@Resource(name=""))和type(@Resource(type="")),则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常  
    • 如果指定name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常  
    • 如果指定type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常  
    • 如果既没指定name,又没指定type,则默认按照byName方式进行装配;如果匹配不到,则回退为一个原始类型进行匹配,如果匹配则自动装配。

    Spring属于第三方的,J2EE是Java自己的东西。使用@Resource可以减少代码和Spring之间的耦合。

     

    二、@Resource注入

    现在有一个接口Human和两个实现类ManImpl、WomanImpl,在service层的一个bean中要引用了接口Human,这种情况处理如下:

    接口Human

     

    package testwebapp.com.wangzuojia.service;
    
    public interface Human {
    	
    	public void speak();
    	
    	public void walk();
    }
    


    实现类ManImpl

     

     

    package testwebapp.com.wangzuojia.service.impl;
    
    import org.springframework.stereotype.Service;
    
    import testwebapp.com.wangzuojia.service.Human;
    
    @Service
    public class ManImpl implements Human {
    
    	public void speak() {
    		System.out.println(" man speaking!");
    
    	}
    
    	public void walk() {
    		System.out.println(" man walking!");
    
    	}
    
    }

     

     

    实现类WomanImpl

     

    package testwebapp.com.wangzuojia.service.impl;
    
    import org.springframework.stereotype.Service;
    
    import testwebapp.com.wangzuojia.service.Human;
    
    @Service
    public class WomanImpl implements Human {
    
    	public void speak() {
    		System.out.println(" woman speaking!");
    
    	}
    
    	public void walk() {
    		System.out.println(" woman walking!");
    
    	}
    
    }

     

     

    主调类SequenceServiceImpl

    package testwebapp.com.wangzuojia.service.impl;
    
    import java.util.Map;
    
    import javax.annotation.Resource;
    
    import org.springframework.stereotype.Service;
    
    import testwebapp.com.wangzuojia.dao.SequenceMapper;
    import testwebapp.com.wangzuojia.service.Human;
    import testwebapp.com.wangzuojia.service.SequenceService;
    
    @Service
    public class SequenceServiceImpl implements SequenceService {
    
    	@Resource
    	private SequenceMapper sequenceMapper;
    	public void generateId(Map<String, String> map) {
    		sequenceMapper.generateId(map);
    		
    	}
    	//起服务此处会报错
    	@Resource
    	private Human human;
    
    }

     

    这时候启动tomcat会包如下错误:

     

     

    严重: Exception sendingcontext initialized event to listener instance of classorg.springframework.web.context.ContextLoaderListenerorg.springframework.beans.factory.BeanCreationException: Error creating beanwith name 'sequenceServiceImpl': Injection of resource dependencies failed;nested exception isorg.springframework.beans.factory.NoUniqueBeanDefinitionException: Noqualifying bean of type [testwebapp.com.wangzuojia.service.Human] is defined:expected single matching beanbut found 2: manImpl,womanImpl atorg.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:311) atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) atorg.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) atorg.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) atorg.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) atorg.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) atorg.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) atorg.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) atorg.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:838) atorg.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537) atorg.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:446) atorg.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:328) atorg.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107) atorg.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4717) atorg.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5179)atorg.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) atorg.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1404) atorg.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1394) atjava.util.concurrent.FutureTask.run(FutureTask.java:266) atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)atjava.lang.Thread.run(Thread.java:745) Caused by:org.springframework.beans.factory.NoUniqueBeanDefinitionException: Noqualifying bean of type [testwebapp.com.wangzuojia.service.Human] is defined: expectedsingle matching bean but found 2: manImpl,womanImpl atorg.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1126) atorg.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014) atorg.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:508) atorg.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:486) atorg.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:615) atorg.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169) atorg.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) atorg.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:308) ...22 more

     

    报错的地方给我们提示了:but found 2: manImpl,womanImpl      意思是Human有两个实现类。解决方案如下:

    package testwebapp.com.wangzuojia.service.impl;
    
    import java.util.Map;
    
    import javax.annotation.Resource;
    
    import org.springframework.stereotype.Service;
    
    import testwebapp.com.wangzuojia.dao.SequenceMapper;
    import testwebapp.com.wangzuojia.service.Human;
    import testwebapp.com.wangzuojia.service.SequenceService;
    
    @Service
    public class SequenceServiceImpl implements SequenceService {
    
    	@Resource
    	private SequenceMapper sequenceMapper;
    	public void generateId(Map<String, String> map) {
    		sequenceMapper.generateId(map);
    		
    	}
    	
    	@Resource(name = "manImpl")//注意是manImpl不是ManImpl,因为使用@Service,容器为我们创建bean时默认类名首字母小写
    	private Human human;
    
    }

     

    这样启动服务就不会报错了。如果是使用的@Autowired注解,要配上@Qualifier("manImpl"),代码如下:

     

    package testwebapp.com.wangzuojia.service.impl;
    
    import java.util.Map;
    
    import javax.annotation.Resource;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Service;
    
    import testwebapp.com.wangzuojia.dao.SequenceMapper;
    import testwebapp.com.wangzuojia.service.Human;
    import testwebapp.com.wangzuojia.service.SequenceService;
    
    @Service
    public class SequenceServiceImpl implements SequenceService {
    
    	@Resource
    	private SequenceMapper sequenceMapper;
    	public void generateId(Map<String, String> map) {
    		sequenceMapper.generateId(map);
    		
    	}
    	
    	@Autowired
    	@Qualifier("manImpl")
    	private Human human;
    
    }

     

     

     

     

     

    展开全文
  • [spring] 注解@Autowired是如何实现的

    万次阅读 多人点赞 2020-09-30 15:56:59
    @Autowired注解用法 @Autowired注解的作用到底是什么 @Autowired注解是如何实现的 例子注解@Override 自己实现一个注解 @Autowired注解实现逻辑分析 问题 注解的有效周期是什么? 注入的bean和用它的bean的...

    Table of Contents

    前言

    @Autowired注解用法

    @Autowired注解的作用到底是什么

    @Autowired注解是如何实现的

    例子注解@Override

    自己实现一个注解

    @Autowired注解实现逻辑分析

    问题

    注解的有效周期是什么?

    注入的bean和用它的bean的关系是如何维护的?


    前言

    使用spring开发时,进行配置主要有两种方式,一是xml的方式,二是java config的方式。spring技术自身也在不断的发展和改变,从当前springboot的火热程度来看,java config的应用是越来越广泛了,在使用java config的过程当中,我们不可避免的会有各种各样的注解打交道,其中,我们使用最多的注解应该就是@Autowired注解了。这个注解的功能就是为我们注入一个定义好的bean。那么,这个注解除了我们常用的属性注入方式之外还有哪些使用方式呢?它在代码层面又是怎么实现的呢?这是本篇文章着重想讨论的问题。

    @Autowired注解用法

    在分析这个注解的实现原理之前,我们不妨先来回顾一下@Autowired注解的用法。

    将@Autowired注解应用于构造函数,如以下示例所示

    public class MovieRecommender {
     
        private final CustomerPreferenceDao customerPreferenceDao;
     
        @Autowired
        public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
            this.customerPreferenceDao = customerPreferenceDao;
        }
     
        // ...
    }

    将@Autowired注释应用于setter方法

    public class SimpleMovieLister {
     
        private MovieFinder movieFinder;
     
        @Autowired
        public void setMovieFinder(MovieFinder movieFinder) {
            this.movieFinder = movieFinder;
        }
     
        // ...
    }

    将@Autowired注释应用于具有任意名称和多个参数的方法

    public class MovieRecommender {
     
        private MovieCatalog movieCatalog;
     
        private CustomerPreferenceDao customerPreferenceDao;
     
        @Autowired
        public void prepare(MovieCatalog movieCatalog,
                CustomerPreferenceDao customerPreferenceDao) {
            this.movieCatalog = movieCatalog;
            this.customerPreferenceDao = customerPreferenceDao;
        }
     
        // ...
    }

    您也可以将@Autowired应用于字段,或者将其与构造函数混合,如以下示例所示

    public class MovieRecommender {
     
        private final CustomerPreferenceDao customerPreferenceDao;
     
        @Autowired
        private MovieCatalog movieCatalog;
     
        @Autowired
        public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
            this.customerPreferenceDao = customerPreferenceDao;
        }
     
        // ...
    }

    直接应用于字段是我们使用的最多的一种方式,但是使用构造方法注入从代码层面却是更加好的,原因可以参考这篇博客:spring重点知识。除此之外,还有以下不太常见的几种方式

    将@Autowired注释添加到需要该类型数组的字段或方法,则spring会从ApplicationContext中搜寻符合指定类型的所有bean,如以下示例所示:

    public class MovieRecommender {
     
        @Autowired
        private MovieCatalog[] movieCatalogs;
     
        // ...
    }

    数组可以,我们可以马上举一反三,那容器也可以吗,答案是肯定的,下面是set以及map的例子:

    public class MovieRecommender {
     
        private Set<MovieCatalog> movieCatalogs;
     
        @Autowired
        public void setMovieCatalogs(Set<MovieCatalog> movieCatalogs) {
            this.movieCatalogs = movieCatalogs;
        }
     
        // ...
    }
    public class MovieRecommender {
     
        private Map<String, MovieCatalog> movieCatalogs;
     
        @Autowired
        public void setMovieCatalogs(Map<String, MovieCatalog> movieCatalogs) {
            this.movieCatalogs = movieCatalogs;
        }
     
        // ...
    }

    以上就是@Autowired注解的主要使用方式,经常使用spring的话应该对其中常用的几种不会感到陌生。

    @Autowired注解的作用到底是什么

    @Autowired这个注解我们经常在使用,现在,我想问的是,它的作用到底是什么呢?

    首先,我们从所属范围来看,事实上这个注解是属于spring的容器配置的一个注解,与它同属容器配置的注解还有:@Required,@Primary, @Qualifier等等。因此@Autowired注解是一个用于容器(container)配置的注解。

    其次,我们可以直接从字面意思来看,@autowired注解来源于英文单词autowire,这个单词的意思是自动装配的意思。自动装配又是什么意思?这个词语本来的意思是指的一些工业上的用机器代替人口,自动将一些需要完成的组装任务,或者别的一些任务完成。而在spring的世界当中,自动装配指的就是使用将Spring容器中的bean自动的和我们需要这个bean的类组装在一起。

    因此,笔者个人对这个注解的作用下的定义就是:将Spring容器中的bean自动的和我们需要这个bean的类组装在一起协同使用。

    接下来,我们就来看一下这个注解背后到底做了些什么工作。

    @Autowired注解是如何实现的

     事实上,要回答这个问题必须先弄明白的是java是如何支持注解这样一个功能的。

    java的注解实现的核心技术是反射,让我们通过一些例子以及自己实现一个注解来理解它工作的原理。

    例子注解@Override

    @Override注解的定义如下:

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface Override {
    }

    @Override注解使用java官方提供的注解,它的定义里面并没有任何的实现逻辑。注意,所有的注解几乎都是这样的,注解只能是被看作元数据,它不包含任何业务逻辑注解更像是一个标签,一个声明,表面被注释的这个地方,将具有某种特定的逻辑

    那么,问题接踵而至,注解本身不包含任何逻辑,那么注解的功能是如何实现的呢?答案必然是别的某个地方对这个注解做了实现。以@Override注解为例,他的功能是重写一个方法,而他的实现者就是JVM,java虚拟机,java虚拟机在字节码层面实现了这个功能。

    但是对于开发人员,虚拟机的实现是无法控制的东西,也不能用于自定义注解。 所以,如果是我们自己想定义一个独一无二的注解的话,则我们需要自己为注解写一个实现逻辑,换言之,我们需要实现自己注解特定逻辑的功能

    自己实现一个注解

    在自己写注解之前我们有一些基础知识需要掌握,那就是我们写注解这个功能首先是需要java支持的,java在jdk5当中支持了这一功能,并且在java.lang.annotation包中提供了四个注解,仅用于编写注解时使用,他们是:

    注解 作用
    @Documented  表明是否在java doc中添加Annotation
    @Retention

    定义注释应保留多长时间,即有效周期。有以下几种策略:

     

    RetentionPolicy.SOURCE - 在编译期间丢弃。 编译完成后,这些注释没有任何意义,因此它们不会写入字节码。 示例@Override,@ SuppressWarnings
    RetentionPolicy.CLASS - 在类加载期间丢弃。 在进行字节码级后处理时很有用。 有点令人惊讶的是,这是默认值。
    RetentionPolicy.RUNTIME - 不要丢弃。 注释应该可以在运行时进行反射。 这是我们通常用于自定义注释的内容。

     

     

    @Target 

    指定可以放置注解的位置。 如果不指定,则可以将注解放在任何位置。若我们只想要其中几个,则需要定义对应的几个。

    下面是这8个属性:

    ElementType.TYPE(类,接口,枚举)

    ElementType.FIELD(实例变量)

    ElementType.METHOD

    ElementType.PARAMETER

    ElementType.CONSTRUCTOR

    ElementType.LOCAL_VARIABLE

    ElementType.ANNOTATION_TYPE(在另一个注释上)

    ElementType.PACKAGE(记住package-info.java)

    @Inherited 控制注解是否对子类产生影响。

     

    下面我们开始自己实现一个注解,注解仅支持 primitives, string和 enumerations这三种类型。 注解的所有属性都定义为方法,也可以提供默认值。我们先实现一个最简单的注解。

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface SimpleAnnotation {
        String value();
    }
    

    上面这个注释里面只定义了一个字符传,它的目标注释对象是方法,保留策略是在运行期间。下面我们定义一个方法来使用这个注解:

    public class UseAnnotation {
    
        @SimpleAnnotation("testStringValue")
        public void testMethod(){
            //do something here
        }
    
    }
    

    我们在这里使用了这个注解,并把字符串赋值为:testStringValue,到这里,定义一个注解并使用它,我们就已经全部完成。

    简单的不敢相信。但是,细心一想的话,我们虽然写了一个注解也用了它,可是它并没有产生任何作用啊。也没有对我们这里方法产生任何效果啊。是的现在确实是这样的,原因在于我们前面提到的一点,我们还没有为这个注解实现它的逻辑,现在我们就来为这个注解实现逻辑。

    应该怎么做呢?我们不妨自己来想一想。首先,我想给标注了这个注解的方法或字段实现功能,我们必须得知道,到底有哪些方法,哪些字段使用了这个注解吧,因此,这里我们很容易想到,这里应该会用到反射。其次,利用反射,我们利用反射拿到这样目标之后,得为他实现一个逻辑,这个逻辑是这些方法本身逻辑之外的逻辑,这又让我们想起了代理,aop等知识,我们相当于就是在为这些方法做一个增强。事实上的实现主借的逻辑也大概就是这个思路。梳理一下大致步骤如下:

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

    现在我们来实现一下这个逻辑,代码如下:

       private static void annotationLogic() {
    
            Class useAnnotationClass = UseAnnotation.class;
            for(Method method : useAnnotationClass.getMethods()) {
                SimpleAnnotation simpleAnnotation = (SimpleAnnotation)method.getAnnotation(SimpleAnnotation.class);
                if(simpleAnnotation != null) {
                    System.out.println(" Method Name : " + method.getName());
                    System.out.println(" value : " + simpleAnnotation.value());
                    System.out.println(" --------------------------- ");
                }
            }
        }

    在这里我们实现的逻辑就是打印几句话。从上面的实现逻辑我们不能发现,借助于java的反射我们可以直接拿到一个类里所有的方法,然后再拿到方法上的注解,当然,我们也可以拿到字段上的注解。借助于反射我们可以拿到几乎任何属于一个类的东西。

    关于反射更多的知识请参见这篇博客:java中的反射和多态实现原理详解以及对比

    一个简单的注解我们就实现完了。现在我们再回过头来,看一下@Autowired注解是如何实现的。

    @Autowired注解实现逻辑分析

    知道了上面的知识,我们不难想到,上面的注解虽然简单,但是@Autowired和他最大的区别应该仅仅在于注解的实现逻辑,其他利用反射获取注解等等步骤应该都是一致的。先来看一下@Autowired这个注解在spring的源代码里的定义是怎样的,如下所示:

    package org.springframework.beans.factory.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;
    
    @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Autowired {
        boolean required() default true;
    }
    

    阅读代码我们可以看到,Autowired注解可以应用在构造方法,普通方法,参数,字段,以及注解这五种类型的地方,它的保留策略是在运行时。下面,我们不多说直接来看spring对这个注解进行的逻辑实现.

    在Spring源代码当中,Autowired注解位于包org.springframework.beans.factory.annotation之中,该包的内容如下:

    经过分析,不难发现Spring对autowire注解的实现逻辑位于类:AutowiredAnnotationBeanPostProcessor之中,已在上图标红。其中的核心处理代码如下:

    private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    		LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<>();
    		Class<?> targetClass = clazz;//需要处理的目标类
           
    		do {
    			final LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<>();
    
                /*通过反射获取该类所有的字段,并遍历每一个字段,并通过方法findAutowiredAnnotation遍历每一个字段的所用注解,并如果用autowired修饰了,则返回auotowired相关属性*/  
    
    			ReflectionUtils.doWithLocalFields(targetClass, field -> {
    				AnnotationAttributes ann = findAutowiredAnnotation(field);
    				if (ann != null) {//校验autowired注解是否用在了static方法上
    					if (Modifier.isStatic(field.getModifiers())) {
    						if (logger.isWarnEnabled()) {
    							logger.warn("Autowired annotation is not supported on static fields: " + field);
    						}
    						return;
    					}//判断是否指定了required
    					boolean required = determineRequiredStatus(ann);
    					currElements.add(new AutowiredFieldElement(field, required));
    				}
    			});
                //和上面一样的逻辑,但是是通过反射处理类的method
    			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
    				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
    				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
    					return;
    				}
    				AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
    				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
    					if (Modifier.isStatic(method.getModifiers())) {
    						if (logger.isWarnEnabled()) {
    							logger.warn("Autowired annotation is not supported on static methods: " + method);
    						}
    						return;
    					}
    					if (method.getParameterCount() == 0) {
    						if (logger.isWarnEnabled()) {
    							logger.warn("Autowired annotation should only be used on methods with parameters: " +
    									method);
    						}
    					}
    					boolean required = determineRequiredStatus(ann);
    					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                  	    currElements.add(new AutowiredMethodElement(method, required, pd));
    				}
    			});
        //用@Autowired修饰的注解可能不止一个,因此都加在currElements这个容器里面,一起处理		
    			elements.addAll(0, currElements);
    			targetClass = targetClass.getSuperclass();
    		}
    		while (targetClass != null && targetClass != Object.class);
    
    		return new InjectionMetadata(clazz, elements);
    	}

    博主在源代码里加了注释,结合注释就能看懂它做的事情了,最后这个方法返回的就是包含所有带有autowire注解修饰的一个InjectionMetadata集合。这个类由两部分组成:

    public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {
    		this.targetClass = targetClass;
    		this.injectedElements = elements;
    	}

    一是我们处理的目标类,二就是上述方法获取到的所以elements集合。

    有了目标类,与所有需要注入的元素集合之后,我们就可以实现autowired的依赖注入逻辑了,实现的方法如下:

    @Override
    	public PropertyValues postProcessPropertyValues(
    			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {
    
    		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
    		try {
    			metadata.inject(bean, beanName, pvs);
    		}
    		catch (BeanCreationException ex) {
    			throw ex;
    		}
    		catch (Throwable ex) {
    			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    		}
    		return pvs;
    	}

    它调用的方法是InjectionMetadata中定义的inject方法,如下

    public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    		Collection<InjectedElement> checkedElements = this.checkedElements;
    		Collection<InjectedElement> elementsToIterate =
    				(checkedElements != null ? checkedElements : this.injectedElements);
    		if (!elementsToIterate.isEmpty()) {
    			for (InjectedElement element : elementsToIterate) {
    				if (logger.isTraceEnabled()) {
    					logger.trace("Processing injected element of bean '" + beanName + "': " + element);
    				}
    				element.inject(target, beanName, pvs);
    			}
    		}
    	}

    其逻辑就是遍历,然后调用inject方法,inject方法其实现逻辑如下:

    		/**
    		 * Either this or {@link #getResourceToInject} needs to be overridden.
    		 */
    		protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
    				throws Throwable {
    
    			if (this.isField) {
    				Field field = (Field) this.member;
    				ReflectionUtils.makeAccessible(field);
    				field.set(target, getResourceToInject(target, requestingBeanName));
    			}
    			else {
    				if (checkPropertySkipping(pvs)) {
    					return;
    				}
    				try {
    					Method method = (Method) this.member;
    					ReflectionUtils.makeAccessible(method);
    					method.invoke(target, getResourceToInject(target, requestingBeanName));
    				}
    				catch (InvocationTargetException ex) {
    					throw ex.getTargetException();
    				}
    			}
    		}

    在这里的代码当中我们也可以看到,是inject也使用了反射技术并且依然是分成字段和方法去处理的。在代码里面也调用了makeAccessible这样的可以称之为暴力破解的方法,但是反射技术本就是为框架等用途设计的,这也无可厚非。

    对于字段的话,本质上就是去set这个字段的值,即对对象进行实例化和赋值,例如下面代码:

    @Autowired
    ObjectTest objectTest;

    那么在这里实现的就相当于给这个objecTest引用赋值了。

    对于方法的话,本质就是去调用这个方法,因此这里调用的是method.invoke.

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

    以上,就是@Autowire注解实现逻辑的全部分析。结合源代码再看一遍的话,会更加清楚一点。下面是spring容器如何实现@AutoWired自动注入的过程的图:

     

    总结起来一句话:使用@Autowired注入的bean对于目标类来说,从代码结构上来讲也就是一个普通的成员变量,@Autowired和spring一起工作,通过反射为这个成员变量赋值,也就是将其赋为期望的类实例。

     

    问题

    注解的有效周期是什么?

    各种注释之间的第一个主要区别是,它们是在编译时使用,然后被丢弃(如@Override),还是被放在编译的类文件中,并在运行时可用(如Spring的@Component)。这是由注释的“@Retention”策略决定的。如果您正在编写自己的注释,则需要决定该注释在运行时(可能用于自动配置)还是仅在编译时(用于检查或代码生成)有用。

    当用注释编译代码时,编译器看到注释就像看到源元素上的其他修饰符一样,比如访问修饰符(public/private)或.。当遇到注释时,它运行一个注释处理器,就像一个插件类,表示对特定的注释感兴趣。注释处理器通常使用反射API来检查正在编译的元素,并且可以简单地对它们执行检查、修改它们或生成要编译的新代码。@Override是一个示例;它使用反射API来确保能够在其中一个超类中找到方法签名的匹配,如果不能,则使用@Override会导致编译错误。

    注入的bean和用它的bean的关系是如何维护的?

    无论以何种方式注入,注入的bean就相当于类中的一个普通对象应用,这是它的实例化是spring去容器中找符合的bean进行实例化,并注入到类当中的。他们之间的关系就是普通的一个对象持有另一个对象引用的关系。只是这些对象都是spring当中的bean而已。

    为什么注入的bean不能被定义为static的?

    从设计的角度来说 ,使用静态字段会鼓励使用静态方法。 静态方法是evil的。 依赖注入的主要目的是让容器为您创建对象并进行连接。 而且,它使测试更加容易。

    一旦开始使用静态方法,您就不再需要创建对象的实例,并且测试变得更加困难。 同样,您不能创建给定类的多个实例,每个实例都注入不同的依赖项(因为该字段是隐式共享的,并且会创建全局状态)。

    静态变量不是Object的属性,而是Class的属性。 spring的autowire是在对象上完成的,这样使得设计很干净。 在spring当中我们也可以将bean对象定义为单例,这样就能从功能上实现与静态定义相同的目的。

    但是从纯粹技术的层面,我们可以这样做:

    将@Autowired可以与setter方法一起使用,然后可以让setter修改静态字段的值。但是这种做法非常不推荐

     

     

    展开全文
  • @Autowired使用全纪录

    千次阅读 2019-05-12 14:26:36
    @Autowired应该是我们在Spring项目中最常用的注解了。 使用起来非常方便,但是一旦出现问题调试起来也是比较麻烦的。 笔者就是这样,平时用来一时爽,出现问题两行泪。 究其原因,还是对@Autowired了解得不够...
  • @autowired原理和流程

    千次阅读 2019-06-23 19:58:49
    转载:https://blog.csdn.net/nuomizhende45/article/details/84960303
  • @Autowired的用法和作用

    万次阅读 2018-10-20 16:31:55
    @Autowired的用法和作用   这个注解就是spring可以自动帮你把bean里面引用的对象的setter/getter方法省略,它会自动帮你set/get。 &lt;bean id="userDao" class="..."/&gt; &...
  • 去除@Autowired注解warning提示

    万次阅读 2020-06-18 17:40:28
    @Autowired注解warning提示 提示 @Autowired private ICommonUtilsService checkService; Field injection is not recommended 解决 替换成下述 private ICommonUtilsService checkService; @Autowired ...
  • @Autowired 注解用在方法与属性上

    万次阅读 2018-05-03 10:50:29
    private ValueOperations&lt;String, String&...@Autowired public void setValueOperations(StringRedisTemplate stringRedisTemplate) { this.redisOperations = stringRedisTemplate.opsFor...
  • 场景: idea中通过@Autowired注入的对象一直有下划线提示,虽然不影响运行,但是强迫症的程序员肯定看不下去. 如何去除呢? 解决:改变@Autowired的检查级别即可. 快捷键:Ctrl+Alt+s,进入idea设置界面,输入...
  • 在写注解的时候 用 @Autowired 发现ide提示报错了 但是不要担心, 项目运行的时候是能正常运行的, 不影响使用. 也可以把 @Autowired 注解换成 @Resource 注解 就不提示错误了 ...
  • 对@Reference 、@Resource和@Autowired的简单理解

    万次阅读 多人点赞 2020-04-23 10:31:54
    主要谈一下对这三个注解的简单理解: @Reference 、@Resource和@Autowired
  • SpringBoot——@Autowired注解的作用

    万次阅读 2019-02-17 23:25:25
    @Controller public class HomeController { @Autowired NewsService newsService; @Autowired UserService userService; @Autowired HostHolder hostHolder; private List&lt;View...
  • @AutoWired下面有红线的处理方法: 在file下的setting中设置即可,如图所示:
  • Intellij Idea @Autowired取消提示

    万次阅读 2016-08-30 08:58:03
    File -- Settings -- Inspections。在Spring Core -- Autowring for Bean Class 中, 将Severity的级别由之前的error改成warning。
  • Autowired,Qualifier,Spring 按名称注入bean属性  @Autowired @Qualifier("addItemDestination") private Topic topic;  
  • Spring @Autowired 注入静态变量

    万次阅读 2018-02-01 14:58:42
    在一些工具类中可能会依赖 service 层的对象,一般情况下工具类都是使用静态方法,对应的成员变量也需要声明为静态的,此时如果直接使用 @Autowired 进行依赖注入,在方法调用的时候会报 NullpointerException. ...
  • 这是由于Springboot Bean的装载机制所导致的,具体大家可以去研究源码。 下面是我的解决方案,仅供参考。 A: @Component ...public class XxxConfig { ... @Autowired private RedisUtil redisUtil; // ...
  • 使用IDEA工具进行开发的时候,需要@Autowired自动注解bean时回报红线,但是项目依然能够运行现有的解决的方案是:打开file-settings或者ctrl+alt+s -&gt; Editor然后在Inspections 点击搜索栏 输入Spring Core在...
  • 将 error 该成 warning 即可
1 2 3 4 5 ... 20
收藏数 222,183
精华内容 88,873
关键字:

autowired