我的编程空间,编程开发者的网络收藏夹
学习永远不晚

使用Spring自定义命名空间

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

使用Spring自定义命名空间

Spring在解析xml文件中的标签的时候会区分当前的标签是四种基本标签(import、alias、bean和beans)还是自定义标签,如果是自定义标签,则会按照自定义标签的逻辑解析当前的标签。另外,即使是bean标签,其也可以使用自定义的属性或者使用自定义的子标签。本文将对自定义标签和自定义属性的使用方式进行讲解,并且会从源码的角度对自定义标签和自定义属性的实现方式进行讲解。

Spring框架从2.0版本开始,提供了基于Schema风格的Spring XML格式用来定义bean的扩展机制。引入Schema-based XML是为了对Traditional的XML配置形式进行简化。通过Schema的定义,把一些原本需要通过几个bean的定义或者复杂的bean的组合定义的配置形式,用另外一种简单而可读的配置形式呈现出来。

Schema-based XML由三部分构成,我们由一幅图说明:

这里写图片描述

  • namespace —— 拥有很明确的逻辑分类
  • element —— 拥有很明确的过程语义
  • attributes —— 拥有很简明的配置选项

例如,<mvc:annotation-driven />这段配置想要表达的意思,就是在mvc的空间内实现Annotation驱动的配置方式。其中,mvc表示配置的有效范围,annotation-driven则表达了一个动态的过程,实际的逻辑含义是:整个SpringMVC的实现是基于Annotation模式,请为我注册相关的行为模式。

下面将阐述一下怎么写自定义XML的bean definition解析和集成这个解析到Spring IOC容器中。在后面的内容中我们将会提到一个重要的概念那就是bean definition.其实Spring中有一个重要的概念那就是bean.而BeanDefinition这个对象就是对应的标签解析后的对象。

