2018年1月6日 星期六

Spring、Spring MVC 設定檔整合 (Spring3.x MVC 十)

雖然可以只用 spring MVC 的設定檔就可以了,但要整合也是 OK 的,但要注意整合的問題

※整合時會出現注入兩次

spring 可以有很多設定檔,可用 web.xml,或者在設定檔使用 import 標籤將其他的設定檔抓進來,但好幾個 spring 設定檔都掃瞄一樣的包,就算設了很多次,不管使用 web.xml 或 import 標籤,都只會注入一次,以上的情形,spring MVC也是一樣

但這兩個設定檔是分開的,兩個都掃瞄一樣的包,會出現兩次


※java bean

package controller;
    
@Controller
@RequestMapping("/ooo/xxx/")
public class XxxAction {
    public XxxAction() {
        System.out.println("XxxAction");
    }
}




package service;
    
@Service
public class XxxServiceImpl {
    public XxxServiceImpl(){
        System.out.println("XxxServiceImpl");
    }
}




※設定檔

※spring 設定檔
<context:component-scan base-package="controller, service" />



※spring MVC 設定檔
<import resource="init.TestDispatcherServlet-servlet2.xml" />
<context:component-scan base-package="controller, service" />




※web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
    
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
    
<servlet>
    <servlet-name>testServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/init.TestDispatcherServlet-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
    
<servlet-mapping>
    <servlet-name>testServlet</servlet-name>
    <url-pattern>*.mvc</url-pattern>
</servlet-mapping>

※啟動伺服器後,會看到 console 會印出兩次 java bean 建構子的內容


※解決方式

可以使用掃瞄不同包來解決,如 spring 掃瞄 controller、spring MVC 掃瞄 service
也可以使用如下的方式:

<context:component-scan base-package="controller, service" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
</context:component-scan>




<context:component-scan base-package="controller, service" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>

※use-default-filters 預設是 true,表示可掃瞄 @Controller、@Service…等的包,將它變成 false 就沒辦法掃了,然後子標籤在和它說可以掃瞄什麼類型的注解

※如果使用 annotation,可以用 @ComponentScan(useDefaultFilters = false, includeFilters = { @Filter(type = FilterType.ANNOTATION, value = App.class) })
.FilterType.ASSIGNABLE_TYPE 將指定的 class 加入 bean id
.FilterType.CUSTOM 寫個類別繼承 TypeFilter 後,即可使用




※spring 抓 spring MVC 注入的變數

spring 就像個全域變數, spring MVC 像個區域變數
區域變數知道有全域變數,但全域變數不知有區域變數
所以 spring MVC 可以抓 spring 的注入屬性;相反則不能

以上個例子來說,假設 controller 是 spring 設定檔設定的;而 service 是 spring MVC 設定的
那 service 使用 @Autowire 抓 XxxAction,伺服器啟動成功;
controller 使用 @Autowire 抓 XxxServiceImpl,伺服器啟動失敗

沒有留言:

張貼留言