返回顶部
首页 > 资讯 > 后端开发 > Python >如何利用Spring把元素解析成BeanDefinition对象
  • 475
分享到

如何利用Spring把元素解析成BeanDefinition对象

2024-04-02 19:04:59 475人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录前言1.BeanDefinition2.BeanDefinitionParserDelegate2.1.parseBeanDefinitionElement2.2.parseBe

前言

spring中解析元素最重要的一个对象应该就属于 BeanDefinition了;这个Spring容器中最基本的内部数据结构;它让xml文件中所有的配置有了一个归属的地方;在xml中存在的配置都能在BeanDefinition找到对应的属性;我们今天来看看BeanDefinition是如何被创建的

1.BeanDefinition

Spring 容器中的内部数据结构,是转换为容器中bean实例的最小接口,其中包含了 属性值、构造函数的参数值等等;

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;   // singleton作用域
    String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;   // prototype作用域

    
    int ROLE_APPLICATION = 0;   // 表明BeanDefinition是应用程序的主要部分。通常对应于用户定义的Bean
    int ROLE_SUPPORT = 1;   // 表明BeanDefinition是支持大部分配置。通常是外部的ComponentDefinition
    int ROLE_INFRASTRUCTURE = 2;    // 表明BeanDefinition提供了一个完全后台角色,与最终用户无关。这个提示是在注册bean时使用的,这些bean完全是组件定义的内部工作的一部分
    
    String getParentName();     
    void setParentName(String parentName);
    
    String getBeanClassName();      // 注意:这并不一定是运行时真正的类名,如果有一个子定义覆盖/继承父类的名称。
    void setBeanClassName(String beanClassName);    // 注意:类名可以在bean工厂的后处理器中进行修改,通常用它的解析变量替换原来的类名

    
    String getFactoryBeanName();
    void setFactoryBeanName(String factoryBeanName);
    String getFactoryMethodName();
    void setFactoryMethodName(String factoryMethodName);    // 注意:该方法由指定工厂Bean调用或者作为本地bean类的静态方法

    
    String getScope();
    void setScope(String scope);
    
    boolean isLazyInit();
    void setLazyInit(boolean lazyInit);
    
    String[] getDependsOn();
    void setDependsOn(String... dependsOn);
    
    boolean isAutowireCandidate
    void setAutowireCandidate(boolean autowireCandidate);

    
    boolean isPrimary();
    void setPrimary(boolean primary);

    
    ConstructorArgumentValues getConstructorArgumentValues();
    
    MutablePropertyValues getPropertyValues();
    
    boolean isSingleton();
    boolean isPrototype();
    boolean isAbstract();
    
    int getRole();
    
    String getDescription();
    String getResourceDescription();
    
    BeanDefinition getOriginatingBeanDefinition();
}

2.BeanDefinitionParserDelegate

BeanDefinitionParserDelegate是一个非常重要的类;spring将所有的解析操作都委托给了这个类;所有我们今天分析 BeanDefinition的创建,都是在这个类里面;

那么我们进一起进入探个究竟把;创建BeanDefinition的入口

2.1.parseBeanDefinitionElement

	
	public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
		//获取id
		String id = ele.getAttribute(ID_ATTRIBUTE);
		//获取name属性;例如:<bean id="simpleProducer" name="aliases1,;aliases2,;aliases3" > 这样就设置了多个别名了
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		List<String> aliases = new ArrayList<String>();
		if (StringUtils.hasLength(nameAttr)) {
		//解析别名;上面的例子就解析成了  三个别名了aliases1,;aliases2,;aliases3
			String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			aliases.addAll(Arrays.asList(nameArr));
		}
		String beanName = id;
		//如果没有设置id,但是设置了name ;那么就把name别名中的第一个当做 bean的名字;并且从别名中remove掉
		if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
			beanName = aliases.remove(0);
			if (logger.isDebugEnabled()) {
				logger.debug("No XML 'id' specified - using '" + beanName +
						"' as bean name and " + aliases + " as aliases");
			}
		}
		if (containingBean == null) {
			
			checkNameUniqueness(beanName, aliases, ele);
		}
		
		AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
		if (beanDefinition != null) {
			//如果没有设置 id 也没有设置name属性;则spring生成一个beanName
			if (!StringUtils.hasText(beanName)) {
				try {
					//TODO... 这个containingBean还不知道是干啥用的
					if (containingBean != null) {
						//自动生成beanName;生成规则我就不赘述了
						beanName = BeanDefinitionReaderUtils.generateBeanName(
								beanDefinition, this.readerContext.getReGIStry(), true);
					}
					else {
						beanName = this.readerContext.generateBeanName(beanDefinition);
						// Register an alias for the plain bean class name, if still possible,
						// if the generator returned the class name plus a suffix.
						// This is expected for Spring 1.2/2.0 backwards compatibility.
						String beanClassName = beanDefinition.getBeanClassName();
						if (beanClassName != null &&
								beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
								!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
							aliases.add(beanClassName);
						}
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Neither XML 'id' nor 'name' specified - " +
								"using generated bean name [" + beanName + "]");
					}
				}
				catch (Exception ex) {
					error(ex.getMessage(), ele);
					return null;
				}
			}
			String[] aliasesArray = StringUtils.toStringArray(aliases);
			//
			
			return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
		}

		return null;
	}

