spring注解之自動裝配和屬性賦值


1.自動裝配

1.1什么是自動裝配?

  Spring利用依賴注入(DI),完成對IOC容器中各個組件的依賴關系賦值

1.2@Autowired/@Qualifier/@Primary

1.2.1@Autowired基本使用

-默認優先按照類型去容器中找對應的組件:applicationContext.getBean(BookDao.class) 找到就賦值;

@Service
public class BookService {
    @Autowired //將BookDao組件裝配到當前組件中,找到就賦值
    private BookDao bookDao;  
}

-如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找  applicationContext.getBean("bookDao")

比方說在配置類中再添加個BookDao組件代碼如下:

@ComponentScan({"com.athome.service","com.athome.dao"})
@Configuration
public class MainAutowiredConfig {
    @Bean("bookDao2")public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setTag("2");
        return  bookDao;
    }
}

那么上面的兩段代碼都有相同類型BookDao組件,這種情況下按照屬性名稱找對應的組件,找到就賦值;

如上面代碼處 ,屬性名是bookDao,則找該組件,如果處 屬性名改為成 處的名字( bookDao2) ,這種情況則找id為bookDao2的組件。

 

@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;

}

從@Autowired定義來看,該注解可修飾 構造器、方法、參數、屬性、注解

  • 標注在方法上:根據方法的形參,從容器中查找
@Component
public class Teacher {
    private Book book;
@Autowired
  //標注在方法,Spring容器創建當前對象,就會調用方法,完成賦值;
    //方法使用的參數,自定義類型的值從ioc容器中獲取
public Book getBook() { return book; } public void setBook(Book book) { this.book = book; } @Override public String toString() { return "Teacher{" + "book=" + book + '}'; } }

 

    @Bean("teacher2")
    public Teacher teacher(@Autowired Book book){
        Teacher teacher = new Teacher();
        teacher.setBook(book);
        return  teacher;
    }
//@Bean+方法參數;參數從容器中獲取;默認不寫@Autowired效果是一樣的;都能自動裝配
上面淺紫色區域可以不寫

 

  • 標注在構造器:默認調用無參構造器;
//默認加在ioc容器中的組件,容器啟動會調用無參構造器創建對象,再進行初始化賦值等操作
@Component
public class Teacher {
    private Book book;

    //構造器要用的組件,都是從容器中獲得
    @Autowired
    public Teacher (Book book){
        this.book = book;
    }

    public Book getBook() {
        return book;
    }
    public void setBook(Book book) {
        this.book = book;
    }
    @Override
    public String toString() {
        return "Teacher{" + "book=" + book + '}';
    }
}

//如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件還是可以自動從容器中獲取

 

  • 標注在參數中:根據參數組件值從容器中查找對應的組件
@Component
public class Teacher {
    private Book book;

    //標注在形參上也是一樣,都是從容器中獲得public Teacher ( @Autowired Book book){
        this.book = book;
    }

    @Autowired
    public Book getBook() {
        return book;
    }
    public void setBook(Book book) {
        this.book = book;
    }
    @Override
    public String toString() {
        return "Teacher{" + "book=" + book + '}';
    }
}

 

1.2.2@Qualifier

@Qualifier指定需要裝配的組件的id,而不是使用屬性名

@Service
public class BookService {

    @Qualifier("bookDao2")
    @Autowired
    private BookDao bookDao;
    public void print(){
        System.out.println(bookDao);
    }
    @Override
    public String toString() {
        return "BookService{" + "bookDao=" + bookDao + '}';
    }
}

 

上面這段代碼,裝配組件id為 bookDao2 的組件,並不是 屬性名為bookDao 的組件

1.2.3@Primary

讓Spring進行自動裝配的時候,默認使用首選的bean; 

也可以繼續使用@Qualifier指定需要裝配的bean的名字;

@ComponentScan({"com.athome.service","com.athome.dao"})
@Configuration
public class MainAutowiredConfig {
    @Primary
    @Bean("bookDao2")
    public BookDao bookDao(){
        BookDao bookDao = new BookDao();
        bookDao.setTag("2");
        return  bookDao;
    }
}

在沒有使用@Qualifier指定裝配的情況下,上面的代碼則會,首選裝配 bookDao2組件
--------------------------------------------------------------------
 @Service public class BookService {
   @Qualifier("bookDao") @Autowired private BookDao bookDao; }
 @Primary @Qualifier("bookDao") 都在使用的話,則  使用@Qualifier("bookDao")指定的組件

 

