激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - spring拓展之如何定義自己的namespace

spring拓展之如何定義自己的namespace

2022-01-19 01:00試水流連 Java教程

這篇文章主要介紹了spring拓展之如何定義自己的namespace方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

spring拓展 定義自己的namespace

1.查看源碼認識spring是怎么加載xml配置的

1.1 spring是怎么創建對象的?

查看spring beanFactory的繼承關系

spring拓展之如何定義自己的namespace

通過查看源碼可以得知,BeanFactory 中的對象創建是實際是根據RootBeanDefinition創建的, 在AbstractAutowireCapableBeanFactory中有具體的實現,包括創建實例,

利用Spring拓展

java的內省實現BeanWrapperImpl,創建對象的包裝類,使用反射給對象填充屬性,并實現依賴注入DI 。具體可以自行參閱源碼。

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
  .....
  protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
          throws BeanCreationException;
}

spring拓展之如何定義自己的namespace

而RootBeanDefination定義的是什么呢?查看AbstractBeanDefination類。

spring拓展之如何定義自己的namespace

可以看到這里就是Spring對對象屬性的封裝,包括類名,屬性,加載策略等等,其實也就是我們在xml里 配置的對象。

1.2 spring是怎么將xml里配置的對象讀到BeanFactory中的?

在查看spring容器的源碼時,得知spring 是使用 org.springframework.beans.factory.xml.XmlBeanDefinitionReader 進行xml解析的

  public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
      .....
      protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                  throws BeanDefinitionStoreException {
              try {
                  //讀取xml
                  Document doc = doLoadDocument(inputSource, resource);
                  //解析并注冊xml中定義的BeanDefination
                  return registerBeanDefinitions(doc, resource);
              }
              catch (BeanDefinitionStoreException ex) {
                  xxx
              }
          }
      .....
  }

接下來查看對dom 解析部分的源碼

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
@Override
  public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
      this.readerContext = readerContext;
      logger.debug("Loading bean definitions");
      Element root = doc.getDocumentElement();
      doRegisterBeanDefinitions(root);
  }
  protected void doRegisterBeanDefinitions(Element root) {
      //為了實現進行遞歸解析
      BeanDefinitionParserDelegate parent = this.delegate;
      this.delegate = createDelegate(getReaderContext(), root, parent);
      if (this.delegate.isDefaultNamespace(root)) {
          //對profile的支持
          String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
          if (StringUtils.hasText(profileSpec)) {
              String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                      profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
              if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                  return;
              }
          }
      }
      preProcessXml(root);
      //開始解析dom樹
      parseBeanDefinitions(root, this.delegate);
      postProcessXml(root);
      this.delegate = parent;
  }
  protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
      if (delegate.isDefaultNamespace(root)) {
          NodeList nl = root.getChildNodes();
          for (int i = 0; i < nl.getLength(); i++) {
              Node node = nl.item(i);
              if (node instanceof Element) {
                  Element ele = (Element) node;
                  if (delegate.isDefaultNamespace(ele)) {
                      //spring的基礎命名元素解析(import、bean、beans、alias)其中在
                      //beans嵌套時會進行遞歸解析
                      parseDefaultElement(ele, delegate);
                  }
                  else {
                      //拓展元素解析
                      delegate.parseCustomElement(ele);
                  }
              }
          }
      }
      else {
          delegate.parseCustomElement(root);
      }
  }
}

查看spring是怎么實現拓展元素的解析的

public class BeanDefinitionParserDelegate {
  public BeanDefinition parseCustomElement(Element ele) {
      return parseCustomElement(ele, null);
  }
  public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
      //獲取當前節點命名空間URI
      String namespaceUri = getNamespaceURI(ele);
      //根據命名空間解析到自定義的NamespaceHandler
      NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
      if (handler == null) {
          error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
          return null;
      }
      //使用拓展的Handler對當前節點進行解析
      return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
  }
}

