聊聊Spring的XML Schema擴展機制的使用方式

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"前言","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在當前Java生態,Spring算的上是最核心的框架,所有的開發組件想要得到大範圍更便捷的使用,都要和Spring進行整合,比如我們熟知的Mybatis、Dubbo等,以及內部封裝的各類組件包括Redis、MQ、配置中心等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有了整合這一步,我們只需引入相應的jar,比如mybatis-spring,然後進行簡單的配置後即可在Spring工程中使用Mybatis的功能,也正是由於這樣的便捷性,導致很多時候我們沒有對其進行深究。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所謂整合,即在Spring的框架下進行擴展,讓框架能無縫的與Spring工程配合使用。Spring設計了良好的擴展的機制,本文將對Spring的擴展方法及原理進行簡單介紹。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"XML Schema擴展","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"打開","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"mybatis-spring","attrs":{}}],"attrs":{}},{"type":"text","text":"、","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"dubbo","attrs":{}}],"attrs":{}},{"type":"text","text":"的源碼會發現在","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"META-INF","attrs":{}}],"attrs":{}},{"type":"text","text":"目錄下有兩個文件(如下圖所示),","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"spring.handlers","attrs":{}}],"attrs":{}},{"type":"text","text":"與","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"spring.schemas","attrs":{}}],"attrs":{}},{"type":"text","text":",這兩個文件就是XML Schema擴展的關鍵入口點。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c7/c79889d74de2b91e1229c65943b5a04e.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"XSD","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"XSD,XML Schema Definition,XML定義。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"XML Schema定義XML文檔的結構,XML Schema語言也稱爲XML定義,即XSD。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"XSD的語法及使用比較簡單,可參考https://www.w3school.com.cn/schema/index.asp進行了解熟悉。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡單的說,XSD用於制定xml文件規範,包括xml中的元素(簡單元素、複雜元素)、屬性、以及屬性類型及約束等。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Spring XML Schema擴展的第一步就是要定義一個xsd文件,比如spring-beans對應xsd文件爲http://www.springframework.org/schema/beans/spring-beans.xsd,如下圖:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a5/a584657f56930260a6140e316beb82f4.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ef/ef0f1ad744f35bdb015fc521d118521d.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了簡單介紹Spring XML Schema擴展實現,下面將一個簡單例子(模擬一個簡單的分佈式id生成器,不會實現具體功能)進行說明,xsd定義如下(文件命名爲DistributedId.xsd,在META-INF目錄下):","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"xml"},"content":[{"type":"text","text":"\n\n\n\n \n \n \n \n \n \n \n \n\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上述xsd文件裏定義了一個複雜元素distributed-id,包含屬性id,bizCode,length,形如:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"xml"},"content":[{"type":"text","text":"\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"注意:xmlns,即爲xml namespace,xml命名空間,後面跟的http鏈接地址可以不存在,因爲xsd會放在當前工程的META-INF下。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"配置spring.handlers和spring.schemas","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如下兩張圖所示,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"spring.schemas","attrs":{}}],"attrs":{}},{"type":"text","text":"文件中用於說明xsd的文件路徑,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"spring.schemas","attrs":{}}],"attrs":{}},{"type":"text","text":"文件用於說明解析此類xsd定義的標籤的處理類,下面會對處理類進行詳細說明。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/33/33fc52ef2c2159bb42946a6c2c91b129.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/6f/6fa35524c8fd12e15123da79fa84e57a.png","alt":null,"title":"","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"NameSpaceHandler與BeanDefinitionParser","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"定義類DistributedIdNamespaceHandler繼承NamespaceHandlerSupport,init方法用於註冊BeanDefinition解析器,也就是解析xml中對應標籤爲Spring Bean。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class DistributedIdNamespaceHandler extends NamespaceHandlerSupport {\n\n @Override\n public void init() {\n registerBeanDefinitionParser(\"distributed-id\", new DistributedIdParser());\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同時要創建BeanDefinitionParser","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class DistributedIdParser implements BeanDefinitionParser {\n\n\n @Override\n public BeanDefinition parse(Element element, ParserContext parserContext) {\n // 解析xml內的標籤\n String bizCode = element.getAttribute(\"bizCode\");\n int length = Integer.valueOf(element.getAttribute(\"length\"));\n String id = element.getAttribute(\"id\");\n \n // 創建DistributedIdFactoryBean bean\n BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();\n builder.getRawBeanDefinition().setBeanClass(DistributedIdFactoryBean.class);\n builder.setScope(BeanDefinition.SCOPE_SINGLETON);\n\n builder.addPropertyValue(\"bizCode\", bizCode);\n builder.addPropertyValue(\"length\", length);\n\n BeanDefinition beanDefinition = builder.getBeanDefinition();\n\n parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);\n\n return beanDefinition;\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中DistributedIdFactoryBean實現FactoryBean接口用於創建DistributedIdComponent Bean,如下","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class DistributedIdFactoryBean implements InitializingBean, FactoryBean {\n\n private String bizCode;\n private int length;\n\n private DistributedIdComponent distributedIdComponent;\n\n @Override\n public DistributedIdComponent getObject() throws Exception {\n return distributedIdComponent;\n }\n\n @Override\n public Class> getObjectType() {\n return DistributedIdComponent.class;\n }\n\n @Override\n public boolean isSingleton() {\n return false;\n }\n\n @Override\n public void afterPropertiesSet() throws Exception {\n distributedIdComponent = new DistributedIdComponent(bizCode, length);\n }\n\n public void setBizCode(String bizCode) {\n this.bizCode = bizCode;\n }\n\n public void setLength(int length) {\n this.length = length;\n }\n}\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目標Bean DistributedIdComponent如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class DistributedIdComponent {\n private String bizCode;\n private int length;\n\n public DistributedIdComponent() {\n\n }\n\n public DistributedIdComponent(String bizCode, int length) {\n this.bizCode = bizCode;\n this.length = length;\n }\n\n public String generateId() {\n System.out.println(\"mock generate id\");\n return String.valueOf(System.currentTimeMillis()).substring(0, length);\n }\n\n public String getBizCode() {\n return bizCode;\n }\n\n public void setBizCode(String bizCode) {\n this.bizCode = bizCode;\n }\n\n public int getLength() {\n return length;\n }\n\n public void setLength(int length) {\n this.length = length;\n }\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"使用","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"spring配置文件,","attrs":{}},{"type":"codeinline","content":[{"type":"text","text":"spring-service.xml","attrs":{}}],"attrs":{}},{"type":"text","text":"中配置distributed-id標籤以及對應的屬性值,如下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"xml"},"content":[{"type":"text","text":"\n\n\n\n \n\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"運行容器驗證:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public class App {\n public static void main(String[] args) {\n ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(\"spring-service.xml\");\n DistributedIdComponent bean = context.getBean(DistributedIdComponent.class);\n\n String id = bean.generateId();\n\n System.out.println(\"id:\" + id);\n }\n}\n","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文主要介紹了Spring XML Schema擴展機制的使用方法,大致步驟爲定義XSD文件、配置spring.schemas、編碼實現NameSpaceHanlder和BeanDefinitionParser實現類、配置spring.handlers。但未說明具體的實現原理,後續會有一篇文章詳細介紹Spring源碼是怎麼實現擴展的,以及介紹爲什麼使用FactoryBean來創建具體的Bean等問題。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章