1.2.4 @Autowired(required=false)

 因為 required=false,如果spring找不到對應的組件的話會賦空值進去;

@Service
public class BookService {
   @Autowired(required = false)//如果容器中沒有BookDao組件的話, 則bookDao=null private BookDao bookDao; public void print(){ System.out.println(bookDao); } @Override public String toString() { return "BookService{" + "bookDao=" + bookDao + '}'; } }
 

1.3@Resource(JSR250)和@Inject(JSR330)

  • @Resource:默認是按照組件名稱進行裝配的;
@Service
public class BookService {

 //   @Qualifier("bookDao2")
//    @Autowired(required = false)
    @Resource
    private BookDao bookDao;
    public void print(){
        System.out.println(bookDao);
    }
    @Override
    public String toString() {
        return "BookService{" + "bookDao=" + bookDao + '}';
    }
}

@Resource@Autowired一樣實現自動裝配功能;
默認是按照組件名稱進行裝配的;
沒有能支持@Primary功能,沒有支持@Autowired(reqiured=false)和 Qualifier
@Resource(name = "bookDao2"),則裝配bookDao2組件

 

  • @Inject:需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能,加@Named注解指定bean 的Id;
@Service
public class BookService {

   // @Qualifier("bookDao2")
    @Inject
    @Named("bookDao2")
    private BookDao bookDao;
    public void print(){
        System.out.println(bookDao);
    }
    @Override
    public String toString() {
        return "BookService{" + "bookDao=" + bookDao + '}';
    }
}

@Inject 和 @Qualifier 、@Primary 、@Named 可組合使用

 

 

1.4Aware注入Spring底層組件

自定義組件想要使用Spring容器底層的組件(ApplicationContext、BeanFactory、 ......)
思路: 自定義組件實現xxxAware, 在創建對象的時候, 會調用接口規定的方法注入到相關組件:XXXAware

 

 查看有哪些接口繼承了Aware接口:

 

參考代碼:

@Component
public class Person implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {
    
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("傳入的ioc:"+applicationContext);
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
        // TODO Auto-generated method stub
        System.out.println("當前bean的名字:"+name);
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        // TODO Auto-generated method stub
        String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
        System.out.println("解析的字符串:"+resolveStringValue);
    }
}
 
分析:Aware注入Spring底層組件原理
把Spring底層的組件可以注入到自定義的bean中,ApplicationContextAware是利用ApplicationContextAwareProcessor來處理的,
其它XXXAware也類似, 都有相關的Processor來處理,其實就是后置處理器來處理。
XXXAware---->功能使用了XXXProcessor來處理的,這就是后置處理器的作用;
ApplicaitonContextAware--->ApplicationContextProcessor后置處理器來處理的
 

1.5@Profile

 @Profile:Spring為我們提供的可以根據當前環境,動態的激活和切換一系列組件的功能;

指定組件在哪個環境的情況下才能被注冊到容器中,不指定,任何環境下都能注冊這個組件

 

參考代碼:

/**
 * Profile:指定組件在哪個環境的情況下才能被注冊到容器中,不指定,任何環境下都能注冊這個組件
 * 1)、加了環境標識的bean,只有這個環境被激活的時候才能注冊到容器中。默認是default環境
 * 2)、寫在配置類上,只有是指定的環境的時候,整個配置類里面的所有配置才能開始生效
 * 3)、沒有標注環境標識的bean在,任何環境下都是加載的;
 */
@Configuration
public class ConfigProfile {

    @Profile("test")
    @Bean("profileTest")
    public void profileTest() {
        System.out.println("profileTest");
    }

    @Profile("dev")
    //@Profile("default") 默認生效該Bean組件
    @Bean("profileDev")
    public void profileDev() {
        System.out.println("profileDev");
    }

    @Profile("prod")
    @Bean("profileProd")
    public void profileProd() {
        System.out.println("profileProd");
    }
}

 

 測試代碼:

public class IOC_ProfileTest {
    //1、使用命令行動態參數: 在虛擬機參數位置加載 -Dspring.profiles.active=test
    //2、代碼的方式激活某種環境;
    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //1、創建一個applicationContext
        //2、設置需要激活的環境
        context.getEnvironment().setActiveProfiles("dev");
        //3、注冊主配置類
        context.register(ConfigProfile.class);
        //4、啟動刷新容器
        context.refresh();