利用下面几个简答的步骤可以创建新的xml配置扩展:

  • Authoring一个XML schema用来描述你的自定义element(s)
  • Coding一个自定义的NamespaceHandler实现(这是一个很简答的步骤,don't worry)
  • Coding一个或者多个BeanDefinitionParse实现(这是最主要的)
  • Registeringr把注册上面的到Spring(这也是一个简答的步骤)

下面将会依次阐述上面的步骤。例如:我们需要创建一个XML扩展(自定义xml element)允许我们可以用一种简单的方式来配置SimpleDateFormat对象(在java.text包中)。最后我们可以定义一个SimpleDateFormat类型的bean definition如下:


<myns:dateformat id="dateFormat"
    pattern="yyyy-MM-dd HH:mm"
    lenient="true"/>

1、Authoring the schema

创建一个Spring IOC容器的XML配置扩展,我们需要编写一个XML Schema用来描述这个扩展。下面的schema我们可以用来配置SimpleDateFormat对象


<!-- myns.xsd (inside package org/springframework/samples/xml) --> 
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.mycompany.com/schema/myns"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:beans="http://www.springframework.org/schema/beans"
        targetNamespace="http://www.mycompany.com/schema/myns"
        elementFormDefault="qualified"
        attributeFormDefault="unqualified">
 
    <xsd:import namespace="http://www.springframework.org/schema/beans"/> 
    <xsd:element name="dateformat">
        <xsd:complexType>
            <xsd:complexContent>
                <xsd:extension base="beans:identifiedType">
                    <xsd:attribute name="lenient" type="xsd:boolean"/>
                    <xsd:attribute name="pattern" type="xsd:string" use="required"/>
                </xsd:extension>
            </xsd:complexContent>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>

上面的schema将会用来配置SimpleDateFormat对象。直接在一个xml应用context文件使用<myns:dateformat /> element.


<myns:dateformat id="dateFormat"
    pattern="yyyy-MM-dd HH:mm"
    lenient="true"/>

注意:上面的XML片段本质上和下面的XML片段意义一样。


<bean id="dateFormat" class="java.text.SimpleDateFormat">
    <constructor-arg value="yyyy-HH-dd HH:mm"/>
    <property name="lenient" value="true"/>
</bean>

2、Coding a NamespaceHandler

针对于上面的的schema,我们需要一个NamespaceHandler用来解析Spring遇到的所有这个特定的namespace配置文件中的所有elements.这个NamespaceHandler将会关心解析myns:dateformat元素。

这个NamespaceHandler接口相对简单,它包括三个重要的方法。

  • init().会在spring使用handler之前实例化NamespaceHandler
  • BeanDefinition parse(Element, ParseContext) - 当Spring遇到上面定义的top-level元素(也就是myms)将会被调用,这个方法能够注册bean definitions并且可以返回一个bean definition.
  • BeanDefinitionHolder decorate(Node, BeanDefinitionHolder, ParserContext),当spring遇到一个attribute或者嵌入到namespace中的元素中将会被调用。

在很多情况下在spring xml配置文件中每个top-level的xml元素代表一个single类型的bean definition(在我们的例子中,是一个single的<myns:dateformat>元素代表一个single的SimpleDateFormat bean definition).Spring提供了很多便利的类用来支持这种场景。在这个例子中,我们将使用NamespaceHandlerSupport。


package org.springframework.samples.xml; 
import org.springframework.beans.factory.xml.NamespaceHandlerSupport; 
public class MyNamespaceHandler extends NamespaceHandlerSupport { 
    public void init() {
        registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
    } 
}

下面讲一下为什么要继承NamespaceHandlerSupport这个抽象类

先看一下Spring自定义命名空间加载过程:

XmlBeanDefinitionReader入口

DefaultDocumentLoader加载并解析一个XML文件成Document实例,从BeanDefinitionReader中获取EntityResolver和ErrorHandler。

在XmlBeanDefinitionReader中创建BeanDefinitionDocumentReader,在这个BeanDefinitionDocumentReader中遍历Document中的每个Element。

对每个Element,如果是默认的URI(即beans命名空间内的定义),调用parseDefaultElement()方法,否则调用BeanDefinitionParserDelegate中的parseCustomElement()方法。

在parseCustomElement()方法中,它找到当前Element的namespaceURI,然后从NamespaceHandlerResolver中获取自定义的NamespaceHandler,使用该NamespaceHandler来解析这个Element,由于我们已经在init()方法中注册了不同的element name对应的BeanDefinitionParser,因而可以使用这个自定义的BeanDefinitionParser来解析自定义的Element。

其中默认的NamespaceHandlerResolver(DefaultNamespaceHandlerResolver)会找到当前classpath下的所有META-INF/spring.handlers文件,加载进来,读取里面的内容成namespaceURI到NamespaceHandler的map,并初始化所有的NamespaceHandler。

看一下BeanDefinitionParserDelegate中的parseCustomElement()方法:


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

其中parse方法为抽象类NamespaceHandlerSupport中的方法:


public BeanDefinition parse(Element element, ParserContext parserContext) {
        return this.findParserForElement(element, parserContext).parse(element, parserContext);
}
 
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
        String localName = parserContext.getDelegate().getLocalName(element);
        BeanDefinitionParser parser = (BeanDefinitionParser)this.parsers.get(localName);
        if (parser == null) {
            parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
        } 
        return parser;
}

而其中的

BeanDefinitionParser parser = (BeanDefinitionParser)this.parsers.get(localName);这句中的parsers是一个HashMap 在继承NamespaceHandlerSupport这个抽象类中的重写了init()方法:


public void init() {
        registerBeanDefinitionParser("dateformat", new SimpleDateFormatBeanDefinitionParser());
    }

NamespaceHandlerSupport这个类的registerBeanDefinitionParser方法:


private final Map<String, BeanDefinitionParser> parsers = new HashMap(); 
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
        this.parsers.put(elementName, parser);
    }

return this.findParserForElement(element, parserContext).parse(element, parserContext);中的parse方法为抽象类AbstractBeanDefinitionParser中的方法:


public final BeanDefinition parse(Element element, ParserContext parserContext) {
        AbstractBeanDefinition definition = this.parseInternal(element, parserContext);
        if (definition != null && !parserContext.isNested()) {
            try {
                String id = this.resolveId(element, definition, parserContext);
                if (!StringUtils.hasText(id)) {
                    parserContext.getReaderContext().error("Id is required for element '" + parserContext.getDelegate().getLocalName(element) + "' when used as a top-level tag", element);
                }
 
                String[] aliases = null;
                if (this.shouldParseNameAsAliases()) {
                    String name = element.getAttribute("name");
                    if (StringUtils.hasLength(name)) {
                        aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
                    }
                }
 
                BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
                this.registerBeanDefinition(holder, parserContext.getRegistry());
                if (this.shouldFireEvents()) {
                    BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
                    this.postProcessComponentDefinition(componentDefinition);
                    parserContext.registerComponent(componentDefinition);
                }
            } catch (BeanDefinitionStoreException var8) {
                parserContext.getReaderContext().error(var8.getMessage(), element);
                return null;
            }
        } 
        return definition;
    }