2.2.parseBeanDefinitionElement

	
	public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, BeanDefinition containingBean) {
		
		this.parseState.push(new BeanEntry(beanName));
		//获取element中有 class属性;
		String className = null;
		if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
			className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
		}

		try {
			//获取parent属性
			String parent = null;
			if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
				parent = ele.getAttribute(PARENT_ATTRIBUTE);
			}
			
			AbstractBeanDefinition bd = createBeanDefinition(className, parent);
			
			parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
			//设置description值;例如<description>test</description>
			bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
			
			parseMetaElements(ele, bd);
			
			parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
			
			parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
			//
			
			parseConstructorArgElements(ele, bd);
			
			parsePropertyElements(ele, bd);
			
			parseQualifierElements(ele, bd);

			bd.setResource(this.readerContext.getResource());
			bd.setSource(extractSource(ele));

			return bd;
		}
		catch (ClassNotFoundException ex) {
			error("Bean class [" + className + "] not found", ele, ex);
		}
		catch (NoClassDefFoundError err) {
			error("Class that bean class [" + className + "] depends on not found", ele, err);
		}
		catch (Throwable ex) {
			error("Unexpected failure during bean definition parsing", ele, ex);
		}
		finally {
			this.parseState.pop();
		}
		return null;
	}

2.3 parseBeanDefinitionAttributes

	 //解析bean的属性值
	public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
			BeanDefinition containingBean, AbstractBeanDefinition bd) {
		
		if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
			error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
		}
		
		else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
			bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
		}
		
		else if (containingBean != null) {
			// Take default from containing bean in case of an inner bean definition.
			bd.setScope(containingBean.getScope());
		}
		//设置 abstract属性,默认是 false
		if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
			bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
		}
		//如果当前元素没有设置 lazyInit 懒加载;则去 this.defaults.getLazyInit();这个defaults是上一篇分析过的;整个xml文件全局的默认值;
		String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
		if (DEFAULT_VALUE.equals(lazyInit)) {
			lazyInit = this.defaults.getLazyInit();
		}
		bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
		// 设置注入方式,有 byName byType 等等,如果当前没有设置,则取this.defaults.getAutowire()的值;
		//然后将其转换为对应的int类型;例如byName是int AUTOWIRE_BY_NAME = 1;
		String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
		bd.setAutowireMode(getAutowireMode(autowire));
		//这个dependency-check字面意义是依赖检查的类型;具体一会分析;如果当前没有设置,则取this.defaults.getDependencyCheck()的值;TODO...
		String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
		bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
		
		if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
			String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
			bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
		}
		//这个autowireCandidate不是很清楚  回头分析TODo..
		String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
		if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
			String candidatePattern = this.defaults.getAutowireCandidates();
			if (candidatePattern != null) {
				String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
				bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
			}
		}
		else {
			bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
		}
		//设置primary 装配时当出现多个Bean候选者时,被标记为Primary的Bean将作为首选者,否则将抛出异常 ;默认为false
		//https://blog.csdn.net/qq_16055765/article/details/78833260
		if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
			bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
		}
		//设置初始化方法
		if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
			String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
			if (!"".equals(initMethodName)) {
				bd.setInitMethodName(initMethodName);
			}
		}
		else {
			//如果 当前元素没有设置 init_method 属性,则判断 xml全局配置有没有设置;this.defaults是全局设置
			if (this.defaults.getInitMethod() != null) {
				bd.setInitMethodName(this.defaults.getInitMethod());
				bd.setEnforceInitMethod(false);
			}
		}
		//与上面初始化无二
		if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
			String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
			bd.setDestroyMethodName(destroyMethodName);
		}
		else {
			if (this.defaults.getDestroyMethod() != null) {
				bd.setDestroyMethodName(this.defaults.getDestroyMethod());
				bd.setEnforceDestroyMethod(false);
			}
		}
		//设置factoryMethodName; spring通过工厂方法配置Bean
		//Https://blog.csdn.net/mrwuyi/article/details/51578654
		if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
			bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
		}
		//设置factoryBeanName   spring通过工厂方法配置Bean
		//https://blog.csdn.net/mrwuyi/article/details/51578654
		if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
			bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
		}

		return bd;
	}

