spring注解驱动开发-(8) 自动装配 @Autowired @Resource @Qualifier @Primary

@Autowired

spring的注解, 用来做自动装配; 如果用于属性上:

首先按照 类型
匹配, 类型匹配失败会用 name
匹配;

如果匹配到 多个
: 再用 @Qualifier("beanName")
的beanName来筛选, 看装配哪个bean;

如果一个都匹配不到, 而且声明了属性 required=false , 不调用不会报错; 调用就会 NoSuchBeanDefinitionException
;

不仅可以用在 属性
上, 也可以用到 方法
/ 构造器
/ 方法参数
上: (用在方法上和用在入参上意义是相同的)

如果使用在set方法上和构造方法上, 都有入参; 不论有没有@Autowired注解在方法上和参数上, 都会从IOC容器中去装配, 不会报错;

@Qualifier

@Qualifier的作用如上; 用来在装配某个类型的bean时, 找到多个bean后用它的value作为name来区分;

@Primary

如果某个类型的bean在IOC容器中有多个可以匹配到; 在装配时又没有指定@Qualifier(value="beanName"); 此时, 就会首先筛选声明时标注了 @Primary的bean来装配!

@Resource

JSR250的注解, 属于java规范;

@Resource默认先按照name来匹配, 如果 name
匹配不到, 再按照 类型
去匹配; 也可以和 @Qualifier 和 @Primary 一起使用;

@Resource和@Autowired比较:

不同点

  1. @Resource首先按照 name
    匹配, 匹配不到采用 类型
    ; @Autowired首先按照 类型
    匹配, 匹配到多个才会用 name
    筛选;
  2. @Resource是JSR250的注解, 是java规范定义的; @Autowired是spring定义的注解;
  3. @Resource没有@Autowired(required=false)里的 required
    属性, 没有可选bean, 即使不调用, 也会报: NoSuchBeanDefinitionException
    ;
  4. @Resource不能使用到 参数
    构造方法
    上; @Autowired可以(ElementType.PARAMETER, ElementType.CONSTRUCTOR)!

共同点:

  1. 都有备选机制: 即 name
    类型
    双备选, 一个找不到, 用另一个;
  2. 当匹配到多个时, 都可以配合使用@Qualifier 和 @Primary来区分;
  3. 当匹配到多个时, 匹配到多个, 也没有@Qualifier 和 @Primary注解区分, 两个注解都会报异常:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.niewj.service.ProductService' available: expected single matching bean but found 2: productService,productService2

配置类: 这里有一个ProductService初始化: productService2

package com.niewj.config;

import com.niewj.service.ProductService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan({"com.niewj.controller", "com.niewj.service"})
public class AutowiredTestConfig {

    // @Primary
    @Bean(name = "productService2")
    public ProductService product2(){
        ProductService productService = new ProductService();
        productService.setLabel("2");
        return productService;
    }
}

Service类: 这里也有一个ProductService注入springIOC: productService(默认名字类名首字母小写)

package com.niewj.service;

import lombok.Data;
import org.springframework.stereotype.Service;

@Data
@Service
public class ProductService {
    private String label="1";
    public void print(){
        System.out.println("ProductService --> print");
    }
}

Controller类:

package com.niewj.controller;

import com.niewj.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class ProductController {

//    // 不指定 @Qualifier("productService2") 时, 在 productService2 处使用 @Primary也能首选 productService2
//    // 指定 @Qualifier("productService2")
//    @Qualifier("productService3")  // 如果没有指定 required=false, 匹配不到则会报告异常: NoSuchBeanDefinitionException
//    //  @Autowired(required = false)
//    @Autowired
//    private ProductService productService;

    @Autowired
    private ProductService productService2;

    public void doPrint(){
        System.out.println(productService2);
    }
}

测试用例:

package com.niewj;

import com.niewj.config.AutowiredTestConfig;
import com.niewj.controller.ProductController;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.stream.Stream;

/**
 * spring 自动装配
 */
public class AutowiredTest {

    @Test
    public void testAutowired() {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AutowiredTestConfig.class);

        // 打印spring容器中的 BeanDefinition
        Stream.of(ctx.getBeanDefinitionNames()).forEach(e-> System.out.println(e));
        System.out.println("=============================");

        ProductController productController = ctx.getBean(ProductController.class);
        productController.doPrint();

        ctx.close();
    }

}

output:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
autowiredTestConfig
bookController
productController
testController
subPacController
bookService
productService
productService2
=============================
ProductService(label=2)

自动装配原理:

@Autowired/@Value/@Inject等注解都是用 AutowiredAnnotationBeanPostProcessor
类实现的~BeanPostProcessor;

同样的实现还有: Aware接口

@ApplicationContextAware 可以获取IOC容器上下文;

@ApplicationEventPublisherAware 获取事件发布器;

@EnvironmentAware 获取属性配置信息;

@EmbeddedValueResolverAware 内置字段的解析, 可以支持 ${}表达式, spEL #{}等;

原文 

https://segmentfault.com/a/1190000023239630

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » spring注解驱动开发-(8) 自动装配 @Autowired @Resource @Qualifier @Primary

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址