this.registerBeanDefinition(holder, parserContext.getRegistry());最终会调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean,BeanDefinitionReaderUtils的注册的源码如下:


//将解析的BeanDefinitionHold注册到容器中 
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)  
    throws BeanDefinitionStoreException {  
        //获取解析的BeanDefinition的名称
         String beanName = definitionHolder.getBeanName();  
        //向IoC容器注册BeanDefinition 
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());  
        //如果解析的BeanDefinition有别名,向容器为其注册别名  
         String[] aliases = definitionHolder.getAliases();  
        if (aliases != null) {  
            for (String aliase : aliases) {  
                registry.registerAlias(beanName, aliase);  
            }  
        }  
}

当调用BeanDefinitionReaderUtils向IoC容器注册解析的BeanDefinition时,真正完成注册功能的是DefaultListableBeanFactory。

DefaultListableBeanFactory向IoC容器注册解析后的BeanDefinition:

DefaultListableBeanFactory中使用一个HashMap的集合对象存放IoC容器中注册解析的BeanDefinition,向IoC容器注册的主要源码如下:


//存储注册的俄BeanDefinition  
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();  
   //向IoC容器注册解析的BeanDefiniton  
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  
         throws BeanDefinitionStoreException {  
     Assert.hasText(beanName, "Bean name must not be empty");  
     Assert.notNull(beanDefinition, "BeanDefinition must not be null");  
     //校验解析的BeanDefiniton  
      if (beanDefinition instanceof AbstractBeanDefinition) {  
           try {  
               ((AbstractBeanDefinition) beanDefinition).validate();  
          }  
          catch (BeanDefinitionValidationException ex) {  
              throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
                      "Validation of bean definition failed", ex);  
          }  
      }  
      //注册的过程中需要线程同步,以保证数据的一致性  
      synchronized (this.beanDefinitionMap) {  
          Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
          //检查是否有同名的BeanDefinition已经在IoC容器中注册,如果已经注册,  
          //并且不允许覆盖已注册的Bean,则抛出注册失败异常  
          if (oldBeanDefinition != null) {  
              if (!this.allowBeanDefinitionOverriding) {  
                  throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
                           "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +  
                          "': There is already [" + oldBeanDefinition + "] bound.");  
              }  
              else {//如果允许覆盖,则同名的Bean,后注册的覆盖先注册的  
                  if (this.logger.isInfoEnabled()) {  
                      this.logger.info("Overriding bean definition for bean '" + beanName +  
                              "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");  
                  }  
              }  
          }  
          //IoC容器中没有已经注册同名的Bean,按正常注册流程注册  
          else {  
              this.beanDefinitionNames.add(beanName);  
              this.frozenBeanDefinitionNames = null;  
          }  
          this.beanDefinitionMap.put(beanName, beanDefinition);  
          //重置所有已经注册过的BeanDefinition的缓存  
          resetBeanDefinition(beanName);  
      }  
} 

3、BeanDefinitionParser

BeanDefinitionParser的责任是解析定义schema在top-level的XML元素.在解析过程中,我们必须访问XML元素,因此我们可以解析我们自定义的XML内容,例如下面的例子:


package org.springframework.samples.xml; 
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element; 
import java.text.SimpleDateFormat;
 
public class SimpleDateFormatBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { 1 
    protected Class getBeanClass(Element element) {
        return SimpleDateFormat.class; 2
    }
 
    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        // this will never be null since the schema explicitly requires that a value be supplied
        String pattern = element.getAttribute("pattern");
        bean.addConstructorArg(pattern);
 
        // this however is an optional property
        String lenient = element.getAttribute("lenient");
        if (StringUtils.hasText(lenient)) {
            bean.addPropertyValue("lenient", Boolean.valueOf(lenient));
        }
    } 
}

注意:

  • 我们使用Spring提供的AbstractSingleBeanDefinitionParser 来处理创建一个single的BeanDefinition的一些基本的工作。
  • 我们重写了AbstractSingleBeanDefinitionParser父类的doParse方法来实现我们自己创建single类型的BeanDefinition的逻辑。

4、Registering the handler and the schema