2.4 parseConstructorArgElement

	
	public void parseConstructorArgElement(Element ele, BeanDefinition bd) {
		String indexAttr = ele.getAttribute(INDEX_ATTRIBUTE);
		String typeAttr = ele.getAttribute(TYPE_ATTRIBUTE);
		String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
		//如果xml配置了index
		if (StringUtils.hasLength(indexAttr)) {
			try {
				int index = Integer.parseInt(indexAttr);
				if (index < 0) {
					error("'index' cannot be lower than 0", ele);
				}
				else {
					try {
						
						this.parseState.push(new ConstructorArgumentEntry(index));
							
						Object value = parsePropertyValue(ele, bd, null);
						//新建一个ValueHolder实例,这个专门存放构造参数的一些 属性值的
						ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
						//设置类型
						if (StringUtils.hasLength(typeAttr)) {
							valueHolder.setType(typeAttr);
						}
						//设置name
						if (StringUtils.hasLength(nameAttr)) {
							valueHolder.setName(nameAttr);
						}
						valueHolder.setSource(extractSource(ele));
						//验证index是否设置正确
						if (bd.getConstructorArgumentValues().hasIndexedArgumentValue(index)) {
							error("Ambiguous constructor-arg entries for index " + index, ele);
						}
						else {
						//ConstructorArgumentValues有个 Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<Integer, ValueHolder>(0)来hold参数
							bd.getConstructorArgumentValues().addIndexedArgumentValue(index, valueHolder);
						}
					}
					finally {
						//出栈;简单的栈结构来跟踪逻辑位置中解析过程,主要是记录异常信息的吧
						this.parseState.pop();
					}
				}
			}
			catch (NumberFORMatException ex) {
				error("Attribute 'index' of tag 'constructor-arg' must be an integer", ele);
			}
		}
		else {
			try {
				//与上无二
				this.parseState.push(new ConstructorArgumentEntry());
				Object value = parsePropertyValue(ele, bd, null);
				ConstructorArgumentValues.ValueHolder valueHolder = new ConstructorArgumentValues.ValueHolder(value);
				if (StringUtils.hasLength(typeAttr)) {
					valueHolder.setType(typeAttr);
				}
				if (StringUtils.hasLength(nameAttr)) {
					valueHolder.setName(nameAttr);
				}
				valueHolder.setSource(extractSource(ele));
				bd.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
			}
			finally {
				this.parseState.pop();
			}
		}
	}

再着重分析一下Object value = parsePropertyValue(ele, bd, null);

解析属性值,解析property 或者 constructor-arg;如下:

    <bean class="src.HelloWorld">
    <property name="beanA" ref="beanA" />
    <property name="name" value="姓名" />
    <constructor-arg name="a" value="1" />
    <constructor-arg name="list">
      <list>
        <value>1</value>
        <value>2</value>
        <value>3</value>
      </list>
    </constructor-arg>
    <meta key="meta1" value="meta1value"/>
  </bean>
  • 这个方法只有两个地方调用 ①.解析属性property元素的时候parsePropertyValue(ele, bd, propertyName) ②.解析构造参数constructor-arg元素的时候 parsePropertyValue(ele, bd, null)
  • 检查配置是否正确 最多只能有其中一个元素:ref,value,子元素(ref,value,list,set array 等等形式的元素) ;
  • 解析子元素,ref,value,list,set array.....等等
