spring註解驅動開發-(8) 自動裝配 @Autowired @Resource @Qualifier @Primary

@Autowired

spring的註解, 用來作自動裝配; 若是用於屬性上:java

首先按照 類型匹配, 類型匹配失敗會用 name匹配;

若是匹配到多個: 再用@Qualifier("beanName")的beanName來篩選, 看裝配哪一個bean;spring

若是一個都匹配不到, 並且聲明瞭屬性 required=false , 不調用不會報錯; 調用就會 NoSuchBeanDefinitionException;shell

不只能夠用在屬性上, 也能夠用到方法/構造器/方法參數上: (用在方法上和用在入參上意義是相同的)測試

若是使用在set方法上和構造方法上, 都有入參; 不論有沒有@Autowired註解在方法上和參數上, 都會從IOC容器中去裝配, 不會報錯;

@Qualifier

@Qualifier的做用如上; 用來在裝配某個類型的bean時, 找到多個bean後用它的value做爲name來區分;

@Primaryui

若是某個類型的bean在IOC容器中有多個能夠匹配到; 在裝配時又沒有指定@Qualifier(value="beanName"); 此時, 就會首先篩選聲明時標註了 @Primary的bean來裝配!

@Resource

JSR250的註解, 屬於java規範;

@Resource默認先按照name來匹配, 若是name匹配不到, 再按照類型去匹配; 也能夠和 @Qualifier 和 @Primary 一塊兒使用;code

@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類:get

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);
    }
}

測試用例:it

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 #{}等;

相關文章
相關標籤/搜索