编码工作完成了.下面是事情就是在Spring XML解析的逻辑能够织入我们定义的element;我们需要在两个特定的目标properties文件中注册我们自定义的namespaceHandler和自定义的XSD文件。这些properties文件都需要被放置在你项目中的'META-INF'应用下。

1) META-INF/spring.handlers

这个properties文件叫做'spring.handlers',包含XML Schema URIS与namespace处理类的映射。在我们的例子中,我们需要像下面:


http\://www.mycompany.com/schema/myns=org.springframework.samples.xml.MyNamespaceHandler

键值对的第一个部分(key)是关联你自定义namespace扩展的URI,并且需要匹配你自定义XSD Schema中的'targetNamespace'属性。

NamespaceHandlerResolver(DefaultNamespaceHandlerResolver)会找到当前classpath下的所有META-INF/spring.handlers文件,加载进来,读取里面的内容成namespaceURI到NamespaceHandler的map,并初始化所有的NamespaceHandler。

DefaultNamespaceHandlerResolver的resolve方法:


    public NamespaceHandler resolve(String namespaceUri) {
        Map<String, Object> handlerMappings = this.getHandlerMappings();
        Object handlerOrClassName = handlerMappings.get(namespaceUri);
        if (handlerOrClassName == null) {
            return null;
        } else if (handlerOrClassName instanceof NamespaceHandler) {
            return (NamespaceHandler)handlerOrClassName;
        } else {
            String className = (String)handlerOrClassName;
 
            try {
                Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
                if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
                    throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
                } else {
                    NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);
                    namespaceHandler.init();
                    handlerMappings.put(namespaceUri, namespaceHandler);
                    return namespaceHandler;
                }
            } catch (ClassNotFoundException var7) {
                throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
            } catch (LinkageError var8) {
                throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
            }
        }
    }
 
    private Map<String, Object> getHandlerMappings() {
        if (this.handlerMappings == null) {
            synchronized(this) {
                if (this.handlerMappings == null) {
                    try {
                        Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
                        if (this.logger.isDebugEnabled()) {
                            this.logger.debug("Loaded NamespaceHandler mappings: " + mappings);
                        }
 
                        Map<String, Object> handlerMappings = new ConcurrentHashMap(mappings.size());
                        CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
                        this.handlerMappings = handlerMappings;
                    } catch (IOException var5) {
                        throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
                    }
                }
            }
        } 
        return this.handlerMappings;
    }

PropertiesLoaderUtils中的loadAllProperties方法:


public static Properties loadAllProperties(String resourceName, ClassLoader classLoader) throws IOException {
        Assert.notNull(resourceName, "Resource name must not be null");
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = ClassUtils.getDefaultClassLoader();
        }
 
        Enumeration<URL> urls = classLoaderToUse != null ? classLoaderToUse.getResources(resourceName) : ClassLoader.getSystemResources(resourceName);
        Properties props = new Properties();
 
        while(urls.hasMoreElements()) {
            URL url = (URL)urls.nextElement();
            URLConnection con = url.openConnection();
            ResourceUtils.useCachesIfNecessary(con);
            InputStream is = con.getInputStream();
 
            try {
                if (resourceName.endsWith(".xml")) {
                    props.loadFromXML(is);
                } else {
                    props.load(is);
                }
            } finally {
                is.close();
            }
        } 
        return props;
    }

2) META-INF/spring.schemas

这个properties文件叫做'spring.schemas',包含XML Schema在classpath中的位置。这个文件主要是防止spring在网络上加载这个schema文件。如果你指定这个properties文件影射,Spring将会在classpath中查找这个schema(在这种情况下会在'org.springframework.samples.xml'包下面的'myns.xsd')


http\://www.mycompany.com/schema/myns/myns.xsd=org/springframework/samples/xml/myns.xsd

你最好部署你的XSD文件在你的NamespaceHandler和BeanDefinition类的classpath中。

5、最终效果演示

如果你已经完成了以上步骤,那么你就成功的定义了你自己的BeanDefinition在Spring IOC容器中。我们可以Spring IOC容器获取到并使用这个Bean对象。

1)配置文件

schema-beans.xml


<?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://www.mycompany.com/schema/myns"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.mycompany.com/schema/myns http://www.mycompany.com/schema/myns/myns.xsd">
 
    <myns:dateformat id="dateFormat"
                     pattern="yyyy-MM-dd HH:mm"
                     lenient="true"/> 
</beans>

2)测试类

SchemaBeanDefinitionTest.java


