Spring源码解析(五)循环依赖问题
引言
循环依赖就是多个类之间互相依赖,比如A依赖B,B也依赖A,如果日常开发中我们用new的方式创建对象,这种循环依赖就会导致不断的在创建对象,导致内存溢出。
Spring是怎么解决循环依赖的问题的?我们结合Spring源码来看一下。
第一种:构造器参数循环引用,单例
创建两个测试类:
public class UserServiceImpl implements UserService {
private TestService testService; public UserServiceImpl() {
} public UserServiceImpl(TestService testService) {
this.testService = testService;
}
}
public class TestServiceImpl implements TestService {
private UserService userService; public TestServiceImpl() { } public TestServiceImpl(UserService userService) {
this.userService = userService;
} }
Spring 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <bean id="userService" class="org.springframework.example.service.impl.UserServiceImpl" lazy-init="true">
<constructor-arg name="testService" ref="testService"></constructor-arg>
</bean>
<bean id="testService" class="org.springframework.example.service.impl.TestServiceImpl" lazy-init="true">
<constructor-arg name="userService" ref="userService"></constructor-arg>
</bean>
</beans>
测试类:
public class ApplicationContextTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("classpath*:test*.xml");
TestService testService= (TestService) context.getBean("testService");
System.out.println(testService);
}
}
例子很简单,两个类互相引用,通过构造器的方式初始化Bean并且两个都是单例。
我们看一下测试结果:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testService' defined in file [D:\spring-framework-3.2.15.RELEASE\spring-framework-3.2.15.RELEASE\spring-test\build\resources\main\test1.xml]: Cannot resolve reference to bean 'userService' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in file [D:\spring-framework-3.2.15.RELEASE\spring-framework-3.2.15.RELEASE\spring-test\build\resources\main\test1.xml]: Cannot resolve reference to bean 'testService' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testService': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:336)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:652)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:145)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1109)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1009)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:492)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:301)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1132)
at org.springframework.example.test.ApplicationContextTest.main(ApplicationContextTest.java:22)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService' defined in file [D:\spring-framework-3.2.15.RELEASE\spring-framework-3.2.15.RELEASE\spring-test\build\resources\main\test1.xml]: Cannot resolve reference to bean 'testService' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testService': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:336)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(ConstructorResolver.java:652)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:145)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1109)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1009)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:492)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:301)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
... 13 more
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testService': Requested bean is currently in creation: Is there an unresolvable circular reference?
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:327)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:217)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:328)
下面通过源码分析一下原因:
在spring中创建单例Bean调用的是DefaultSingletonBeanRegistry,我们直接看DefaultSingletonBeanRegistry就好了。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while the singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
/**1.创建bean之前singletonsCurrentlyInCreation put BeanName,该bean正在创建中*/
beforeSingletonCreation(beanName);
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<Exception>();
}
try {
/**2.创建Bean*/
singletonObject = singletonFactory.getObject();
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
/**3.bean创建完成以后singletonsCurrentlyInCreation删除beanName*/
afterSingletonCreation(beanName);
}
/**4.将单例Bean添加容器中*/
addSingleton(beanName, singletonObject);
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
1.创建bean之前判断该bean是否正在创建中
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.containsKey(beanName) &&
this.singletonsCurrentlyInCreation.put(beanName, Boolean.TRUE) != null) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
singletonsCurrentlyInCreation就是一个Map,如果第一次创建Bean,会将beanName添加到map中并返回前一个值null。比如我们现在先初始化UserService,那么map中就会存在<userService,true>
2.通过constructor初始化Bean,BeanDefinitionValueResolver
/**
* Resolve a reference to another bean in the factory.
*/
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
String refName = ref.getBeanName();
refName = String.valueOf(evaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
return this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
/**先初始化ref引用的bean*/
Object bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
}
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
UserService还没有创建完成,需要先创建TestService,创建TestService又会走第1步,将testService添加到map中<testService,true>,这个时候来到第2步,又会先创建UserService,这个时候又到流程1,
发现Map中已存在<userService,true>,这个时候就会抛出BeanCurrentlyInCreationException。
第二种:set方法方式,单例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <bean id="userService" class="org.springframework.example.service.impl.UserServiceImpl" lazy-init="true">
<property name="testService" ref="testService"></property>
</bean>
<bean id="testService" class="org.springframework.example.service.impl.TestServiceImpl" lazy-init="true">
<property name="userService" ref="userService"></property>
</bean>
</beans>
单例的实例化过程主要分为两步:创建bean实例,属性的依赖注入,之前通过带参数constructor实例化的时候,需要先实例化属性,所以导致了循环依赖。
set方法注入的方式是怎么避免的呢?接下来看一下AbstractAutowireCapableBeanFacotry:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
//省略.....if (instanceWrapper == null) {
/**1.创建bean实例*/
instanceWrapper = createBeanInstance(beanName, mbd, args);//通过Constructor初始化在此处就训陷入循环引用
}
//省略....................// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
/**
* 2.及早暴露单例bean引用,解决循环引用
*/
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//创建匿名内部类,匿名内部类会将beanName、mbd,bean(final修饰)拷贝一份到内部类,已保证当前方法执行完成后局部变量退栈后内部类还可以访问。
addSingletonFactory(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
} // Initialize the bean instance.
Object exposedObject = bean;
try {
/**
* 3.依赖注入
*/
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
/**
* 9.执行自定义BeanProcesser和init-method
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
//省略.......
1.创建bean实例时,用的无参构造器属性且属性并没有注入值。
2.及早暴露单例bean引用,这一步就是解决循环引用的关键。
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64); /** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16); /** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16); /** Set of registered singletons, containing the bean names in registration order */
private final Set<String> registeredSingletons = new LinkedHashSet<String>(64); /**
* Add the given singleton factory for building the specified singleton
* if necessary.
* <p>To be called for eager registration of singletons, e.g. to be able to
* resolve circular references.
* @param beanName the name of the bean
* @param singletonFactory the factory for the singleton object
*/
protected void addSingletonFactory(String beanName, ObjectFactory singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
this.singletonFactories.put(beanName, singletonFactory);这里把匿名内部类放到了map里,匿名内部类会将beanName、mbd,bean(final修饰)拷贝一份到内部类,通过
singletonFactory的getEarlyBeanReference方法可以获得未初始化完成的bean实例。这就相当于把未初始化完成的bean提前暴露出来。
/**
* Obtain a reference for early access to the specified bean,
* typically for the purpose of resolving a circular reference.
* @param beanName the name of the bean (for error handling purposes)
* @param mbd the merged bean definition for the bean
* @param bean the raw bean instance
* @return the object to expose as bean reference
*/
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
//这是扩展点,如果不扩展相当于直接返回bean
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return exposedObject;
}
}
}
}
return exposedObject;
}
3.依赖注入
bean创建完成后要为属性注入值
/**先初始化ref引用的bean*/
Object bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
例如当前初始化的是A依赖B,
这个时候就会初始化依赖对象B,B初始化过程跟A是一样的,也会到依赖注入这一步,这个时候同样会初始化依赖对象A,bean在初始化之前会先在缓冲中取,这个时候就可以取到A,就不会循环继续初始化下去。
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
//单例bean只是创建了实例,并没有为属性赋值,提前暴露出来,防止循环依赖
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
总结:
初始化A对象:
--创建A对象
--将包含A对象的匿名内部对象ObjectFacotry放到singletonFactories(map)中。
--依赖注入,创建对象B
--创建B对象
--将包含B对象的匿名内部对象ObjectFacotry放到singletonFactories(map)中。
--依赖注入,创建对象A
--创建之前,判断缓存中是否存在
singletonFactory.getObject()获取A,将对象A放到earlySingletonObjects(Map)中,并返回
--B对象创建完毕,放到singletonObjects(Map)中
--A对象创建完毕,放到singletonObjects(Map)中
初始化B对象:
--创建前,判断缓存中是否存在
Object singletonObject = this.singletonObjects.get(beanName);直接返回B
第三种:set方法方式和constructor混合,单例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <bean id="userService" class="org.springframework.example.service.impl.UserServiceImpl" lazy-init="true" >
<constructor-arg ref="testService" index="0"></constructor-arg>
</bean>
<bean id="testService" class="org.springframework.example.service.impl.TestServiceImpl" lazy-init="true">
<property name="userService" ref="userService"></property>
</bean>
</beans>
我们通过单例Bean初始化过程的梳理,通过默认构造器初始化的单例Bean会提前暴露出来,其他bean引用它的时候是可以直接获取到的。
现在这种配置情况,context.getBean("userService");是会抛出循环引用异常的,而context.getBean("testService")是正常的。
我们看一下测试结果:
第四种:set方法方式,prototype
prototype类型的bean循环依赖会报异常。通过源码看一下,这个比较简单
/**prototype类型,判断benaName是不是创建中,出现了循环引用*/
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//省略.......
/**
* 6.创建原型bean,scope="prototype"
*/
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
/** Names of beans that are currently in creation */
private final ThreadLocal<Object> prototypesCurrentlyInCreation =
new NamedThreadLocal<Object>("Prototype beans currently in creation"); protected void beforePrototypeCreation(String beanName) {
Object curVal = this.prototypesCurrentlyInCreation.get();
if (curVal == null) {
this.prototypesCurrentlyInCreation.set(beanName);
}
else if (curVal instanceof String) {
Set<String> beanNameSet = new HashSet<String>(2);
beanNameSet.add((String) curVal);
beanNameSet.add(beanName);
this.prototypesCurrentlyInCreation.set(beanNameSet);
}
else {
Set<String> beanNameSet = (Set<String>) curVal;
beanNameSet.add(beanName);
}
}
在创建prototype类型的bean之前会将beanName添加到prototypesCurrentlyInCreation,prototypesCurrentlyInCreation是ThreadLocal类型的,每个线程一个。所有创建中的BeanName都会放进去。
创建A对象
--判断benaName是不是创建中
--A 添加到prototypesCurrentlyInCreation
--创建A实例
--依赖注入
--创建依赖B
--判断benaName是不是创建中
--B添加到prototypesCurrentlyInCreation(此时prototypesCurrentlyInCreation对应的value值是个Set 包含了A和B)
--创建A实例
--判断benaName是不是创建中,这个时候就会抛出BeanCurrentlyInCreationException异常
Spring源码解析(五)循环依赖问题的更多相关文章
- Spring源码分析之循环依赖及解决方案
Spring源码分析之循环依赖及解决方案 往期文章: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostPro ...
- Spring源码-IOC部分-循环依赖-用实例证明去掉二级缓存会出现什么问题【7】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
- Spring源码--debug分析循环依赖--构造器注入
目的:源码调试构造器注入,看看是怎么报错的. spring:5.2.3 jdk:1.8 一.准备 首先准备两个循环依赖的类:userService和roleServic <bean id=&qu ...
- Spring源码解析-基于注解依赖注入
在spring2.5版本提供了注解的依赖注入功能,可以减少对xml配置. 主要使用的是 AnnotationConfigApplicationContext: 一个注解配置上下文 AutowiredA ...
- Spring源码解析——循环依赖的解决方案
一.前言 承接<Spring源码解析--创建bean>.<Spring源码解析--创建bean的实例>,我们今天接着聊聊,循环依赖的解决方案,即创建bean的ObjectFac ...
- Spring源码解析 - AbstractBeanFactory 实现接口与父类分析
我们先来看类图吧: 除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegistry和SingletonBeanRegistry接口. 这边主要提供了 ...
- Spring源码解析系列汇总
相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...
- Spring源码解析之BeanFactoryPostProcessor(三)
在上一章中笔者介绍了refresh()的<1>处是如何获取beanFactory对象,下面我们要来学习refresh()方法的<2>处是如何调用invokeBeanFactor ...
- Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...
- Celery 源码解析五: 远程控制管理
今天要聊的话题可能被大家关注得不过,但是对于 Celery 来说确实很有用的功能,曾经我在工作中遇到这类情况,就是我们将所有的任务都放在同一个队列里面,然后有一天突然某个同学的代码写得不对,导致大量的 ...
随机推荐
- error C2065:!错误:未定义标识符“pBuf);”
error C2065: “pBuf):”: 未声明的标识符 错误原因:第二个括号)使用的是中文符号!还有最后那个分号! 改回来就好了~ 原错误: 修正后错误消失:
- mysql数据库中,通过一条insert into语句,同时插入多个值
需求描述: 今天在看一本mysql的书籍,发现一个mysql中insert into好用的技巧,就是通过 1条insert into语句,插入多行数据,而不是多个insert into语句.在此记录下 ...
- C#获取CPU处理器核心数量的方法_C#教程
https://yq.aliyun.com/ziliao/89096 摘要: 本文讲的是C#获取CPU处理器核心数量的方法_C#教程, 有几条不同的处理器信息,您可以获得有关的信息:物理处理器数量.核 ...
- 工具类之数据库工具类:DBUtil(採用反射机制)
常常操作数据库的码农们一定知道操作数据库是一项非常复杂的工作.它不仅要解决各种乱码的问题还要解决各种数据表的增删改查等的操作. 另外每次操作数据库都要用到数据库连接.运行SQL语句.关闭连接的操作.所 ...
- Java精选笔记_面向对象(慨念、类和对象)
面向对象概念 在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象. 相对于面向过程而言.是一种思想,强调的是功能的对象. 面向对象的本质:以类的方式组织代码, ...
- webpack2.0简单配置教程
以前习惯用gulp+less来开发项目,由于公司项目用的vue开发的,所以学下webpack这个打包工具.以下是我学习时的笔记,希望给在webpack配置过程中遇到麻烦的朋友一丝帮助. 目前只配置了s ...
- os.path模块【python】
os.path.abspath(path) #返回绝对路径 os.path.basename(path) #返回文件名 os.path.commonprefix(list) #返回list(多个路径) ...
- EOF ---shell编程
转自:http://blog.163.com/njut_wangjian/blog/static/1657964252013112152418345/ 在shell编程中,”EOF“通常与”<& ...
- js jquery获取当前元素的兄弟级 上一个 下一个元素 jquery如何获取第一个或最后一个子元素
var chils= s.childNodes; //得到s的全部子节点 var par=s.parentNode; //得到s的父节点 var ns=s.nextSbiling; //获得 ...
- Objective-c官方文档翻译 类的定义
类是对象的蓝图. 一个类是描述了对象的行为和属性.例如NSString的一个实例.他的类提供了各种的方法来转化和表示他的内部字符的表示. 每个类的实例都包含了这个类的属性和行为.例如每个NSSt ...