1. 程式人生 > >基於註解的元件掃描——Spring IOC/DI(五)

基於註解的元件掃描——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概述