其中NamespaceHandlerResolver 會去查找當前項目中classpath 下的META-INF目錄下所有文件名為 spring.handlers配置文件,定位到自定義namespace的解析器實現類。

其中在namespace 的處理器中可以通過進行BeanDefination的注冊,注冊過的BeanDefination會用來給BeanFactory創建對象使用,將解析好的BeanDefination注冊到parserContext.getRegistry()中即可。其實DefaultListableBeanFactory 就是一個BeanDefinitionRegistry。

@Override
  public BeanDefinition parse(Element element, ParserContext parserContext) {
      ....
      parserContext.getRegistry().registerBeanDefinition(beanName, mbd);
  }

2.定義自己的namespace

2.1 定義schema約束xsd文件

將自定義的xsd文件放到項目的 META-INF 目錄下。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://xxx.xxx.com/schema/myns"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:tool="http://www.springframework.org/schema/tool"
  targetNamespace="http://xxx.xxx.com/schema/myns">
  <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
  <xsd:import namespace="http://www.springframework.org/schema/beans"/>
  <xsd:import namespace="http://www.springframework.org/schema/tool"/>
  <xsd:annotation>
      <xsd:documentation><![CDATA[ Namespace support for the myns test. ]]></xsd:documentation>
  </xsd:annotation>
  <xsd:complexType name="mybeanType">
      <xsd:attribute name="id" type="xsd:ID">
          <xsd:annotation>
              <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
          </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="name" type="xsd:string" use="required">
          <xsd:annotation>
              <xsd:documentation><![CDATA[ The mybean name. ]]></xsd:documentation>
          </xsd:annotation>
      </xsd:attribute>
      <xsd:attribute name="class" type="xsd:string" use="required">
          <xsd:annotation>
              <xsd:documentation><![CDATA[ The version. ]]></xsd:documentation>
          </xsd:annotation>
      </xsd:attribute>
  </xsd:complexType>
  <xsd:element name="mybean" type="mybeanType">
      <xsd:annotation> 
          <xsd:documentation><![CDATA[ The mybean config ]]></xsd:documentation> 
      </xsd:annotation>
  </xsd:element>
</xsd:schema>

更多xsd寫法可以參閱xml的相關資料。

2.2創建自定義namespace的NamespaceHandler

使用NamespaceHandlerSupport來實現我們定義的NamespaceHandler。在init時去提供具體的標簽的 解析器。

BeanDefinitionParser

public class MybeanParser implements BeanDefinitionParser {
  @Override
  public BeanDefinition parse(Element element, ParserContext parserContext) {
      RootBeanDefinition mbd =  new RootBeanDefinition();
      mbd.setBeanClassName(element.getAttribute("class"));
      String beanName = element.getAttribute("id");
      MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
      mutablePropertyValues.add("name", element.getAttribute("name"));
      mbd.setPropertyValues(mutablePropertyValues);
      parserContext.getRegistry().registerBeanDefinition(beanName, mbd);
      return mbd;
  }
}

實現自定義的NamespaceHandler

public class MynsNameSpaceHandler extends NamespaceHandlerSupport{
  @Override
  public void init() {
      registerBeanDefinitionParser("mybean", new MybeanParser());
  }
}

這里的mybean是myns namespace下的元素標簽的具體的解析實現

如:

<myns:mybean></myns:mybean>

2.3配置自定義的NamespaceHandler映射

在META-INF下創建文件 spring.handlers

http\://xxx.xxx.com/schema/myns=com.xxx.MynsNameSpaceHandler

2.4使用自定義的Namespace

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:myns="http://xxx.xxx.com/schema/myns"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://xxx.xxx.com/schema/myns http://xxx.xxx.com/schema/myns.xsd
      ">
      <myns:mybean class="com.xxx.People" id="mybean123" name="testMybean"></myns:mybean>
</beans>

2.5測試