        String[] names = context.getBeanDefinitionNames();
        for (String s: names) {
            System.out.println(s);
        }
    }
}

 

測試結果:

 

 

2.屬性賦值

使用@Value賦值:
1.基本數值
2.可以寫SpEL; #{}
3.可以寫${};取出配置文件【properties】中的值(在運行環境變量里面的值)


下面是一個Bean: Person類
public class Person {
@Value("高菲") //基本數值 private String name;
@Value(
"#{20-2}") //SpEL表達式 #{} private Integer age;
@Value(
"${person.nickName}") //取出配置文件中的數據 ${} private String nickName;   下面代碼是 setter/getter/toString方法 }

 

 配置類:

@PropertySource:讀取外部配置文件中的 K / V 保存到運行環境變量中;加載完外部的配置文件以后使用${}取出配置文件的值。

@PropertySource(value = {"classpath:/person.properties"})//獲取外部配置文件
@Configuration
public class MainConfigOfPropertyValue {

    @Bean
    public Person person(){
        return new Person();
    }
}

 

測試類:

 @Test
    public void test(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValue.class);
        Person person = (Person) applicationContext.getBean("person");
        String[] names = applicationContext.getBeanDefinitionNames();
        for (String  s: names) {
            System.out.println("mainConfigOfPropertyValue配置類中有哪些bean -->"+s);
        }
        System.out.println(person);
        //可以通過運行環境來獲取配置文件中的數據
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        String property = environment.getProperty("person.nickName");
        System.out.println("運行環境取配置文件中的值: "+property);
    }

運行結果:

 

3.小結

  • 自動裝配:Spring利用依賴注入(DI),完成對IOC容器中各個組件的依賴關系賦值;

  1)、@Autowired:自動注入:
          1)、默認優先按照類型去容器中找對應的組件:applicationContext.getBean(BookDao.class);找到就賦值
          2)、如果找到多個相同類型的組件,再將屬性的名稱作為組件的id去容器中查找
                              applicationContext.getBean("bookDao")
          3)、@Qualifier("bookDao"):使用@Qualifier指定需要裝配的組件的id,而不是使用屬性名
          4)、自動裝配默認一定要將屬性賦值好,沒有就會報錯;
              可以使用@Autowired(required=false);
          5)、@Primary:讓Spring進行自動裝配的時候,默認使用首選的bean;
                  也可以繼續使用@Qualifier指定需要裝配的bean的名字
          BookService{  
              @Autowired
              BookDao  bookDao;
          }
  
  2)、Spring還支持使用@Resource(JSR250)和@Inject(JSR330)[java規范的注解]
          @Resource:
              可以和@Autowired一樣實現自動裝配功能;默認是按照組件名稱進行裝配的;
              沒有能支持@Primary功能沒有支持@Autowired(reqiured=false);
          @Inject:
              需要導入javax.inject的包,和Autowired的功能一樣。沒有required=false的功能;
   @Autowired:Spring定義的; @Resource、@Inject都是java規范
      
  AutowiredAnnotationBeanPostProcessor:解析完成自動裝配功能;        
  
  3)、 @Autowired:構造器,參數,方法,屬性;都是從容器中獲取參數組件的值
          1)、[標注在方法位置]:@Bean+方法參數;參數從容器中獲取;默認不寫@Autowired效果是一樣的;都能自動裝配
          2)、[標在構造器上]:如果組件只有一個有參構造器,這個有參構造器的@Autowired可以省略,參數位置的組件還是可以自動從容器中獲取
          3)、放在參數位置:
  
  4)、自定義組件想要使用Spring容器底層的一些組件(ApplicationContext,BeanFactory,xxx);
          自定義組件實現xxxAware;在創建對象的時候,會調用接口規定的方法注入相關組件;Aware;
          把Spring底層一些組件注入到自定義的Bean中;
          xxxAware:功能使用xxxProcessor;ApplicationContextAware==》ApplicationContextAwareProcessor;
  • 屬性賦值

  @Value("基本數值")

  @Value("SpEL表達式")    - #{}

  @Value("獲取配置文件中值")  - ${}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM