目錄
2.2 例1:通過resource-pattern指定掃描的資源
四、使用 @Resource 或 @Inject 自動裝配 Bean
spring掃描組件這個使用頻率是比較高的,要熟悉
一、知識點
- 組件掃描(component scanning): Spring 能夠從 classpath 下自動掃描, 偵測和實例化具有特定註解的組件.
- 特定組件包括:
- @Component: 基本註解, 標識了一個受 Spring 管理的組件
- @Repository: 標識持久層組件
- @Service: 標識服務層(業務層)組件
- @Controller: 標識表現層組件
- 對於掃描到的組件, Spring 有默認的命名策略: 使用非限定類名, 第一個字母小寫. 也可以在註解中通過 value 屬性值標識組件的名稱
1、@controller 控制器(注入服務)
2、@service 服務(注入dao)
3、@repository dao(實現dao訪問)
4、@component (把普通pojo實例化到spring容器中,相當於配置文件中的<bean id="" class=""/>)@Component,@Service,@Controller,@Repository註解的類,並把這些類納入進spring容器中管理。
下面寫這個是引入component的掃描組件
<context:component-scan base-package=”com.mmnc”>
其中base-package爲需要掃描的包(含所有子包)
1、@Service用於標註業務層組件
2、@Controller用於標註控制層組件(如struts中的action)
3、@Repository用於標註數據訪問組件,即DAO組件.
4、@Component泛指組件,當組件不好歸類的時候,我們可以使用這個註解進行標註。
@Service public class UserServiceImpl implements UserService { }
@Repository public class UserDaoImpl implements UserDao { } getBean的默認名稱是類名(頭字母小寫),如果想自定義,可以@Service(“***”) 這樣來指定,這種bean默認是單例的,如果想改變,可以使用@Service(“beanName”) @Scope(“prototype”)來改變。
可以使用以下方式指定初始化方法和銷燬方法(方法名任意): @PostConstruct public void init() { }
- 當在組件類上使用了特定的註解之後, 還需要在 Spring 的配置文件中聲明 <context:component-scan> :
- base-package 屬性指定一個需要掃描的基類包,Spring 容器將會掃描這個基類包裏及其子包中的所有類.
- 當需要掃描多個包時, 可以使用逗號分隔.
- 如果僅希望掃描特定的類而非基包下的所有類,可使用 resource-pattern 屬性過濾特定的類,示例:
<context:component-scan base- package= "com.hualinux.spring.beans resource- pattern= "autowire/*.class"/ >
- <context:include-filter> 子節點表示要包含的目標類
- <context:exclude-filter> 子節點表示要排除在外的目標類
- <context:component-scan> 下可以擁有若干個 <context:include-filter> 和 <context:exclude-filter> 子節點
- <context:include-filter> 和 <context:exclude-filter> 子節點支持多種類型的過濾表達式:
二、例子
2.1 普通例子
2.1.1 目錄結構
2.1.2 代碼
src--> beans-annotation.xml
src右擊-->new-->XML Configuration File-->Spring config-->輸入名字“beans-annotation” ,凡是後面創建xml我都簡寫
src-->xxx.xml
<!-- 指定Spring IOC 容器掃描的包-->
<context:component-scan base-package="com.hualinux.beans.annotation" />
src-->com.hualinux.beans.annotation.controller.UserController.java
package com.hualinux.beans.annotation.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
public void execute(){
System.out.println("UserController execute...");
}
}
src-->com.hualinux.beans.annotation.repository.UserRepository.java
package com.hualinux.beans.annotation.repository;
public interface UserRepository {
void save();
}
src-->com.hualinux.beans.annotation.repository.UserRepositoryImpl.java
package com.hualinux.beans.annotation.repository;
import org.springframework.stereotype.Repository;
@Repository("userRepository")
public class UserRepositoryImpl implements UserRepository {
@Override
public void save() {
System.out.println("UserRepository Save...");
}
}
src-->com.hualinux.beans.annotation.service.UserService.java
package com.hualinux.beans.annotation.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void add(){
System.out.println("UserService add...");
}
}
src-->com.hualinux.beans.annotation.TestObject.java
package com.hualinux.beans.annotation;
import org.springframework.stereotype.Component;
@Component
public class TestObject {
}
src-->com.hualinux.beans.annotation.Main.java
package com.hualinux.beans.annotation;
import com.hualinux.beans.annotation.controller.UserController;
import com.hualinux.beans.annotation.repository.UserRepository;
import com.hualinux.beans.annotation.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-annotation.xml");
TestObject to = (TestObject) ctx.getBean("testObject");
System.out.println(to);
UserController userController = (UserController) ctx.getBean("userController");
System.out.println(userController);
UserService userService = (UserService) ctx.getBean("userService");
System.out.println(userService);
UserRepository userRepository = (UserRepository) ctx.getBean("userRepository");
System.out.println(userRepository);
}
}
運行如果如下:
com.hualinux.beans.annotation.TestObject@bcec361
com.hualinux.beans.annotation.controller.UserController@26794848
com.hualinux.beans.annotation.service.UserService@302552ec
com.hualinux.beans.annotation.repository.UserRepositoryImpl@3d285d7e
2.2 例1:通過resource-pattern指定掃描的資源
上面的例子就是了,在這裏把上面例子中的 com.hualinux.beans.annotation.Main.java修改一下,只剩下“UserRepository”其餘的註解掉,以方便後臺例子測試
package com.hualinux.beans.annotation;
import com.hualinux.beans.annotation.controller.UserController;
import com.hualinux.beans.annotation.repository.UserRepository;
import com.hualinux.beans.annotation.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-annotation.xml");
/* TestObject to = (TestObject) ctx.getBean("testObject");
System.out.println(to);
UserController userController = (UserController) ctx.getBean("userController");
System.out.println(userController);
UserService userService = (UserService) ctx.getBean("userService");
System.out.println(userService);*/
UserRepository userRepository = (UserRepository) ctx.getBean("userRepository");
System.out.println(userRepository);
}
}
2.3 例2:過濾表達式<context:include-filter>
<context:include-filter> 和 <context:exclude-filter> 子節點支持多種類型的過濾表達式
<!-- context:exclude-filter 子節點指定排除哪些指定表達式組件 context:include-filter 子節點指定包含哪些表達式組件,該子節點需要 use-default-filters 配合使用 -->
修改一下 beans-annotation.xml配置文件
<!-- 指定Spring IOC 容器掃描的包-->
<!-- 可以通過resource-pattern指定掃描的資源
<context:component-scan base-package="com.hualinux.beans.annotation" resource-pattern="repository/*.class" />-->
<!-- context:exclude-filter子節點指定排除哪些指定表達式組件-->
<context:component-scan base-package="com.hualinux.beans.annotation" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />
</context:component-scan>
<!-- <!– 指定Spring IOC 容器掃描的包–>
<context:component-scan base-package="com.hualinux.beans.annotation" />-->
運行com.hualinux.beans.annotation.Main.java,結果爲:
com.hualinux.beans.annotation.repository.UserRepositoryImpl@489115ef
2.4 例3:過濾表達式<context:exclude-filter>
修改beans-annotation.xml配置文件
<!--
context:exclude-filter 子節點指定排除哪些指定表達式組件
context:include-filter 子節點指定包含哪些表達式組件,該子節點需要 use-default-filters 配合使用
-->
<context:component-scan base-package="com.hualinux.beans.annotation" >
<context:exclude-filter type="assignable" expression="com.hualinux.beans.annotation.repository.UserRepository" />
</context:component-scan>
<!-- 指定Spring IOC 容器掃描的包-->
<!-- 可以通過resource-pattern指定掃描的資源
<context:component-scan base-package="com.hualinux.beans.annotation" resource-pattern="repository/*.class" />-->
<!-- context:exclude-filter子節點指定排除哪些指定表達式組件-->
<!--
<context:component-scan base-package="com.hualinux.beans.annotation" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />
</context:component-scan>
-->
<!-- <!– 指定Spring IOC 容器掃描的包–>
<context:component-scan base-package="com.hualinux.beans.annotation" />-->
com.hualinux.beans.annotation.Main.java修改如下
package com.hualinux.beans.annotation;
import com.hualinux.beans.annotation.controller.UserController;
import com.hualinux.beans.annotation.repository.UserRepository;
import com.hualinux.beans.annotation.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-annotation.xml");
TestObject to= (TestObject) ctx.getBean("testObject");
System.out.println(to);
UserController userController= (UserController) ctx.getBean("userController");
System.out.println(userController);
UserService userService= (UserService) ctx.getBean("userService");
System.out.println(userService);
// UserRepository userRepository= (UserRepository) ctx.getBean("userRepository");
// System.out.println(userRepository);
}
}
運行它,結果如下
com.hualinux.beans.annotation.TestObject@3c9754d8
com.hualinux.beans.annotation.controller.UserController@3bf7ca37
com.hualinux.beans.annotation.service.UserService@79079097
三、組件裝配
3.1 知識點
- <context:component-scan> 元素還會自動註冊 AutowiredAnnotationBeanPostProcessor 實例, 該實例可以自動裝配具有 @Autowired 和 @Resource 、@Inject註解的屬性.
3.2 沒使用組件裝配引入的例子
根據:
1、@controller 控制器(注入服務)
2、@service 服務(注入dao)
3、@repository dao(實現dao訪問)
4、@component (把普通pojo實例化到spring容器中,相當於配置文件中的<bean id="" class=""/>)
沒裝配前的代碼:beans-annotation.xml 只有下面代碼
<context:component-scan base-package="com.hualinux.beans.annotation" />
com.hualinux.beans.annotation.controller.UserController修改爲:
package com.hualinux.beans.annotation.controller;
import com.hualinux.beans.annotation.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
//這個註解一定要寫,否則不能自動添加到Ioc容器中,我這裏故意先不寫
//@Controller
public class UserController {
@Autowired
private UserService userService;
public void execute(){
System.out.println("UserController execute...");
userService.save();
}
}
com.hualinux.beans.annotation.service.UserService.java修改爲
package com.hualinux.beans.annotation.service;
import com.hualinux.beans.annotation.repository.UserRepository;
import org.springframework.stereotype.Service;
@Service
public class UserService implements UserRepository{
@Override
public void save() {
System.out.println("UserRepository Save...");
}
}
com.hualinux.beans.annotation. repository.UserRepository.java不變
com.hualinux.beans.annotation. repository.UserRepositoryImpl.java不變
com.hualinux.beans.annotation.Main.java修改爲
package com.hualinux.beans.annotation;
import com.hualinux.beans.annotation.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext ctx=new ClassPathXmlApplicationContext("beans-annotation.xml");
UserController userController= (UserController) ctx.getBean("userController");
System.out.println(userController);
userController.execute();
}
}
運行結果,發現報錯了:
空指針,UserController類肯定有問題,打開看一下,如下圖所示:
3.3 使用 @Autowired 自動裝配 Bean
@Autowired 註解自動裝配具有兼容類型的單個 Bean屬性
- 構造器, 普通字段(即使是非 public), 一切具有參數的方法都可以應用@Authwired 註解
- 默認情況下, 所有使用 @Authwired 註解的屬性都需要被設置. 當 Spring 找不到匹配的 Bean 裝配屬性時, 會拋出異常, 若某一屬性允許不被設置, 可以設置 @Authwired 註解的 required 屬性爲 false
- 默認情況下, 當 IOC 容器裏存在多個類型兼容的 Bean 時, 通過類型的自動裝配將無法工作. 此時可以在 @Qualifier 註解裏提供 Bean 的名稱. Spring 允許對方法的入參標註 @Qualifiter 已指定注入 Bean 的名稱
- @Authwired 註解也可以應用在數組類型的屬性上, 此時 Spring 將會把所有匹配的 Bean 進行自動裝配.
- @Authwired 註解也可以應用在集合屬性上, 此時 Spring 讀取該集合的類型信息, 然後自動裝配所有與之兼容的 Bean.
- @Authwired 註解用在 java.util.Map 上時, 若該 Map 的鍵值爲 String, 那麼 Spring 將自動裝配與之 Map 值類型兼容的 Bean, 此時 Bean 的名稱作爲鍵值
例子從上面的代碼中修改一下,在屬性上添加一個@Authwired註解
com.hualinux.beans.annotation.controller.UserController.java 修改代碼如下:
package com.hualinux.beans.annotation.controller;
import com.hualinux.beans.annotation.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
@Autowired
private UserService userService;
public void execute(){
System.out.println("UserController execute...");
userService.add();
}
}
com.hualinux.beans.annotation.service.UserService.java 代碼修改如下:
package com.hualinux.beans.annotation.service;
import com.hualinux.beans.annotation.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService{
@Autowired
private UserRepository userRepository;
public void add(){
System.out.println("UserService add...");
userRepository.save();
}
}
com.hualinux.beans.annotation. repository.UserRepository.java不變
com.hualinux.beans.annotation. repository.UserRepositoryImpl.java不變
運行com.hualinux.beans.annotation.Main.java,結果如下:
com.hualinux.beans.annotation.controller.UserController@55b0dcab
UserController execute...
UserService add...
UserRepository Save...
3.4 如果類有衝突怎辦
com.hualinux.beans.annotation. repository.UserRepositoryImpl.java改一下把
@Repository("userRepository")
改爲
@Repository
添加多一個類
src-->com.hualinux.beans.annotation.repository.UserJdbcRepository.java,代碼如下:
package com.hualinux.beans.annotation.repository;
import org.springframework.stereotype.Repository;
@Repository
public class UserJdbcRepository implements UserRepository {
@Override
public void save() {
System.out.println("UserJdbcRepository save...");
}
}
運行com.hualinux.beans.annotation.Main.java,發現報錯:
....
..No qualifying bean of type 'com.hualinux.beans.annotation.repository.UserRepository' available: expected single matching bean but found 2: userJdbcRepository,userRepositoryImpl
...
再看一下UserService類idea也自動提示有問題了
原因是上面2個bean繼承“userRepository”類,在UserSerice類中不能唯一區分到底是調用哪個bean的save方法
解決:
- 像之前那個,指定哪個是默認的
@Repository("userRepository")
- 添加@Qualifier 註解,指定一個類
package com.hualinux.beans.annotation.service; import com.hualinux.beans.annotation.repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Service public class UserService{ @Autowired //注意思第一個字母是小寫 @Qualifier("userRepositoryImpl") private UserRepository userRepository; public void add(){ System.out.println("UserService add..."); userRepository.save(); } }
四、使用 @Resource 或 @Inject 自動裝配 Bean
- Spring 還支持 @Resource 和 @Inject 註解,這兩個註解和 @Autowired 註解的功用類似
- @Resource 註解要求提供一個 Bean 名稱的屬性,若該屬性爲空,則自動採用標註處的變量或方法名作爲 Bean 的名稱
- @Inject 和 @Autowired 註解一樣也是按類型匹配注入的 Bean, 但沒有 reqired 屬性
- 建議使用 @Autowired 註解