public class MybeanNamespaceTestCase {
  @SuppressWarnings("resource")
  @Test
  public void testGetBean(){
      ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"myapp.xml"},false);
      ac.setValidating(false);
      ac.refresh();
      People bean = ac.getBean("mybean123",People.class);
      System.out.println(bean.getName());
  }
}

這里設置ac.setValidating(false); 是因為如果開啟xml約束檢查,需要配置schema的位置,

也是在META-INF 下新建spring.schemas

并加入:

http\://xxx.xxx.com/schema/myns.xsd=META-INF/myns.xsd

這樣spring 在xml解析時會調用org.springframework.beans.factory.xml.PluggableSchemaResolver

進行獲取schema文件進行約束檢查,

這樣配置完畢后就可以ac.setValidating(true);啦,如果文件內容不符合規范,會啟動時拋出異常。

此外,如果想要在使用過程開發工具能夠像使用spring 自身的一些配置時有提升功能,可以將schema文件

上傳到文件服務器上,能夠通過http 訪問到xsi:schemaLocation的地方,或者配置開發工具中的xml 約束映射,將地址映射到本 地磁盤中,這樣就能

spring拓展之如何定義自己的namespace

spring拓展之如何定義自己的namespace

 

spring-namespace實現自定義標簽類

介紹如何通過spring namespace的方式進行bean的配置

最終要達到的目的如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:user="http://www.wuxueyou.cn/schema/user"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.wuxueyou.cn/schema/user http://www.wuxueyou.cn/schema/user.xsd">

  <user:self-user id="user2" userId="12" name="aaa"/>
  <bean id="user1" class="com.xueyou.User">
      <property name="userId" value="33"/>
      <property name="name" value="xiaoming"/>
  </bean>
</beans>

好,下面上貨。

1.配置java bean

2.編寫xsd文件

3.編寫BeanDefinationParse標簽解析類

4.編寫調用標簽解析類的NamespaceHandler類

5.編寫spring.handlers和spring.schemas供spring讀取

6.在spring中使用

spring拓展之如何定義自己的namespace

 

目錄結構

 

1.配置java Bean

package com.xueyou; 
public class User {
  private int userId;
  private String name; 
  public User() {
  }

  public int getUserId() {
      return userId;
  }

  public void setUserId(int userId) {
      this.userId = userId;
  }

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }

  @Override
  public String toString() {
      return "User{" +
              "userId='" + userId + '\'' +
              ", name='" + name + '\'' +
              '}';
  }
}

2.編寫xsd文件

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.wuxueyou.cn/schema/user"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema"
          xmlns:beans="http://www.springframework.org/schema/beans"
          targetNamespace="http://www.wuxueyou.cn/schema/user"
          elementFormDefault="qualified">
  <xsd:import namespace="http://www.springframework.org/schema/beans"
              schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd"/>
  <xsd:element name="self-user">
      <xsd:complexType>
          <!--這里的最外層的id是spring用的,用來定義bean的名稱用的,不要和類中的id混淆了-->
          <xsd:attribute name="id" type="xsd:string" use="required"/>
          <xsd:attribute name="userId" type="xsd:int" use="required"/>
          <xsd:attribute name="name" type="xsd:string" use="required"/>
      </xsd:complexType>
  </xsd:element>
</xsd:schema>

3.編寫BeanDefinationParse標簽解析類

package com.xueyou.parser; 
import com.xueyou.User;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.w3c.dom.Element;

public class UserDefinationParser extends AbstractSimpleBeanDefinitionParser {
  @Override
  protected Class<?> getBeanClass(Element element) {
      return User.class;
  }

  @Override
  protected void doParse(Element element, BeanDefinitionBuilder builder) {
      int userId = Integer.valueOf(element.getAttribute("userId"), 0);
      String name = element.getAttribute("name");
      builder.addPropertyValue("userId", userId);
      builder.addPropertyValue("name", name);
  }
}

4.編寫調用標簽解析類的NamespaceHandler類