public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {
		String elementName = (propertyName != null) ?
						"<property> element for property '" + propertyName + "'" :
						"<constructor-arg> element";

		// 最多只能有其中一个元素:ref,value,子元素(ref,value,list,set array 等等形式的元素) 等等
		
		nodeList nl = ele.getChildNodes();
		Element subElement = null;
		
		for (int i = 0; i < nl.getLength(); i++) {
			Node node = nl.item(i);
			if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&
					!nodeNameEquals(node, META_ELEMENT)) {
				// Child element is what we're looking for.
				if (subElement != null) {
					error(elementName + " must not contain more than one sub-element", ele);
				}
				else {
					subElement = (Element) node;
				}
			}
		}
		
		boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);
		boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);
		//1.如果 ref 和 value都存在  抛异常
		//2.如果ref或者value存在 一个并且 subElement也存在  抛异常
		if ((hasRefAttribute && hasValueAttribute) ||
				((hasRefAttribute || hasValueAttribute) && subElement != null)) {
			error(elementName +
					" is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);
		}

//如果是ref;返回RuntimeBeanReference implements BeanReference;有beanName,toParent,source等属性
		if (hasRefAttribute) {
			String refName = ele.getAttribute(REF_ATTRIBUTE);
			if (!StringUtils.hasText(refName)) {
				error(elementName + " contains empty 'ref' attribute", ele);
			}
			RuntimeBeanReference ref = new RuntimeBeanReference(refName);
			ref.setSource(extractSource(ele));
			return ref;
		}
		//如果是value;返回TypedStringValue;设置属性 value和source 
		else if (hasValueAttribute) {
			TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));
			valueHolder.setSource(extractSource(ele));
			return valueHolder;
		}
		//如果是list;解析一下子元素
		else if (subElement != null) {
			return parsePropertySubElement(subElement, bd);
		}
		else {
			// Neither child element nor "ref" or "value" attribute found.
			error(elementName + " must specify a ref or value", ele);
			return null;
		}
	}
//解析子元素
public Object parsePropertySubElement(Element ele, BeanDefinition bd, String defaultValueType) {
		//如果不是默认的命名空间,则最终调用public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) 来解析;
		//第一篇文章分析过 根据元素选择不同的解析器来解析;
		if (!isDefaultNamespace(ele)) {
			return parseNestedCustomElement(ele, bd);
		}
		//解析<bean>元素;这里就是我们本文正在分析的方法,所以不概述了
		else if (nodeNameEquals(ele, BEAN_ELEMENT)) {
			BeanDefinitionHolder nestedBd = parseBeanDefinitionElement(ele, bd);
			if (nestedBd != null) {
				nestedBd = decorateBeanDefinitionIfRequired(ele, nestedBd, bd);
			}
			return nestedBd;
		}
		//如果是ref 元素 RuntimeBeanReference
		else if (nodeNameEquals(ele, REF_ELEMENT)) {
			// A generic reference to any name of any bean.
			String refName = ele.getAttribute(BEAN_REF_ATTRIBUTE);
			boolean toParent = false;
			if (!StringUtils.hasLength(refName)) {
				// A reference to the id of another bean in the same XML file.
				refName = ele.getAttribute(LOCAL_REF_ATTRIBUTE);
				if (!StringUtils.hasLength(refName)) {
					// A reference to the id of another bean in a parent context.
					refName = ele.getAttribute(PARENT_REF_ATTRIBUTE);
					toParent = true;
					if (!StringUtils.hasLength(refName)) {
						error("'bean', 'local' or 'parent' is required for <ref> element", ele);
						return null;
					}
				}
			}
			if (!StringUtils.hasText(refName)) {
				error("<ref> element contains empty target attribute", ele);
				return null;
			}
			RuntimeBeanReference ref = new RuntimeBeanReference(refName, toParent);
			ref.setSource(extractSource(ele));
			return ref;
		}
		//解析idref
		else if (nodeNameEquals(ele, IDREF_ELEMENT)) {
			return parseIdRefElement(ele);
		}
		//解析value
		else if (nodeNameEquals(ele, VALUE_ELEMENT)) {
			
			return parseValueElement(ele, defaultValueType);
		}
		//解析null
		else if (nodeNameEquals(ele, NULL_ELEMENT)) {
			// It's a distinguished null value. Let's wrap it in a TypedStringValue
			// object in order to preserve the source location.
			TypedStringValue nullHolder = new TypedStringValue(null);
			nullHolder.setSource(extractSource(ele));
			return nullHolder;
		}
		//解析array
		else if (nodeNameEquals(ele, ARRAY_ELEMENT)) {
			return parseArrayElement(ele, bd);
		}
		//list
		else if (nodeNameEquals(ele, LIST_ELEMENT)) {
			return parseListElement(ele, bd);
		}
		//set
		else if (nodeNameEquals(ele, SET_ELEMENT)) {
			return parseSetElement(ele, bd);
		}
		//map
		else if (nodeNameEquals(ele, MAP_ELEMENT)) {
			return parseMapElement(ele, bd);
		}
		//props
		else if (nodeNameEquals(ele, PROPS_ELEMENT)) {
			return parsePropsElement(ele);
		}
		else {
			error("Unknown property sub-element: [" + ele.getNodeName() + "]", ele);
			return null;
		}
	}

