基於註解的元件掃描——Spring IOC/DI(五)
上一章我們講了無註解的自動裝配:
https://blog.csdn.net/qq_34598667/article/details/83317377
這一章我們講一下基於註解的裝配,元件掃描
基於註解的元件掃描
案例準備:
之前案例com.oak.entity中的Person類
public class Person {
private String name;
private Integer age;
//構造方法等方法略
...
}
在包com.oak.dao中新建一個PersonDao介面如下:
public interface PersonDao {
void msg();
}
在同包下新建一個PersonDaoImpl實現PersonDao:
public class PersonDaoImpl implements PersonDao{
private Person person=new Person();
@Override
public void msg() {
System.out.println(person);
}
}
在包com.oak.service中新建PersonService類,呼叫PersonDao:
public class PersonService {
private PersonDao personDao= new PersonDaoImpl();
public void msg(){
personDao.msg();
}
}
以上述程式碼為例解析註解
什麼是元件掃描?
我們之前的案例中發現,在建立bean時需要在xml中配置大量的< bean >定義,書寫過於複雜。我們可以指定一個包路徑,讓spring自動掃描該包(及子包)下所有的元件類,當發現類定義了前有特定的spring註解時,就在spring容器中建立其對應的bean。等價於在xml中配置。
指定元件掃描路徑
在xml中使用<context:component-scan base-package=“指定包路徑”>指定掃描路徑
注意:有些同學在加入這一句話之後會有報錯,不要忘了宣告xml名稱空間,在beans中新增
xmlns:context="http://www.springframework.org/schema/context"
在schemaLocation中新增
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
新增之後的程式碼為:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<!--指定註解掃描包路徑-->
<context:component-scan base-package="com.oak"/>
</beans>
如果例項化容器時出現巢狀異常,則需要匯入aop的jar包:spring-aop-4.2.4.RELEASE.jar
元件類掃描路徑
如果在包中指定了註解掃描的路徑,則在該路徑下如果出現以下註解都會被載入進spring建立bean
@Component 通用註解 都可用(預設bean名稱以類名小寫開頭,可自定義)
@Named 同上
@Repository 持久層註解元件
@Service 業務層元件註解
@Controller 控制層元件註解
@Component
例:給Person加上@Component註解
@Component
public class Person {
private String name;
private Integer age;
//構造方法等方法略
...
}
新建testAnnotation方法並測試:
@Test
public void testAnnotation(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Person person=ctx.getBean("person",Person.class);
System.out.println(person);
}
控制檯輸出:
Person [name=null, age=null]
由此可見,已經為Person類建立了Bean,但是並沒有給屬性注入值。
同樣可以使用其他註解給相應的類添加註解,例如,給持久層dao添加註解並指定bean名稱:
@Repository("personDao")//相當於在配置檔案中 <bean id="personDao" class="……"></bean>
public class PersonDaoImpl implements PersonDao{
private Person person=new Person();
@Override
public void msg() {
System.out.println(person);
}
}
在test中測試:
@Test
public void testAnnotation(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonDao person=ctx.getBean("personDao",PersonDao.class);
person.msg();
}
控制檯輸出:
Person [name=null, age=null]
指定依賴注入關係註解
@Autowired/@Qualifier
處理構造器注入和setter注入
用法:
@Autowired :可以用於 Setter 方法、建構函式、欄位,甚至普通方法,前提是方法必須有至少一個引數。
@Qualifier :當容器中存在多個 Bean 的型別與需要注入的引數型別相同時,注入將不能執行,可以使用@Qualifier 標註,提供一個 String 型別的值作為候選的 Bean 的名字
案例:使用註解完成bean的例項化和屬性的注入,完成上述程式碼的解耦:
修改Person,使用註解@Value給屬性注入值
@Component
public class Person {
@Value("二狗")
private String name;
@Value("18")
private Integer age;
//構造方法等方法略
...
}
修改PersonDaoImpl檔案,新增@autowired註解:
@Repository("personDao")
public class PersonDaoImpl implements PersonDao{
@Autowired //自動裝配,根據類名稱去找相應的類來建立物件
private Person person;
@Override
public void msg() {
System.out.println(person);
}
}
直接測試剛才的方法,使用了註解完成自動裝配:
Person [name=二狗, age=18]
假設現在Spring容器中存在兩個Person型別的bean :person和person1,則使用@Autowired無法完成自動裝配,需要使用@Qualifier來指定bean的名稱,例如:
@Repository("personDao")
public class PersonDaoImpl implements PersonDao{
@Autowired //自動裝配,根據類名稱去找相應的類來建立物件
@Qualifier("person")//當多個Person型別的bean存在時,可以指定自動裝配的bean名稱
private Person person;
@Override
public void msg() {
System.out.println(person);
}
}
@Inject/@Named
用法與同上,只不過需要額外導包
@Resource/@Name
只能處理setter注入
@Resource 相當於@Autowired
@Name的作用相當於@Qualifier
修改PersonService,使用@Service給業務層建立bean,使用@Resource 完成自動裝配
@Service//@Component 業務層元件掃描
public class PersonService {
@Resource(name="personDao")//指定bean名稱注入
private PersonDao personDao;
public void msg(){
personDao.msg();
}
}
修改測試方法為:
@Test
public void testAnnotation(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonDao person=ctx.getBean("personDaoImpl",PersonDao.class);
person.msg();
PersonService service=ctx.getBean("personService",PersonService.class);
service.msg();
}
測試結果為:
Person [name=二狗, age=18]
Person [name=二狗, age=18]
@Autowired和@Resource的區別
1)@Autowired與@Resource都可以用來裝配bean. 都可以寫在欄位上,或寫在setter方法上。
2)@Autowired預設按型別裝配(這個註解是屬業spring的),預設情況下必須要求依賴物件必須存在,如果要允許null值,可以設定它的required屬性為false,如:@Autowired(required=false) ,如果我們想使用名稱裝配可以結合@Qualifier註解進行使用
3)@Resource(這個註解屬於J2EE的),預設按照名稱進行裝配,名稱可以通過name屬性進行指定,如果沒有指定name屬性,當註解寫在欄位上時,預設取欄位名進行安裝名稱查詢,如果註解寫在setter方法上預設取屬性名進行裝配。當找不到與名稱匹配的bean時才按照型別進行裝配。但是需要注意的是,如果name屬性一旦指定,就只會按照名稱進行裝配。
下一章,Spring AOP概述