package com.xueyou.handler; 
import com.xueyou.parser.UserDefinationParser;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport; 
public class UserNamespaceHandler extends NamespaceHandlerSupport {
  public void init() {
      registerBeanDefinitionParser("self-user", new UserDefinationParser());
  }
}

5.編寫spring.handlers和spring.schemas以供spring讀取

spring.handlers

http\://www.wuxueyou.cn/schema/user=com.xueyou.handler.UserNamespaceHandler

spring.schemas

http\://www.wuxueyou.cn/schema/user.xsd=namespace/user.xsd

6.打包

首先把剛才的打成一個jar包,需要注意在maven的plugin中添加如下內容, 這個shade插件能夠合并指定的內容,比如spring.schema等等

<build>
  <plugins>
      <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-shade-plugin</artifactId>
          <version>3.2.0</version>
          <executions>
              <execution>
                  <phase>package</phase>
                  <goals>
                      <goal>shade</goal>
                  </goals>
                  <configuration>
                      <transformers>
                          <transformer
                                  implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                              <resource>META-INF/spring.handlers</resource>
                          </transformer>
                          <transformer
                                  implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                              <resource>META-INF/spring.schemas</resource>
                          </transformer>
                          <transformer
                                  implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                              <mainClass></mainClass>
                          </transformer>
                      </transformers>
                  </configuration>
              </execution>
          </executions>
      </plugin>
  </plugins>
</build>

7.在其他項目中使用

在一個web項目中使用這個類

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:user="http://www.wuxueyou.cn/schema/user"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.wuxueyou.cn/schema/user http://www.wuxueyou.cn/schema/user.xsd">

  <user:self-user id="user2" userId="12" name="aaa"/>
  <bean id="user1" class="com.xueyou.User">
      <property name="userId" value="33"/>
      <property name="name" value="xiaoming"/>
  </bean>
</beans>

在controller中進行測試

package com.example.demo.controller; 
import com.xueyou.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; 
import javax.annotation.Resource;

@RestController
@RequestMapping("/namespacetest")
public class NamespaceController {

  @Resource(name = "user2")
  private User user;

  @RequestMapping("/user")
  public User namespacetest() {
      return user;
  }
}

運行結果:

 

 
spring拓展之如何定義自己的namespace

 

運行結果

最終,我們可以使用spring-namespace對bean進行配置了。這樣比<bean>標簽要好的多。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。

原文鏈接:https://blog.csdn.net/m0_38043362/article/details/78329188

延伸 · 閱讀

精彩推薦
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
主站蜘蛛池模板: 亚洲精品一区二区三区免 | 午夜视频中文字幕 | wwwxxx国产 | 免费大香伊蕉在人线国产 | 国产精品一区视频 | 天天舔夜夜操 | 成人啪啪18免费网站 | 毛片视频免费观看 | 中国av免费观看 | 毛片免费观看视频 | 羞羞视频入口 | 亚洲国产精品高潮呻吟久久 | 91网站链接| 成人毛片免费在线 | 毛片视频免费观看 | xfplay噜噜av | 午夜精品在线视频 | 7777欧美 | 蜜桃传媒视频麻豆第一区免费观看 | 超碰97国产在线 | 中文字幕在线播放第一页 | 国产日韩在线 | 日韩精品羞羞答答 | 免费小毛片 | 国产xxxx岁13xxxxhd| av在线官网 | 欧美国产日韩在线观看成人 | 黄色大片在线观看 | 99视频有精品视频高清 | 欧美有码在线观看 | 精品国产观看 | 一级黄色电影网站 | 欧美不卡 | 亚洲自拍第二页 | 色播视频在线播放 | 久久精品日韩一区 | 操碰在线视频 | 精品国产一区二区三区在线 | 加勒比婷婷色综合久久 | 亚洲国产精品一区二区三区 | 日韩中文字幕一区二区三区 |