package org.springframework.samples.xml; 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; 
import java.text.SimpleDateFormat;
 
public class SchemaBeanDefinitionTest { 
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("schema-beans.xml");
        SimpleDateFormat dateFormat = context.getBean("dateFormat", SimpleDateFormat.class);
                System.out.println("-------------------gain object--------------------");
        System.out.println(dateFormat);
    } 
}

3)项目结构:

这里写图片描述

注意:在idea静态资源必须放在resources下面,不然会报错。

4)运行结果

这里写图片描述

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

使用Spring自定义命名空间

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

如何使用命名空间组织自定义 PHP 函数?

通过命名空间,您可以在 php 中将自定义函数分组到逻辑层级中,避免名称冲突,提高代码的可读性和可维护性。具体步骤包括:使用 namespace 关键字创建命名空间;在命名空间内定义自定义函数;使用 use 关键字使用命名空间中的函数。命名
如何使用命名空间组织自定义 PHP 函数?
2024-04-22

C#命名空间怎么定义和使用

在C#中,命名空间用于组织和管理代码,以便更好地组织项目结构和避免命名冲突。要定义一个命名空间,可以使用关键字"namespace",如下所示:namespace MyNamespace{// 在这里定义类、方法等}要在代码中使用命名
C#命名空间怎么定义和使用
2024-03-01

【C++】命名空间 namespace 与 标准流 iostream ( 命名空间概念简介 | 命名空间定义 | 命名空间使用 | iostream 中的命名空间分析 )

文章目录 一、命名空间 namespace1、命名空间基本概念2、名称概念4、C 语言的命名空间3、命名空间避免标识符冲突 二、命名空间定义1、命名空间基本概念2、命名空间定义语法3、代码示例 - 命名空间定义使用 三、命名
2023-08-20

php命名空间之怎么定义空间

小编给大家分享一下php命名空间之怎么定义空间,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!首先,我们了解一下什么是命名空间。(有需要的可以参考PHP 命名空间)
2023-06-20

C#命名空间怎么定义

这篇文章主要介绍“C#命名空间怎么定义”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C#命名空间怎么定义”文章能帮助大家解决问题。C# 命名空间(Namespace)命名空间的设计目的是提供一种让一
2023-06-17

C++命名空间namespace怎么定义

今天小编给大家分享一下C++命名空间namespace怎么定义的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、命名空间的定
2023-07-05

PHP扩展开发:如何使用命名空间组织和管理自定义函数?

使用命名空间管理自定义函数至关重要,它允许开发者创建自己的命名范围,防止名称冲突。步骤包括:创建命名空间(namespace)、使用 use 语句导入命名空间、调用命名空间函数。在实战案例中,mymath 扩展演示了如何使用命名空间组织数学
PHP扩展开发:如何使用命名空间组织和管理自定义函数?
2024-05-15

C++空间命名的使用

本文主要介绍了C++空间命名的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-01-28

Python中规范定义命名空间的一些建议

API的设计是一个艺术活。往往需要其简单、易懂、整洁、不累赘。 很多时候,我们在底层封装一个方法给高层用,而其它的方法只是为了辅助这个方法的。 也就是说我们只需要暴露这个方法就行,不用关心这个方法是怎么实现的,不用关心其它辅助方法的存在。
2022-06-04

Vuex命名空间namespaced的使用

本文主要介绍了Vuex命名空间namespaced的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-03-06

php命名空间怎么使用

在PHP中,命名空间用来解决不同类或函数同名的问题,使其具有唯一性和可管理性。通过使用命名空间,可以将相关的类、函数和常量组织在一起,避免命名冲突。使用命名空间的基本语法是在文件的开头使用`namespace`关键字来定义命名空间,然后在使
2023-08-08

php如何使用命名空间

这篇文章主要讲解了“php如何使用命名空间”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“php如何使用命名空间”吧!首先我们来看一个例子。file1.php 文件代码
2023-06-20

Vuex命名空间namespaced怎么使用

这篇文章主要介绍“Vuex命名空间namespaced怎么使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vuex命名空间namespaced怎么使用”文章能帮助大家解决问题。在项目中,如果需要用
2023-07-05

Win10怎么使用命令创建自定义大小的空文件

这篇文章主要介绍Win10怎么使用命令创建自定义大小的空文件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!创建空文件操作步骤1.右键开始按钮,选择“Windows PowerShell(管理员)”或“CMD命令提示符
2023-06-10

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录