SpringMVC 源代碼深度解析 (掃描和注冊的注解Bean)


轉http://blog.csdn.net/congcong68/article/details/40829037

我們在SpringMVC開發項目中,有的用注解和XML配置Bean,這兩種都各有自己的優勢,數據源配置比較經常用XML配置,控制層依賴的service比較經常用注解等(在部署時比較不會改變的),我們經常比較常用的注解有@Component是通用標注,@Controller標注web控制器,@Service標注Servicec層的服務,@Respository標注DAO層的數據訪問。SpringMVC啟動時怎么被自動掃描然后解析並注冊到Bean工廠中去(放到DefaultListableBeanFactory中的Map<String, BeanDefinition> beanDefinitionMap中 以BeanNamekey)?我們今天帶着這些問題來了解分析這實現的過程,我們在分析之前先了解一下這些注解。

   @Controller標注web控制器,@Service標注Service層的服務,@Respository標注DAO層的數據訪問。@Component是通用標注,只是定義為一個類為BeanSpringMVC會把所有添加@Component注解的類作為使用自動掃描注入配置路徑下的備選對象。@Controller@Service\@Respository只是更加的細化,都是被@Component標注,所以我們比較不推薦使用@Component。源代碼如下:

 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
    String value() default "";
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    String value() default "";
}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
    String value() default "";
}

 

都是有標示@Component

  我們在配置文件中,標示配置需要掃描哪些包下,也可以配置對某個包下不掃描,代碼如下:

<context:component-scan base-package="cn.test">
        <context:exclude-filter type="regex" expression="cn.test.*.*.controller"/>
        <context:exclude-filter type="regex" expression="cn.test.*.*.controller2"/>
</context:component-scan>  

 

說明:

   <context:exclude-filter>指定的不掃描包,<context:exclude-filter>指定的掃描包

SpringMVC先讀取配置文件,然后根據context:component-scan中屬性base-package去掃描指定包下的classjar文件,把標示@Controller標注web控制器,@Service標注Servicec層的服務,@Respository標注DAO層的數據訪問等注解的都獲取,並注冊為Bean類放到Bean工廠,我們接下來要分析的這個過程。我們平時項目開發都是這樣的注解,實現MVC模式,代碼如下:

 

//控制層
@Controller
@RequestMapping(value="/test")
public class TestController2 {
    @Autowired
    private TestService testService;
    @RequestMapping(value="/index")
    public String getIndex(Model model){
        
        return "";
    }
}

//服務層
@Service("testService")
public class TestServiceImpl implements  TestService{
}

我們今天的入口點就在這,因為解析注解的到注冊,也是先讀取配置文件並解析,在解析時掃描對應包下的Java類,里面有DefaultBeanDefinitionDocumentReader這個類,doRegisterBeanDefinitions這個方法實現解析配置文件的Bean,這邊已經讀取進來形成Document 形式存儲,然后開始解析Bean,是由BeanDefinitionParserDelegate類實現的,BeanDefinitionParserDelegate完成具體Bean的解析(例如:bean標簽、import標簽等)這個在上一篇SpringMVC  源代碼深度解析 IOC容器(Bean 解析、注冊)里有解析,今天注解屬於擴展的標簽,是由NamespaceHandlerBeanDefinitionParser來解析。源代碼如下:

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
        String namespaceUri = getNamespaceURI(ele);
        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
        if (handler == null) {
            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
            return null;
        }
        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
    }

 NamespaceHandler這邊這邊起到了什么作用,根據不同的Namespace獲取不同的NamespaceHandler,因為我們在Beans標簽配置了命名空間,然后就可以配置對應的標簽,解析標簽時,比較有自己的所實現的NamespaceHandler來解析,如圖所示:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM