Spring v3.0.2 Learning Note 9 - Classpath Scanning

在classpath自動掃描將組件納入容器管理

前面的例子都是使用xml的bean定義來配置組件,即便使用了@Resource或者@Autowired的方式減少了一部分bean的定義,但是在一個稍大的項目中,通常還是會有幾十甚至數百個組件,查找或維護都不太方便。

自從Spring v2.5以後,引入了組件自動掃描的機制,它可以在類路徑下尋找標註了@Component、@Service、@Controller、 @Repository註解的類,並將這些類納入spring容器進行管理。它的作用和在xml文件中使用bean節點配置組件是完全一樣的。

要使用自動掃描,需要用以下配置:
<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-3.0.xsd
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd ">

     <context:component-scan base-package="com.spring.test"/>

</beans>
其中base-package 爲需要掃描的包及其子包。
context:component-scan已經包含了 <context:annotation-config>,所以不需要再添加<context:annotation-config>也可使用@Resource等註解。

@Service             用於標註業務層組件
@Controller         用於標註控制層組件(如struts中的action)
@Repository        用於標註數據訪問組件,即DAO組件
@Component       泛指組件,當組件不好歸類,可使用這個註解。


以目前的spring的版本,上面的組件的處理器的處理都是一樣的,沒有區別。

修改以前用到的例子,來使用classpath掃描的方式工作。

package com.spring.test.dao;

import org.springframework.stereotype.Repository;

@Repository

public class PersonDao {

    public void add() {
        System.out.println("This is add() method in DAO layer.");
    }
}
------------------------------------------------------------------------------------------

package com.spring.test.manager.impl;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.spring.test.dao.PersonDao;
import com.spring.test.manager.IPersonService;

@Service

public class PersonManager implements IPersonService {
    @Resource
    private PersonDao personDao;

    public void setPersonDao(PersonDao personDao) {
        this.personDao = personDao;
    }

    @Override
    public void save() {
        personDao.add();
    }
}
-----------------------------------------------------------------------------------------
測試類1:
package com.spring.test.junit;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.test.manager.IPersonService;

public class PersonServiceTest {

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
    }

    @Test
    public void test() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "spring.xml");
        // 注意classpath掃描的方式下,如何取bean的id
        IPersonService personService = (IPersonService) ctx
                .getBean("personManager");
        personService.save();
    }

}

classpath自動掃描的方式,如何知道bean的id

  • 若@Service中沒有給定bean的id/name,默認狀況下是類名,但是第一個字母變爲小寫,如上例中的 (IPersonService) ctx.getBean("personManager");會取到類 com.spring.test.manager.impl.PersonManager。如果有多個同名的PersonManager,但是處在不同的 package下,如何辦呢?則可在@Service中指定bean的name
  • @Service("service name"),如果採用了指定名稱的方式,則按照名稱來匹配組件。比如:@Service("personService"),如果運行測試類1會出錯, 因爲名稱不匹配了,需要改爲 (IPersonService) ctx.getBean("personService");纔可以工作。

classpath自動掃描的方式,如何指定作用域


如果不指定,默認狀態爲singleton,如果需要修改,採用以下方法:
@Scope("prototype")
@Service("personManager")
public class PersonManager implements IPersonService {
// 省略
}

指定初始化方法和銷燬方法

@PostConstruct  等同於bean定義的init-method="初始化方法名"
@PreDestroy         等同於bean定義的destroy-method="銷燬方法名"

 package com.spring.test.manager.impl;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.spring.test.dao.PersonDao;
import com.spring.test.manager.IPersonService;

@Service("personManager")
public class PersonManager implements IPersonService {
    @Resource
    private PersonDao personDao;

    public void setPersonDao(PersonDao personDao) {
        this.personDao = personDao;
    }

    @PostConstruct
    public void init() {
        System.out.println("This is init() method.");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("This is destroy() method.");
    }

    @Override
    public void save() {
        personDao.add();
    }
}
---------------------------------------------------------------------------
package com.spring.test.junit;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PersonServiceTest {

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
    }

    @Test
    public void test() {
        AbstractApplicationContext ctx = new ClassPathXmlApplicationContext(
                "spring.xml");

        ctx.close();
    }

}
運行此測試類,發現控制檯輸出了初始化方法和銷燬方法中的內容。

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