1. 程式人生 > >Spring 之 @ComponentScan 探究以及 mock Spring MVC

Spring 之 @ComponentScan 探究以及 mock Spring MVC

.com nbsp glib sep exce 明顯 comm exc director

【 @ComponentScan 探究】

原文():發現一件奇怪的事情,我明明沒有指定掃描那個包,卻能實實在在地 Autowired 那個包中的類的對象而不出現異常。

按理來說,要自動裝配某一個類的對象,首先,需要在那個類上標註 @Component 或者是 @Controller ;其次,需要掃描那個類所在的那個包。我的情況是條件二並不滿足卻獲得了那個對象。我嘗試給那個類去掉 @Component 註釋,結果報錯了,所以並不是條件一有問題,明顯是由於 Spring 自主掃描了我沒有顯式指定的那個包,並為那個帶有組件聲明的類創建了對象。

更加顯式地指定要掃描的那個包:

@ComponentScan(basePackageClasses={HomeController.class
})

結果仍然是不報錯地獲得了我沒有顯式指定掃描的那個包的類的對象,實驗之後發現,成功自動裝配的條件應該是:

  1. 在類的上面有相應的組件聲明,例如 @Component 或者是 @Controller ,或者其它等價註釋。
  2. 類所在的包被直接顯式指定掃描,或者該類被直接顯示指定掃描的那個(些)包中的類所 import

總之不管怎樣,作為組件的聲明都是必須的。

後續(糾正):(。﹏。*) 我錯了,可以成功 Autowired 的原因是我在另外一個 config 文件中掃描了根包,這會順帶掃描所有該包的子包

技術分享

還有,,上面的寫法容易出錯,建議這樣寫,

@ComponentScan(basePackageClasses={Spittle.class
},

效果上是完全等價的,只不過不再需要自己寫字符串了, Spittle 是根包下的類。

【 mock Spring MVC 】

基於使用概率導入大量的依賴包有個缺點就是一旦依賴包出現問題很難鎖定問題到底出在哪裏!!!

這些問題通常是由於依賴包的版本造成的 ( ╯□╰ ) , 因此對於依賴包的導入務必保證不必要不導入,並添加一些適當的註釋。

最好是能夠清楚地了解各個包的用途、來源,這樣也方便查相應的文檔:

【算是一個 pom.xml 模板】

標記為紅色的是進行 mock 測試可能用到的包

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>spittr</groupId> <artifactId>spittr</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.0.0</version> <configuration> <warSourceDirectory>WebContent</warSourceDirectory> </configuration> </plugin> </plugins> </build> <dependencies> <!-- spring-web 包括 web 、 bean 、aop 、 context 、 core 等 spring-webmvc 的子集--> <!-- <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.2.9.RELEASE</version> </dependency> --> <!-- jSTL taglibs--> <dependency> <groupId>org.apache.taglibs</groupId> <artifactId>taglibs-standard-spec</artifactId> <version>1.2.5</version> </dependency> <dependency> <groupId>org.apache.taglibs</groupId> <artifactId>taglibs-standard-impl</artifactId> <version>1.2.5</version> </dependency> <!-- spring-web 包括 web 、 bean 、aop 、 context 、 core、 webmvc 等 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.7.RELEASE</version> </dependency> <!-- spring-test 包括 test 等,含 mock --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.3.2.RELEASE</version> <scope>test</scope> </dependency> <!-- mock 相關的類庫 --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.5</version> <scope>test</scope> </dependency> <!-- hamcrest 相關的類庫 --> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> <scope>test</scope> </dependency> <!-- junit 包括 junit 、 hamcrest --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <!-- commons-lang 僅一個包,包括各種各樣的工具,簡化 hashCode 、 Equal 代碼 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.4</version> </dependency> </dependencies> </project>

【 mock Mvc】

package spittr.web;

import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
// 附上 API 文檔地址: http://docs.spring.io/spring/docs/current/javadoc-api/
public class HomeControllerTest {
    @Test
    public void testHomePage() throws Exception {
        HomeController controller = new HomeController();
        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
        mockMvc.perform(MockMvcRequestBuilders.get("/")).andExpect(MockMvcResultMatchers.view().name("home"));
    }
}

可以修改為靜態導入:

package spittr.web;

import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
// 附上 API 文檔地址: http://docs.spring.io/spring/docs/current/javadoc-api/
public class HomeControllerTest {
    @Test
    public void testHomePage() throws Exception {
        HomeController controller = new HomeController();
        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
        mockMvc.perform(get("/")).andExpect(view().name("home"));
    }
}

【 mock 一個接口的實現類】

package spittr.web;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.servlet.view.InternalResourceView;

import spittr.Spittle;
import spittr.data.SpittleRepository;

public class SpittleControllerTest {
    @Test
    public void shouldShowRecentSpittles() throws Exception {
        List<Spittle> expectedSpittles = createSpittleList(20);
        SpittleRepository mockRepository = mock(SpittleRepository.class);
        when(mockRepository.findSpittles(Long.MAX_VALUE, 20)).thenReturn(expectedSpittles);
        SpittleController controller = new SpittleController(mockRepository);
        MockMvc mockMvc = standaloneSetup(controller).setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp")).build();
        mockMvc.perform(get("/spittles")).andExpect(view().name("spittles")).andExpect(model().attributeExists("spittleList"));
    }
    
    public List<Spittle> createSpittleList(int count) {
        List<Spittle> spittles = new ArrayList<>();
        for (int i = 0; i < count; ++i) {
            spittles.add(new Spittle("Spittle" + i, new Date()));
        }
        return spittles;
    }
}

Spring 之 @ComponentScan 探究以及 mock Spring MVC