3 总结

至此,BeanDefinition就已经解析完成了! 我们一起总结一下整个流程:

  • 解析 id,name属性放入List aliases中;aliases持有所有别名
  • 检查beanName,和aliases是否跟之前有重复;因为当前的对象BeanDefinitionParserDelegate中属性 Set usedNames 会持有所有解析出来的beanName 和 aliases;
  • 解析元素,将xml中的所有元素解析成AbstractBeanDefinition中对应的属性;
  • 解析完了拿到AbstractBeanDefinition的实例之后;创建一个BeanDefinitionHolder实例对象; 这个实例对象持有 AbstractBeanDefinition,beanName,aliases;这些属性;并且返回holder实例对象;

到此这篇关于如何利用Spring把元素解析成BeanDefinition对象的文章就介绍到这了,更多相关Spring BeanDefinition内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 如何利用Spring把元素解析成BeanDefinition对象

本文链接: https://lsjlt.com/news/166439.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 如何利用Spring把元素解析成BeanDefinition对象
    目录前言1.BeanDefinition2.BeanDefinitionParserDelegate2.1.parseBeanDefinitionElement2.2.parseBe...
    99+
    2024-04-02
  • 如何使用JavaScript对象元素
    这篇文章主要讲解了“如何使用JavaScript对象元素”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何使用JavaScript对象元素”吧! 该<...
    99+
    2024-04-02
  • 如何Spring Boot中使用MockMvc对象进行单元测试
    这期内容当中小编将会给大家带来有关如何Spring Boot中使用MockMvc对象进行单元测试,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Spring测试框架提供MockMvc对象,可以在不需要客户端...
    99+
    2023-05-31
    springboot mockmvc
  • 利用java如何实现把对象数组导出从Excel文件
    利用java如何实现把对象数组导出从Excel文件?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、导入相关jar包,pom依赖如下: <dependency> ...
    99+
    2023-05-31
    java excel 对象数组
  • 如何在spring mvc中controller的对象如何利用ajax进行传递
    如何在spring mvc中controller的对象如何利用ajax进行传递?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。基础类型如果传递的json数据为基础类型(Int,S...
    99+
    2023-05-31
    springmvc ajax controller
  • 如何利用Spring容器实现高效的Java对象存储?
    Spring框架是一个非常流行的Java开发框架,它提供了很多功能强大的工具和库,让Java开发变得更加高效和简便。其中,Spring容器是Spring框架的核心组件之一,它可以帮助我们管理Java对象的生命周期,控制对象的创建和销毁,并提...
    99+
    2023-11-02
    存储 spring 容器
  • jQuery如何在创建元素时使用对象来定义属性
    这篇文章主要为大家展示了“jQuery如何在创建元素时使用对象来定义属性”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“jQuery如何在创建元素时使用对象来定义属性”这篇文章吧。创建元素时使用对...
    99+
    2023-06-27
  • Spring中如何集成Ehcache使用页面以及对象缓存
    Spring中如何集成Ehcache使用页面以及对象缓存,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。Ehcache在很多项目中都出现过,用法也比较简单。一般的加些配置就可...
    99+
    2023-06-17
  • 如何利用同步对象提高 ASP 应用的响应速度?教程解析
    ASP应用的响应速度是一个非常重要的指标,影响着用户体验和网站的整体性能。同步对象是提高ASP应用响应速度的一种有效方法,本文将为您介绍如何利用同步对象来提高ASP应用的响应速度。 一、什么是同步对象 同步对象是一种多线程编程技术,用于协调...
    99+
    2023-07-25
    教程 同步 对象
  • 如何利用vertical-align:middle实现行内元素的水平垂直居中对齐
    这篇文章主要讲解了“如何利用vertical-align:middle实现行内元素的水平垂直居中对齐”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何利用v...
    99+
    2024-04-02
  • 如何解析XML DOM文档对象模型用法
    这期内容当中小编将会给大家带来有关如何解析XML DOM文档对象模型用法,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。向大家简单介绍一下XML DOM,XML DOM是X...
    99+
    2024-04-02
  • json数据如何利用JSONObject进行生成并解析
    json数据如何利用JSONObject进行生成并解析?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1. json数据类型类型描述Number数字型String字符串型Bo...
    99+
    2023-05-31
    jsonobject json
  • 如何解析Java 面向对象的特征与应用
    这篇文章给大家介绍如何解析Java 面向对象的特征与应用,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。## 类和对象* 面向对象与面向过程面向过程:是指类似在C语言学习中,所写的代码都在主程序(main())中运行,非...
    99+
    2023-06-25
  • jQuery如何使用特定名字的元素对应的值生成一个数组
    这篇文章主要为大家展示了“jQuery如何使用特定名字的元素对应的值生成一个数组”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“jQuery如何使用特定名字的元素对应的值生成一个数组”这篇文章吧。...
    99+
    2023-06-27
  • 如何利用 Python 脚本解析 Spring Boot 项目的日志文件?
    Spring Boot 是一种流行的 Java 应用程序框架,它的日志文件可以提供有关应用程序行为和错误的重要信息。但是,解析这些日志文件可能很困难,特别是当日志文件很大或需要长时间监视时。在本文中,我们将介绍如何使用 Python 脚本解...
    99+
    2023-09-04
    文件 关键字 spring
  • 学习如何在CSS中准确地定位元素:深入解析绝对定位属性
    绝对定位属性CSS详解:掌握定位元素在文档流中的准确定位方法,需要具体代码示例 导言: 在前端开发中,我们经常会遇到需要将元素精确定位在指定位置的情况。CSS中的绝对定位属性能够帮助我们实现这一目标。本文将深入探讨绝对定位属性(...
    99+
    2024-01-23
    绝对定位 文档流 定位元素
  • LeetCode算法题:如何利用Java对象重定向达到最优解?
    在LeetCode算法题中,经常会遇到需要在一个函数中同时处理输入和输出的情况。这时候,我们可以利用Java对象重定向来达到最优解。本文将详细介绍如何利用Java对象重定向来解决这类问题。 Java对象重定向是指将一个Java对象的输出流...
    99+
    2023-08-15
    对象 重定向 leetcode
  • 如何解析Java对象引用与JVM自动内存管理
    今天就跟大家聊聊有关如何解析Java对象引用与JVM自动内存管理,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。解析Java对象引用与JVM自动内存管理(转)[@more@]对象引用应...
    99+
    2023-06-03
  • Java编程技巧:如何利用对象重定向解决LeetCode算法题?
    在LeetCode算法题中,我们经常需要在代码中使用大量的循环和条件语句,以实现算法的核心逻辑。然而,这样的代码往往难以维护和调试,同时也很难通过单元测试来验证其正确性。因此,我们需要一种更加高效、可维护的方法来解决这些问题。在本文中,我...
    99+
    2023-08-15
    对象 重定向 leetcode
  • 利用信号如何监控Django模型对象字段值的变化详解
    django信号系统 django自带一套信号发射系统来帮助我们在框架的不同位置传递信息.也就是说,当某一事件发生时,信号系统可以允许一个或多个发送者(senders)将通知或信号(signals)推送...
    99+
    2022-06-04
    字段 详解 模型
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作