精华内容
下载资源
问答
  • @resource
    千次阅读
    2021-12-09 21:50:47


    此注解来源于JSR规范(Java Specification Requests),其作用是找到依赖的组件注入到应用来,它利用了JNDI(Java Naming and Directory Interface Java命名目录接口 J2EE规范之一)技术查找所需的资源。

    网上查了些资料看的有点晕晕, 这里用例子来说明 @Resource的用法 , 以及需要注意的问题

    属性介绍

    name:
    	资源的JNDI名称。在spring的注入时,指定bean的唯一标识。
    type:
    	指定bean的类型。
    lookup:
    	引用指向的资源的名称。它可以使用全局JNDI名称链接到任何兼容的资源。
    authenticationType:
    	指定资源的身份验证类型。它只能为任何受支持类型的连接工厂的资源指定此选项,而不能为其他类型的资源指定此选项。
    shareable:
    	指定此资源是否可以在此组件和其他组件之间共享。
    mappedName:
    	指定资源的映射名称。
    description:
    	指定资源的描述。
    

    @Resource 的装配规则

    默认情况下,即所有属性都不指定,它默认按照byType的方式装配bean对象。
    如果指定了name,没有指定type,则采用byName。
    如果没有指定name,而是指定了type,则按照byType装配bean对象。
    当byName和byType都指定了,两个都会校验,如果找不到,或者找到多个(比如byName的方式找到了BeanA, ByType的方式找到了BeanB ) 这种情况也是不会成功的.

    上述略显官方的味道的解释,相信不少人也是晕晕的 , 也对这个"默认值" 情况解释的不到位 , 下面来个灵魂总结.

    灵魂总结

    注意: !!! type和name的根本逻辑就是 type是划定一个范围 , 然后name 在其中选择一个
    举个栗子:

    • 如果 type 只匹配了 一个 ( 1 ) , 那么成功装备结果 必然是 1 , 如果name只有找到了1 , 或者没有找到的情况下才会配置成功( 没有显示指定name值, 默认为变量名) , name如果在容器中找到了非1 的bean ,则会报类型错误.
    • 如果type 匹配了 ( 1 , 2 , 3 ) 多个实例 , 那么name只有匹配到 其中一个,才会装配成功, 如果一个也匹配不到 , 则会报错 ,因为spring不知道到底要装配哪个实例.
    • 如果type一个都没有匹配到,那就直接凉凉了 ,报错:No qualifying bean of type xxx 的错误, 即使name指定的值在容器中找到了符合条件的bean实例, 也会报 类型不符合的错误.

    先来看下@Resource的应用场景

    @Resource的应用场景一般都是在装配的时候出现了多个符合条件的bean , 这时候用@Autowired注解自动装配就会出现了问题 . 此时就可以用@Resource注解类解决问题 . (@Qualifier + @Autowired 也可以实现, 这里主要说下@Resource注解) , 通常就是解决多态的问题.

    代码演示

    这里示例将@Resource 放在了类的属性上

    首先有个HelloService接口:

    package com.resource.service;
    public interface HelloService {
        void sayHello();
    }
    

    两个实现类 , HelloServiceImpl1 和 HelloServiceImpl2 , 实现的sayHello()方法,分别在控制台打印出 hello one! , hello two! 如下:

    package com.resource.service.impl;
    @Component
    public class HelloServiceImpl1 implements HelloService {
        public void sayHello() {
            System.out.println("hello one!");
        }
    }
    
    package com.resource.service.impl;
    @Component
    public class HelloServiceImpl2 implements HelloService {
        public void sayHello() {
            System.out.println("hello two!");
        }
    }
    

    业务类UseService 实现属性装配

    package com.resource;
    @Component
    public class UseService {
        //@Qualifier("helloServiceImpl1")
        //@Autowired
        //private HelloService helloService;
        
        @Resource
        private HelloService helloServiceImpl;
        public void say(){
            helloServiceImpl.sayHello();
        }
    }
    

    测试类

        public static void main(String[] args) {
            //1.创建容器
            AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("com");
            //2.获取对象
            UseService useService = ac.getBean("useService", UseService.class);
            useService.say();
        }
    

    默认情况

    装配代码

    其它代码不变

        @Resource
        private HelloService helloServiceImpl;
        public void say(){
            helloServiceImpl.sayHello();
        }
    
    运行测试

    这时候如果什么都不指定, 运行则会报错如下:

    Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException
    : No qualifying bean of type 'com.resource.service.HelloService' available
    : expected single matching bean but found 2: helloServiceImpl1,helloServiceImpl2
    
    分析

    @Resource是用 ByType和ByName 来装配的, 如果没有显示的通过type属性和name属性指定 , “就会找其默认值”
    在这个示例中type就是HelloService.class , 又因为其是接口, spring在容器中找到了其两个已经注入容器的实现类分别为 helloServiceImpl1 , helloServiceImpl2 这两个实例. (范围)
    而name 也没有通过属性执行 , name默认值就是变量的名称 helloServiceImpl , 显然spring容器中是没有的. (后续会通过测试验证)
    通过默认指定值得ByType和ByName 其结果就是得到了两个符合要求的实例 , 而name也没有完成在type后有多个实例的情况下 “选一个” . 所有会有上述的把报错信息.

    byName (name默认属性名)

    装配代码

    其它代码不变

        @Resource
        private HelloService helloServiceImpl1;
        public void say(){
            helloServiceImpl1.sayHello();
        }
    

    这个变化就是上个示例中将属性名从helloServiceImpl 改成了 helloServiceImpl1 .

    运行测试
    hello one!
    Process finished with exit code 0
    
    分析

    这里同样byType后 有两个实例 helloServiceImpl1 , helloServiceImpl2 , 而name没有显示指定, 默认为变量名 helloServiceImpl1 , 也完成了选一个的任务, 进而装配成功!

    byName (name显示指定)

    装配代码

    其它代码不变

        @Resource(name="helloServiceImpl2")
        private HelloService helloServiceImpl1;
        public void say(){
            helloServiceImpl1.sayHello();
        }
    

    这个变化就是上个示例中 指定了name属性的值

    运行测试
    hello two!
    Process finished with exit code 0
    
    分析

    可以看到属性名为helloServiceImpl1 , 显示指定的是helloServiceImpl2 , 即如果显示指定name的值得话就取该值, 相当于是对默认的变量名覆盖了(可以这样理解). 就是有显示指定就用显示指定的, 没有就用变量名. 结果输出hello two! 就是对的了.

    byType 显示指定

    装配代码

    其它代码不变 , 装配改为显示指定type值,如下

        @Resource(type = HelloServiceImpl1.class )
        private HelloService helloServiceImpl1;
        public void say(){
            helloServiceImpl1.sayHello();
        }
    

    这个变化就是上个示例中 指定了name属性的值

    运行测试
    hello one!
    Process finished with exit code 0
    
    分析

    显示指定了type = HelloServiceImpl1.class , 也就范围就是 helloServiceImpl1 , 根据开头的灵魂总结 , type已经确定了一个 , 那么 name (默认变量名 或者显示指定 ) 的值 就必须是helloServiceImpl1 或者是一个在spring容器中找不到的名称.
    注意: 这是个坑, 如果你指定的变量名刚好是spring容器中的某个bean的id , 那么这里就会报
    Bean named ‘xxxx’ is expected to be of type ‘com.resource.service.impl.HelloServiceImpl1’ 的异常!!!
    这里用代码演示下:
    新建了个HiService类

    package com.resource.service.impl;
    @Component
    public class HiService {
       public void sayHello() {
           System.out.println("Hi Hi!");
       }
    }
    

    装配类 (主要改了变量名为hiservice ,HiService 的bean id)

        @Resource(type = HelloServiceImpl1.class )
        private HelloService hiService;
        public void say(){
            hiService.sayHello();
        }
    

    运行报类型的错误如下:

    org.springframework.beans.factory.BeanNotOfRequiredTypeException:
     Bean named 'hiService' is expected to be of type 'com.resource.service.impl.HelloServiceImpl1' 
     but was actually of type 'com.resource.service.impl.HiService'
    

    finally

    以上仅为个人见解 , 能看到这里希望能让您有所收获.
    抛砖引玉 , 如有不到之处, 敬请指正.

    更多相关内容
  • 主要介绍了详解Spring关于@Resource注入为null解决办法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • Spring 中 @Service 和 @Resource 注解的区别 1 前言 在咱们使用 spring 框架的时候,注解是“不可或缺”的一部分,她帮我们脱离了配置繁琐的 XML 文件的工作,但有一点却需要我们自己去把握,那就是“3何”,即...
  • Spring框架中 @Autowired 和 @Resource 注解的区别 在 spring 框架中,除了使用其特有的注解外,使用基于 JSR-250 的注解,它包括 @PostConstruct, @PreDestroy 和 @Resource 注释。  首先,咱们简单了解 @...
  • 编码剖析@Resource注解的实现原理
  • 主要介绍了详解Spring依赖注入:@Autowired,@Resource和@Inject区别与实现原理,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • @Resource详解

    万次阅读 多人点赞 2021-03-31 16:10:15
    @Resource详解 阅读本文之前希望读者最好已经对整个Bean的大体Spring执行顺序已经有了一定的了解。 示例 定义一个接口,表示水果类,只包含一个方法代表售卖。 public interface Fruit { void sell(); } 有两个...

    @Resource详解

    阅读本文之前希望读者最好已经对整个Bean的大体Spring执行顺序已经有了一定的了解。

    示例

    定义一个接口,表示水果类,只包含一个方法代表售卖。

    public interface Fruit {
    
        void sell();
    }
    

    有两个具体实现类,Apple🍎和Banana🍌。

    @Service
    public class Apple implements Fruit {
    
    
        public Apple() {
            System.out.println("Apple......");
        }
    
        @Override
        public void sell() {
            System.out.println("苹果2元一斤");
        }
    }
    
    @Service
    public class Banana implements Fruit {
    
        public Banana() {
            System.out.println("Banana...");
        }
    
        @Override
        public void sell() {
            System.out.println("香蕉3元一串");
        }
    }
    

    具体的商店类来注入Fruit接口。

    @Component
    public class Store {
    
        @Resource
        private Fruit fruit;
    
        public void getFruit() {
            fruit.sell();
        }
    
    }
    

    测试方法:

    public class Test {
    
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
            context.getBean(Store.class).getFruit();
    
    
            // 优雅关闭,SpringWEB中已有相关实现
            context.registerShutdownHook();
        }
    }
    

    实际执行结果:
    在这里插入图片描述

    这里可以清楚的看到报了NoUniqueBeanDefinitionException异常,说是希望单个Bean的匹配,却找到了多个。

    下面就来具体的讲下为什么。

    首先,@Resource中没有设置任何属性值,统统采用的是默认的值。

    按照Spring Bean的加载顺序,Store Bean创建的时候,BeanFactory中已经创建了Apple和Banana Bean。

    在这里插入图片描述

    1. newInstance

    第一步就是先创建出Store对象。

    2. 解析类中的字段

    Spring在实例化对象后,会调用 applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);方法对BeanDefinition进行完善,主要为了后续的BeanPostProcessor处理器在注入对应的字段时能获取到需要注入的类的相关信息。

    而对应需要注入的一个个类而言,就是使用ResourceElement对象来进行保存,相关重要的构造函数如下:

    public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
       super(member, pd);
       Resource resource = ae.getAnnotation(Resource.class);
       // 获取@Resource的name属性
       String resourceName = resource.name();
       // 获取@Resource的type属性
       Class<?> resourceType = resource.type();
       this.isDefaultName = !StringUtils.hasLength(resourceName);
       if (this.isDefaultName) {
          // 如果没有设置@Resource name属性就用字段名称作为bean name
          resourceName = this.member.getName();
          // 如果member是setter方法,则取setXXX的XXX部分为bean name
          if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
             resourceName = Introspector.decapitalize(resourceName.substring(3));
          }
       }
       else if (embeddedValueResolver != null) {
          // 如果设置了@Resource name的属性,则使用EmbeddedValueResolver对象先做一次SpringEL解析得到真正的bean name
          resourceName = embeddedValueResolver.resolveStringValue(resourceName);
       }
       if (Object.class != resourceType) {
          // 确保字段或setter方法类型与resourceType一致
          checkResourceType(resourceType);
       }
       else {
          // No resource type specified... check field/method.
          resourceType = getResourceType();
       }
       this.name = (resourceName != null ? resourceName : "");
       this.lookupType = resourceType;
       String lookupValue = resource.lookup();
       // 如果使用jndi查找名字
       this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
       Lazy lazy = ae.getAnnotation(Lazy.class);
       // 是否延迟注入
       this.lazyLookup = (lazy != null && lazy.value());
    }
    

    当name属性没有被设置时,就会执行下面的分支,根据是方法注入还是属性注入,分别设置为方法名称set后面的字符串或字段名称。

       if (this.isDefaultName) {
          // 如果没有设置@Resource name属性就用字段名称作为bean name
          resourceName = this.member.getName();
          // 如果member是setter方法,则取setXXX的XXX部分为bean name
          if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
             resourceName = Introspector.decapitalize(resourceName.substring(3));
          }
       }
    

    下面是具体的ResourceElement类对象中的各属性。

    在这里插入图片描述

    然后可以测试下在@Resource注解中加入name属性;

    @Resource(name = “apple”)

    得到的是下面的对象。
    在这里插入图片描述

    这里可以看出name属性会有明显的不同。

    这里name属性和lookupType属性其实可以对应于@Resource中的name和type属性。

    3. populateBean

    第三步就是类属性的注入。

    执行到对应的处理器(@Resource是通过CommonAnnotationBeanPostProcessor处理器进行处理的)进行属性注入的时候,autowireResource就会用来获取对应属性需要注入的对象。

    protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
          throws NoSuchBeanDefinitionException {
    
       // 自动装配的对象
       Object resource;
       // 自动装配的名字
       Set<String> autowiredBeanNames;
       // 依赖的属性名
       String name = element.name;
    
       if (factory instanceof AutowireCapableBeanFactory) {
          AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
          DependencyDescriptor descriptor = element.getDependencyDescriptor();
          // 判断是否设置了name属性的值
          if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
             autowiredBeanNames = new LinkedHashSet<>();
             resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
             if (resource == null) {
                throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
             }
          }
          else {
             resource = beanFactory.resolveBeanByName(name, descriptor);
             autowiredBeanNames = Collections.singleton(name);
          }
       }
       else {
          resource = factory.getBean(name, element.lookupType);
          autowiredBeanNames = Collections.singleton(name);
       }
    
       if (factory instanceof ConfigurableBeanFactory) {
          ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
          for (String autowiredBeanName : autowiredBeanNames) {
             if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
                //注册依赖关系
                beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
             }
          }
       }
    
       return resource;
    }
    

    这里的element对象就是我们之前解析保存的ResourceElement

    然后最重要的,上面强调过的name属性在不同Resource注解中解析出来的ResourceElement是会不同的,这里就会有不同的处理方式。

    isDefaultName为false时,说明name属性被设置了值,此时执行的如下逻辑;

         resource = beanFactory.resolveBeanByName(name, descriptor);
         autowiredBeanNames = Collections.singleton(name);
    

    resolveBeanByName方法就是通过设置的名称来进行解析对应的Bean对象。接着就能看到经常使用到的getBean方法,从BeanFactory中拿到Bean对象。

    public Object resolveBeanByName(String name, DependencyDescriptor descriptor) {
       InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
       try {
          // 获取bean
          return getBean(name, descriptor.getDependencyType());
       }
       finally {
          // 为目标工厂方法提供依赖描述符
          ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
       }
    }
    

    当Resource注解中name没有设置值,即使用的是字段名称作为beanName,执行的就是

             resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
    

    resolveDependency方法中实际工作的方法就是doResolveDependency:

    public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
          @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
    
       //设置新得当前切入点对象,得到旧的当前切入点对象
       InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
       
           // ...省略
    
          // 查找相关所有类型匹配的bean
          Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
          //如果没有候选bean对象
          if (matchingBeans.isEmpty()) {
             //如果descriptor需要注入
             if (isRequired(descriptor)) {
                //抛出NoSuchBeanDefinitionException或BeanNotOfRequiredTypeException以解决不可 解决的依赖关系
                raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
             }
             //返回null,表示么有找到候选Bean对象
             return null;
          }
    
          //定义用于存储唯一的候选Bean名变量
          String autowiredBeanName;
          //定义用于存储唯一的候选Bean对象变量
          Object instanceCandidate;
    
          //如果候选Bean对象Map不止有一个
          if (matchingBeans.size() > 1) {
             //确定candidates中可以自动注入的最佳候选Bean名称
             autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
    
             if (autowiredBeanName == null) {
                // 如果有多个匹配结果,抛出异常
                if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
                   //让descriptor尝试选择其中一个实例,默认实现是抛出NoUniqueBeanDefinitionException.
                   return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
                }
                else {
                   return null;
                }
             }
             instanceCandidate = matchingBeans.get(autowiredBeanName);
          }
          else {
             //获取machingBeans唯一的元素
             Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
             autowiredBeanName = entry.getKey();
             instanceCandidate = entry.getValue();
          }
    
          // ...省略
      
          //返回最佳候选Bean对象【result】
          return result;
       }
       finally {
          //设置上一个切入点对象
          ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
       }
    }
    

    doResolveDependency方法中会获取所有和指定type相同的所有bean集合,当发现bean集合中的元素个数超过1时就抛出了上面出现的错误了,如果只有一个那自然而然就是拿那个bean来返回。

    这里抛出的异常其实不是直接抛出的,而是调用的DependencyDescriptor中的resolveNotUnique方法,而该方法默认实现就是会直接抛出一个NoUniqueBeanDefinitionException异常,这也是Spring留的一个可扩展的地方。

    我们可以通过继承DependencyDescriptor,然后重写该方法来自定义选择一个最优的bean(比如说选择第一个),然后在BeanPostProcessor中选择我们的子类作为实现,这样在@Resource不指定任何属性的情况下,有多个实现类的bean也不会抛出异常。

    在这里插入图片描述

    拓展

    • 当只指定type属性时;

    @Resource(type = Apple.class)
    在这里插入图片描述

    设置type属性后,isDefaultName的值还是为true,所以执行的还是resolveDependency方法。但是由于添加了类型的限制,所以也就不会匹配到多个Bean,而产生异常。

    • 既指定了name属性,又指定了type类型,但是是不同的类;

    @Resource(name = “banana”, type = Apple.class)
    在这里插入图片描述

    name属性被设置为banana,isDefaultName变为false,执行resolveBeanByName方法。

    但是由于找不到对应beanName为banana,但是类型又为Apple.class的bean,还是会抛出异常。

    在这里插入图片描述

    总结

    多种@Resource不同使用情况所执行方法如下所示;

    在这里插入图片描述

    • 当@Resource不设置任何值时,isDefaultName会为true,当对应字段名称的bean或者BeanDefinition已存在时会走byName的形式,否则走byType的形式

    • 只指定了type属性时,只有当对应的名称不存在对应的bean或BeanDefinition,才会通过byType找到唯一的一个类型匹配的bean;

    • 只指定了name属性,会执行getBean方法,根据指定的name来获取bean;

    • 既指定了name属性,又指定了type属性,会先根据那么查找对应的bean,然后进行type类型比较。

    如何解决本文最上面出现的问题?

    • @Resource中指定name或着type;
    • @Qualifier指定bean名称;
    • 将字段名称修改为指定的bean名称;
    • 直接修改对象类型。

    只推荐第一种方法。

    展开全文
  • 主要介绍了Spring实战之使用@Resource配置依赖操作,结合实例形式分析了Spring使用@Resource配置依赖具体步骤、实现及测试案例,需要的朋友可以参考下
  • @Autowired与@Resource区别

    万次阅读 2022-04-05 16:06:15
    一、前言 Spring Bean覆盖配置 二、@Autowired 注解处理器 装配方式 注解属性 作用范围 1. 成员变量 2. 构造器 3. 方法 ...三、@Resource ...四、@Autowired与@Resource对比 二者对比 @Autowired装配流程 @Resou


    一、前言

    @Autowired和@Resource都是用来自动装配bean的。

    • @Resource是JSR-250提供的,它是Java标准,绝大部分框架都支持。
    • @Autowired功能非常强大,但只适用于Spring框架,如果换成了JFinal等其他框架,功能就会失效。

    Spring Bean覆盖配置

    spring:
      main:
        allow-bean-definition-overriding: true
    

    allow-bean-definition-overriding属性用于配置出现相同名称bean的情况如何处理:

    • 值为false时(默认值为false),如果出现相同名称的bean,直接抛异常。
    • 值为true时,表示支持相同名称的bean覆盖,后定义的bean会覆盖之前定义的相同名称的bean。

    下文会提到按类型装配,那么什么是同一类型呢?

    • 父类及其子类都属于父类这一类型
    • 接口及其实现类都属于接口这一类型

    二、@Autowired

    @Autowired是Spring提供的注解,用于自动装配。

    注解处理器

    AutowiredAnnotationBeanPostProcessor类是Autowired注解的注解处理器。

    关于注解处理器可参考文章:https://blog.csdn.net/JokerLJG/article/details/123548694

    装配方式

    • 按类型装配(默认使用的装配方式)。
    • 按名称装配(结合@Qualifier注解使用)。

    注解属性

    • required:默认值true。值为true时,表示必须注入,如bean不存在则会报错;值为false时,表示bean存在就注入,不存在则不注入。

    作用范围

    @Autowired的作用范围:成员变量、构造器、方法、参数、注解。

    1. 成员变量

    @Service
    public class UserService {
    
        @Autowired
        private IUser user;
    }
    

    使用最多的方式。

    2. 构造器

    @Service
    public class UserService {
    
        private IUser user;
    
        @Autowired
        public UserService(IUser user) {
            this.user = user;
        }
    }
    

    构造器上使用Autowired注解,实际上还是使用了成员变量装配的方式,并非构造器装配。

    3. 方法

    @Service
    public class UserService {
    
        @Autowired
        public void test(IUser user) {
           user.test();
        }
    }
    

    Spring会在项目启动的过程中,自动调用一次加了@Autowired注解的方法,我们可以在该方法做一些初始化的工作。

    4. 参数

    在构造器的入参上加Autowired注解

    @Service
    public class UserService {
    
        private IUser user;
    
        public UserService(@Autowired IUser user) {
            this.user = user;
            System.out.println("user:" + user);
        }
    }
    

    在非静态方法的入参上加Autowired注解

    @Service
    public class UserService {
    
        public void test(@Autowired IUser user) {
           user.test();
        }
    }
    

    5. 注解

    略。

    使用技巧

    同一类型多个bean

    当按类型装配时,如果该类型的bean不止一个时,会直接报错。举例说明:

    接口:

    public interface IUser {
        void test();
    }
    

    实现类1:

    @Service
    public class User1 implements IUser{
        @Override
        public void test() {
        }
    }
    

    实现类2:

    @Service
    public class User2 implements IUser{
        @Override
        public void test() {
        }
    }
    

    自动装配:

    @Service
    public class UserService {
    
        @Autowired
        private IUser user;
    }
    

    启动时的错误信息:

    Field userService in com.joker.controller.UserController required a single bean, but 2 were found:
    	- userServiceImpl1: defined in file [D:\work\my\springboot\target\classes\com\joker\controller\UserServiceImpl1.class]
    	- userServiceImpl2: defined in file [D:\work\my\springboot\target\classes\com\joker\controller\UserServiceImpl2.class]
    

    @Primary的使用

    @Primary注解可以解决上述问题(按类型装配时,如果该类型的bean不止一个时,会报错)。

    当我们使用自动配置的方式装配Bean时,如果这个Bean有多个候选者,假如其中一个候选者具有@Primary注解修饰,该候选者会被选中,作为自动装配的bean。

    在上面代码不变的情况下,只需在User1或User2上加@Primary注解,此时@Autowired自动装配会成功,并且自动装配的是加了@Primary注解的这个类对应的bean。

    User1类加@Primary注解

    @Service
    @Primary
    public class User1 implements IUser{
        @Override
        public void test() {
        }
    }
    

    @Qualifier的使用

    通过@Autowired和@Qualifier的结合使用可以按名称装配。

    @Service
    public class UserService {
    
        @Autowired
        @Qualifier("user1")
        private IUser user;
    }
    

    自动装配名称为user1的bean(注意:bean的类型也必须要满足为IUser类型)。

    装配多个实例

    我们一般使用的都是用@Autowired自动装配单个实例,但其实它也可以用来装配多个实例。可以通过List、Set、Map来装配多个实例,如下:

    @Service
    public class UserService {
    
        @Autowired
        private List<IUser> userList;
    
        @Autowired
        private Set<IUser> userSet;
    
        @Autowired
        private Map<String, IUser> userMap;
    }
    

    上面的装配方式会吧IUser类型的多个实例bean都装配的List、Set、Map中。

    @Autowired装配未生效

    下面列举常见@Autowired装配未生效的情况:

    1. @Autowired所在类未加@Controller、@Service、@Component、@Repository等注解,或者或者一些其它情况(如直接new对象的到实例)。这些情况会导致该类的bean并没有交给spring容器去管理,spring就无法完成自动装配的功能。

      public class UserService {
      
          @Autowired
          private IUser user;
      
          public void test() {
              user.say();
          }
      }
      
    2. 注解未被@ComponentScan扫描到。

    三、@Resource

    @Resource是JDK自带的注解,用于自动装配。

    注解处理器

    CommonAnnotationBeanPostProcessor类是Resource的注解处理器。

    装配方式

    @Resource默认按照名称自动注入。

    • 既没指定name,也没指定type,自动按照名称装配(当注解写在字段上时,默认取字段名,当注解写在setter方法上时,默认取属性名进行装配。);如果没有匹配,则退而按照类型装配,找不到则抛出异常。

      如果没有指定 name 属性,

    • 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。

    • 如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。

    • 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。

    注解属性

    Resource注解的主要属性:

    • name:指定需注入的bean的名称
    • type: 指定需注入的bean的类型

    作用范围

    @Resource的作用范围:类、成员变量、方法。

    1. 成员变量

    @Service
    public class UserService {
    
        @Resource
        private IUser user;
    }
    

    2. 方法

    @Service
    public class UserService {
    
        @Resource
        public void test(IUser user) {
            user.test();
        }
    }
    

    3. 类

    略。

    四、@Autowired与@Resource对比

    二者对比

    @Autowired@Resource
    Spring定义的注解JSR-250定义的注解
    默认按类型自动装配默认按名称自动装配
    一个参数:required(默认true),表示是否必须注入七个参数:最重要的两个参数是name、type
    默认按类型自动装配
    如果要按名称自动装配,需要使用@Qualifier一起配合
    默认按名称自动装配
    如果指定了name,则按名称自动装配;如果指定了type,则按类型自动装配
    作用范围:构造器、方法、参数、成员变量、注解作用范围:类、成员变量、方法

    @Autowired装配流程

    请添加图片描述

    @Resource装配流程

    请添加图片描述

    展开全文
  • @Autowired 与@Resource选择

    千次阅读 2022-03-13 23:21:56
    总结:推荐使用@Resource,如果追求速度,就使用@Resource指定名字(或者在注入接口的时候,强制指定实现类名) spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource...

    总结:推荐使用@Resource,如果追求速度,就使用@Resource指定名字(或者在注入接口的时候,强制指定实现类名)
    spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。
      @Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,而@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
      @Resource装配顺序
      1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
      2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
      3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
      4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
     
     @Autowired 与@Resource的区别:
    1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。

    2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:

    @Autowired()
    @Qualifier(“baseDao”)
    privateBaseDao baseDao;
    3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

    推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
    在这里插入图片描述
    个人总结:
    @Autowired 根据类型type注入,

    @Qualifier(“cusInfoService”)//一般作为@Autowired()的修饰用,

    @Autowired @Qualifie(“userService”) 两个结合起来可以根据名字和类型注入

    @Resource 默认根据名字name注入,其次按照类型搜索,也可以通过name和type属性进行选择性注入

    一般@Autowired和@Qualifier一起用,@Resource单独用。

    当然没有冲突的话@Autowired也可以单独用
    @Resource
    默认情况下是按照名称进行匹配,如果没有找到相同名称的Bean,则会按照类型进行匹配,有人可能会想了,这下好了,用这个是万能的了,不用管名字了,也不用管类型了,

    缺点:

    根据这个注解的匹配效果可以看出,它进行了两次匹配,也就是说,如果你在UserService这个类上面这样写注解,@Service,它会怎么找呢,首先是找相同名字的,如果没有找到,再找相同类型的,而这里的@Service没有写名字,这个时候就进行了两次搜索,显然,速度就下降了许多。也许你还会问,这里的@Service本来就没有名字,肯定是直接进行类型搜索啊。其实不是这样的,UserServiceImpl 上面如果有@Service默认的名字 是这个userServiceImpl,注意看,就是把类名前面的大写变成小写,就是默认的Bean的名字了。一般开发都会自己指定名字,例如:userService

    @Resource根据名字搜索是这样写@Resource(“userService”),如果你写了这个名字叫userService,那么UserServiceImpl上面必须也是这个名字,不然还是会报错。

    @Autowired @Qualifie(“userService”)

    是直接按照名字进行搜索,也就是说,对于UserServiceImpl 上面@Service注解必须写名字,不写就会报错,而且名字必须是@Autowired @Qualifie(“userService”) 保持一致。如果@Service上面写了名字,而@Autowired @Qualifie() ,一样会报错。

    说了这么多,可能你有些说晕了,那么怎么用这三个呢,
    要实际的工作是根据实际情况来使用的,UserServiceImpl上面可能会这样写 @Service(“userService”),这样通常使用AutoWire和@Resource多一些,bean的名字不用写。

    这里的实际工作情况,到底是什么情况呢?

    如果你的架构设计师考虑的比较精细,要求比较严格,要求项目上线后的访问速度比较好,这个时候@AutoWire没有@Resource好用,因为@Resource可以根据名字来搜索,是这样写的@Resource(name=“userService”),可以直接写@Resource(“userService”),因为默认byname。

    为什么推荐@Resource(name=“userService”)???

    因为根据名字搜索是最快的,就好像查数据库一样,根据Id查找最快。因为这里的名字与数据库里面的ID是一样的作用。这个时候,就要求你多写几个名字,工作量自然就增加了。而如果你不用注解,用xml文件的时候,对于注入Bean的时候要求写一个Id,xml文件时候的id就相当于这里的名字。

    这个@Autowired @Qualifie(“userService”) 也可以用名字啊,为什么不用呢?

    原因很简单,这个有点长,不喜欢,增加工作量。

    说了那么多没用,你能做的就是简单直接,什么最方便就用什么,
    你就直接用@Resource得了,如果你喜欢用@Autowire也行,不用写名字。
    参考:@Autowired 与@Resource选择(治好你的强迫症)

    展开全文
  • 【spring】依赖注入之@Resource注入

    千次阅读 2022-02-22 23:48:48
    @Resource是属于jdk的注解:javax.annotation.Resource。我们一般认为他是ByName的方式注入!
  • 主要介绍了通过@Resource注解实现属性装配代码详解,具有一定借鉴价值,需要的朋友可以参考下
  • @Autowired和@Resource区别

    千次阅读 多人点赞 2022-05-12 20:45:40
    @Autowired和@Resource区别 1.提供方不同 ​ @Autowired 是Spring提供的,@Resource 是J2EE提供的。 2.装配时默认类型不同 ​ @Autowired只按type装配,@Resource默认是按name装配。 3、使用区别 (1)@Autowired与@...
  • @Autowired和@Resource的区别

    千次阅读 2022-03-13 08:44:15
    @Autowired和@Resource的区别? (1)提供者不一样 , @Autowired是spring包中提供的注解,@Resource是jdk中提供的注解; (2)解析类不一样, @Autowired是由后置处理器AutowiredAnnotationBeanPostProcessor解析...
  • 1.@Resource是Java提供的注解但spring支持这个注解,@Autowired是spring提供的注解 2. @Autowried只有一个属性,requried,是否是必须的,默认是true,为true的情况下找不到这个注入的bean会报错。进行依赖注入的时候...
  • 详细解读@resource和@autowired

    千次阅读 2021-06-21 11:24:44
    详细解读@resource和@autowired简述相同之处不同之处(1)@Autowired(2)@Resource注意!!!@Resource装配顺序: 简述 @Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是...
  • @Resource注解用法

    千次阅读 2021-08-20 15:58:03
    @Resource注解和@Autowired注解一样,都是为了装配Bean,但是两者在使用上又有少许区别 @Autowired是默认按照类型装配Bean,当需要用名称装配时,可以在@Autowired后面使用@Qualifier注解指定name属性,来告知...
  • @Resource遇到的一些坑

    2022-01-13 12:42:33
    如果将@Resource改为@Autowired就可以启动成功,感觉很奇怪 查找原因 首先看看这两个注解之间的区别@Resource和@Autowired之间的区别 Spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解...
  • @Autowired 与@Resource选择(治好你的强迫症) spring不但支持自己定义的@Autowired注解,还支持几个由JSR-250规范定义的注解,它们分别是@Resource、@PostConstruct以及@PreDestroy。  @Resource的作用相当于@...
  • @Resource

    千次阅读 2019-08-04 11:07:09
    @Autowired 与@Resource的区别: 1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。 2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象...
  • @AutoWired和@Resource的区别

    千次阅读 2022-03-12 18:03:57
    @AutoWired spring的注解,默认通过类型注入,如果存在多个实例符合要求,则根据名称注入 @Resource java自带的注解,默认通过名称注入,如过名称不存在,则根据类型进行注入 如果一个接口有多个实现类,通过这两个...
  • 在传统的MVC实现里面 Spring boot 的controller-service-Impl-Dao-db controller层调用service接口层里面的方法大多使用 @Autowired自动注入注解 实际上调用Impl的具体实现 ...@Resource注解:可以通过 byName命名 和
  • @Autowired 和 @Resource 的区别区别@Autowired@Resource 区别 区别1:@Autowired 是spring提供的注解,@Resource 是JDK提供的注解 区别2:@Autowired 默认的注入方式是ByType(根据类型进行匹配),@Resource 默认...
  • Spring中@Autowired和@Resource的区别

    千次阅读 多人点赞 2021-10-19 20:13:48
    @Resource 在语义上被定义为通过其唯一的名称来标识特定的目标组件,其中声明的类型与匹配过程无关。 如果没有明确指定名称,则默认名称是从字段名称或设置方法(get、set方法)派生的。 如果用在字段上,则采用...
  • @Autowired注解与@Resource注解的区别

    千次阅读 2022-04-12 11:42:38
    @Resource是由J2EE提供的注解,需要导入包javax.annotation.Resource 也就是说@Autowired是外部包导入的,而@Resource是J2EE自己的 二、自动注入规则 @Autowired默认按照byType自动注入 @Autowired采取的是按照...
  • @Autowired 和 @Resource 这两个注解大家想必都有在项目里面出现过,但是真的清楚这俩玩意的用法或者说是区别么? 一直用的都是@Autowired ? 别人代码用什么就copy用什么,反正他没错,俺也不会错? 它们都是...
  • @Autowired 和 @Resource的区别

    千次阅读 2022-01-24 10:46:52
    1.@Autowired是Spring的,@Resource是javax包下的。 2.@Autowired默认按类型匹配,@Resource默认按名称匹配 3.@Autowired默认按类型匹配, spring容器中没有该类型的bean,报NoSuchBeanDefinitionException 有一个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,283,967
精华内容 513,586
关键字:

@resource

友情链接: MMC5983MA Driver.rar