[Spring] 基於 Java 的配置

在對 Spring 進行顯示配置的時候,有兩種可選方案:Java 和 XML。Java 配置是更好的選擇,因爲它更強大,類型安全且對重構友好。因爲它就是 Java 代碼,就像程序中的其他 Java 代碼一樣。

同時,JavaConfig與其他的Java代碼又有所區別,儘管它與其他的組件一樣都使用相同的語言進行表述,但JavaConfig是 配置代碼。這意味着它不應該包含任何業務邏輯,JavaConfig也不應該侵入到業務邏輯代碼 之中。

接下來,讓我們看一下如何通過JavaConfig顯式配置Spring

基本概念:@Configuration 和 @Bean

@Configuration 被用於類上,指明這是一個配置類,該類應該包含在Spring應用上下文中如何創建bean的細節。@Bean 用於方法上,這個方法返回一個被裝配的對象,方法體中包含了最終產生bean實例的邏輯。

看一個例子:

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

上面的 AppConfig 類將和下面的 XML 配置有一樣的效果

<beans>
    <bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

默認情況下,bean 的 ID 與帶有 @Bean 註解的方法名是一樣的。在本例中,bean的名字將會是 myService。如果你想爲其設置成一個不同的名字的話,那麼可以重命名該方法,也可以通過 name 屬性指定一個不同的名字:

@Bean(name = "hisService")
public MyService myService() {
    return new MyServiceImpl();
}

開啓自動裝配也是很簡單的

@Configuration
@ComponentScan(basePackages = "com.acme")
public class AppConfig  {
    ...
}

使用 @ComponentScan 註解即可,它等同於如下 XML 配置

<beans>
    <context:component-scan base-package="com.acme"/>
</beans>

藉助 JavaConfig 實現注入

我們前面所聲明的 myService bean 是非常簡單的,它自身沒有其他的依賴。但現在,我 們需要聲明 MyApp bean,它依賴於 myService 。在 JavaConfig 中,要如何將它們裝配在一起呢?

在 JavaConfig 中裝配 bean 的最簡單方式就是引用創建 bean 的方法。例如,下面就是一種聲明 myApp 的可行方案:

@Bean
public MyApp myApp() {
    return new MyApp(myService());
}

可以看到,通過調用方法來引用 bean 的方式有點令人困惑。其實還有一種理解起來更爲簡單的方式:

@Bean
public MyApp myApp(MyService myService) {
    return new MyApp(myService);
}

在這裏,myApp() 方法請求一個 MyService 作爲參數。當 Spring 調用myApp() 創建 MyApp bean 的時候,它會自動裝配一個 MyService 到配置方法之中。然後,方法體就可以按照合適的方式來使用它。

通過這種方式引用其他的 bean 通常是最佳的選擇,因爲它不會要求將MyService 聲明到 同一個配置類之中。在這裏甚至沒有要求MyService 必須要在 JavaConfig 中聲明,實際上 它可以通過組件掃描功能自動發現或者通過 XML 來進行配置。

使用 JavaConfig 配置 Java Web

配置DispatcherServlet

DispatcherServlet 是 Spring MVC的核心。在這裏請求會第一次接觸到框架,它要負責將請求路由到其他的組件之中。

按照傳統的方式,像 DispatcherServlet 這樣的 Servlet 會配置在 web.xml 文件中,這個文件會放到應用的 WAR 包裏面。當然,這是配置 DispatcherServlet 的方法之一。但是,藉助於 Servlet 3 規範和 Spring 3.1的功能增強,這種方式已經不是唯一的方案了。

我們會使用 Java 將 DispatcherServlet 配置在 Servlet 容器中,而不會再使用 web.xml 文 件。如下的程序清單展示了所需的Java類。

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] {AppConfig.class};
    }

    //指定配置類
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] {WebConfig.class};
    }

    //將 DispatcherServlet 映射到 "/"
    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }
}

要理解上面的程序清單是如何工作的,我們可能只需要知道擴 展AbstractAnnotationConfigDispatcherServletInitializer的任意類都會自 動地配置DispatcherServlet和Spring應用上下文,Spring的應用上下文會位於應用程序 的Servlet上下文之中。

儘管它的名字很長,但是 AbstractAnnotationConfigDispatcherServletInitializer 使用起來很簡 便。在程序清單中,WebAppInitializer 重寫了三個方法。

第一個方法是 getServletMappings(),它會將一個或多個路徑映射 到DispatcherServlet上。在本例中,它映射的是“/”,這表示它會是應用的默認 Servlet。它會處理進入應用的所有請求。

爲了理解其他的兩個方法,我們首先要理解DispatcherServlet和一個Servlet監聽器(也 就是ContextLoaderListener)的關係。

當 DispatcherServlet 啓動的時候,它會創建 Spring 應用上下文,並加載配置文件或配置 類中所聲明的bean。在程序清單的 getServletConfigClasses() 方法中,我們要求 DispatcherServlet 加載應用上下文時,使用定義在 WebConfig 配置類(使用Java配置)中的 bean。

但是在Spring Web應用中,通常還會有另外一個應用上下文。另外的這個應用上下文是 由ContextLoaderListener創建的。

getServletConfigClasses() 方法返回的帶有 @Configuration 註解的類將會用來定義 DispatcherServlet 應用上下文中的 bean。getRootConfigClasses() 方法返回的帶有 @Configuration 註解的類將會用來配置 ContextLoaderListener 創建的應用上下文中的bean。

在本例中,根配置定義在 AppConfig 中,DispatcherServlet 的配置聲明在 WebConfig 中。

啓用Spring MVC

我們有多種方式來配置 DispatcherServlet,與之類似,啓用Spring MVC組件的方法也不僅一種。以前,Spring 是使用 XML 進行配置的,你可以使用 <mvc:annotationdriven> 啓用註解驅動的Spring MVC。
我們所能創建的最簡單的 Java Spring MVC 配置就是一個帶有 @EnableWebMvc 註解的類

@Configuration
@EnableWebMvc
public class WebConfig {
}

這可以運行起來,它的確能夠啓用Spring MVC,但還有不少問題要解決:

  • 沒有配置視圖解析器。如果這樣的話,Spring 默認會使用 BeanNameViewResolver,這個視圖解析器會查找 ID 與視圖名稱匹配的 bean,並且查找的 bean 要實現 View 接口,它以這樣的方式來解析視圖。
  • 沒有啓用組件掃描。這樣的結果就是,Spring只能找到顯式聲明在配置類中的控制器。
  • 這樣配置的話,DispatcherServlet 會映射爲應用的默認 Servlet,所以它會處理所有的請求,包括對靜態資源的請求,如圖片和樣式表(在大多數情況下,這可能並不是你想要的效果)。

因此,我們需要在 WebConfig 這個最小的 Spring MVC 配置上再加一些內容,從而讓它變得真正有用。如下程序清單中的 WebConfig 解決了上面所述的問題。

@Configuration
@EnableWebMvc //啓用 Spring MVC
@ComponentScan("com.web")  //啓用組件掃描
public class WebConfig extends WebMvcConfigurerAdapter {
    //配置視圖解析器
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setExposeContextBeansAsAttributes(true);
        return resolver;
    }

    //配置靜態資源處理
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}
發佈了50 篇原創文章 · 獲贊 26 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章