hualinux spring 3.13:在 classpath 中掃描組件

目錄

一、知識點

 二、例子

2.1  普通例子

2.1.1 目錄結構

2.1.2 代碼

2.2 例1:通過resource-pattern指定掃描的資源

2.3  例2:過濾表達式

2.4  例3:過濾表達式

三、組件裝配

3.1 知識點

3.2 沒使用組件裝配引入的例子

3.3 使用 @Autowired 自動裝配 Bean

3.4 如果類有衝突怎辦

四、使用 @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>



    <!--    &lt;!&ndash; 指定Spring IOC 容器掃描的包&ndash;&gt;
        <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>
-->



    <!--    &lt;!&ndash; 指定Spring IOC 容器掃描的包&ndash;&gt;
        <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方法

解決:

  1. 像之前那個,指定哪個是默認的

@Repository("userRepository")

  1. 添加@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 註解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章