一、自動裝配
自動裝配即爲Spring利用依賴注入來完成對IOC容器中各個組件的依賴關係賦值。
Spring框架的五種自動裝配模式:
- no:Spring框架的默認設置,在該設置下自動裝配是關閉的。開發者需要自行在bean定義中用標籤或註解來明確的設置依賴關係。
- byName:根據名稱設置依賴關係來自動裝配bean屬性。
- byType:根據類型設置依賴關係來自動裝配bean屬性。
- constructor:構造器的自動裝配和byType模式類似,但是僅僅適用於在容器中存在與構造器的參數相同類型的bean的情況,如果在容器中沒有找到與構造器的參數類型一致的bean,那麼將會拋出異常。
- autodetect:該模式自動探測使用構造器自動裝配或者byType自動裝配。首先會嘗試找合適的帶參數的構造器,如果找到的話就是用構造器自動裝配,如果在bean內部沒有找到相應的構造器或者是無參構造器,容器就會自動選擇byTpe的自動裝配方式。在Spring3.0之後已經被標記爲@Deprecated,不建議使用。
二、自動裝配相關注解
從Spring2.5開始,開始支持使用註解來自動裝配Bean的屬性。它允許更細粒度的自動裝配,我們可以選擇性的標註某一個屬性來對其應用自動裝配。Spring支持幾種不同的應用於自動裝配的註解。
- Spring自帶的@Autowired註解。
- JSR-250的@Resource註解。
- JSR-330的@Inject註解。
1.@Autowired
@Autowired註解默認優先按照類型(byType)去容器中找對應的組件。如果找到多個相同類型的組件,就將屬性的名稱作爲組件的id去容器中查找同id的bean再進行賦值。
@Autowired註解可以標註在構造器,參數,方法,屬性上。標註在方法位置可以不加@Autowired註解,方法參數是直接從容器中獲取的。(即爲constructor自動裝配模式)
使用
下面通過一個例子來掌握@Autowired的作用:
創建Dao層person類
@Repository
public class PersonDao {
public int flag=1;
@Override
public String toString() {
return "PersonDao [flag=" + flag + "]";
}
}
創建service層的personService類
@Service
public class PersonService {
@Autowired
PersonDao personDao;
@Override
public String toString() {
return "PersonService [personDao=" + personDao + "]";
}
}
這裏的PersonService 類還可以將@Autowired標註在不同的地方:屬性對應的set方法和構造方法。同樣能實現將personDao類型的組件裝配到PersonService類中。
@Service
public class PersonService {
PersonDao personDao;
@Override
public String toString() {
return "PersonService [personDao=" + personDao + "]";
}
public PersonService(@Autowired PersonDao personDao) {
this.personDao=personDao;
}
}
}
@Service
public class PersonService {
PersonDao personDao;
@Override
public String toString() {
return "PersonService [personDao=" + personDao + "]";
}
@Autowired
public void setPersonDao(PersonDao personDao) {
this.personDao=personDao;
}
}
創建配置類SpringConfigOfAutoWired類
@Configuration
@ComponentScan(value = {"com.learn.dao","com.learn.service"})
public class SpringConfigOfAutoWired {
@Bean
PersonDao personDao2() {
PersonDao personDao = new PersonDao();
personDao.flag=2;
return personDao;
}
}
創建測試類AutoWiredTest
public class AutoWiredTest {
@Test
public void test() {
//獲取Spring的IOC容器
AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfigOfAutoWired.class);
//從容器中獲取bean
String[] names= applicationContext.getBeanDefinitionNames();
for(String i:names) {
System.out.println(i);
}
PersonService service=applicationContext.getBean(PersonService.class);
System.out.println(service);
}
}
運行test()方法,查看控制檯結果:
可以看到@Autowired默認注入的是personDao,對應屬性名personDao。
默認情況下,它具有強制契約特性,其所標註的屬性必須是可裝配的。當容器中沒有這個類型的組件但又不想影響容器的創建,可以使用@Autowired(required = false)
。
另外,當容器中有多個相同類型的組件時,如果定義的這個屬性名在容器中沒有對應的組件id,那麼就會報NoUniqueBeanDefinitionException
這個異常。這時使用@Qualifier註解就可以避免這種情況。
@Qualifier
@Qualifier註解的作用是指定需要裝配的組件的id,相當於按照byName類型進行自動裝配。 @Qualifier不能單獨使用。
在 PersonService 類中添加註解@Qualifier("personDao2")
,這樣就指定了使用id爲personDao2的組件來裝配。
@Service
public class PersonService {
@Qualifier("personDao2")
@Autowired
PersonDao personDao3;
@Override
public String toString() {
return "PersonService [personDao=" + personDao3 + "]";
}
}
再次運行測試方法test(),查看控制檯輸出:
@Primary
讓Spring進行自動裝配時,優先使用@Primary註解修飾的組件。使用這個註解也能避免使用屬性名作爲id來查找容器中的組件,下面刪除前面添加的@Qualifier註解,在person2()方法上添加@Primary
@Configuration
@ComponentScan(value = {"com.learn.dao","com.learn.service"})
public class SpringConfigOfAutoWired {
@Primary
@Bean(value = "personDao2")
PersonDao personDao2() {
PersonDao personDao = new PersonDao();
personDao.flag=2;
return personDao;
}
}
這樣自動裝配時就會優先裝配id爲personDao2的組件。
2.@Resource
@Resource屬於java規範中的註解,@Resource可以與@Autowired一樣實現自動裝配功能,默認是按照屬性名的名稱進行裝配。可以通過@Resource(name = “”)指定組件的id,如果byName方式找不到,就使用byType方式查找。但是不支持搭配@Primary和@Qualifier("")使用和不支持@Autowired的required功能。
使用
修改類PersonService 改用@Resource進行自動裝配
@Service
public class PersonService {
//@Qualifier("personDao2")
//@Autowired(required = false)
@Resource
PersonDao personDao3;
@Override
public String toString() {
return "PersonService [personDao=" + personDao3 + "]";
}
}
這樣也是能成功裝配組件。這裏如果添加@Primary和@Qualifier("")來指定組件,雖然不會報錯但是是不起作用的。
3.@Inject
@Inject屬於java規範中的註解,同樣提供與@Autowired一樣實現自動裝配功能,支持搭配@Primary和@Qualifier("")註解使用,但是沒有支持required=false的功能。
@Inject是根據類型進行自動裝配的,找到後以屬性名作爲id來匹配要裝配的組件,如果存在多個相同類型的組件時或需要按名稱進行裝配,則需要配合@Named;
需要在pom.xml中添加以下依賴才能使用:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
使用
@Service
public class PersonService {
//@Qualifier("personDao2")
//@Autowired(required = false)
//@Resource
@Named("personDao2")
@Inject
PersonDao personDao3;
@Override
public String toString() {
return "PersonService [personDao=" + personDao3 + "]";
}
}
這樣同樣能成功裝配PersonDao類型的id爲personDao2的組件。
三、總結
-
@Autowired是spring自帶的,@Resource是JSR-250規範實現的,@Inject是JSR-330規範實現的,需要對應導入不同的包。
-
@Autowired、@Inject用法基本一樣,不同的是@Autowired有一個request屬性
-
@Autowired、@Inject是默認按照類型匹配的,@Resource是按照名稱匹配的
-
@Autowired如果需要按照名稱匹配需要和@Qualifier一起使用,@Inject和@Name一起使用
-
@Inject支持搭配@Primary和@Qualifier("")註解一起使用
參考:annotation之@Autowired、@Inject、@Resource三者區別
拓展閱讀:
徹底搞明白Spring中的自動裝配和Autowired
XML配置文件中實現自動裝配——Spring 自動裝配及其註解