spring源碼閱讀(1/4) - Bean生成

上午去繳了上次沒帶駕駛證的扣分罰款,最近在圖書館沒事就看曾國藩家書,曾國藩說人要明強。光強沒有用,你要明強。也就是說要強的有道理。曾國藩又說,做學問不能做死學問,做學問其實很重要的事就是能懂得孝悌,把家持好,能做事。能做事很重要,學問再高,不能做事,也是無用。相反即使沒什么學問,寫不出來,但是能做事,事事做的條理,家庭安排的和睦,家族事宜能夠有積極的貢獻,再到更大的方面,都能做好,這才是學問的意義。看了一下,上一篇文章已經是2號的了,這個月已經9號了,1/3了,可是這重頭的Bean加載還沒有什么大的進展,這樣怎么能行,家里的事情還要辦,很多事情還沒弄好,這可不行呀。

想要人生有所突破,下一番苦工是不可能省略的。一半努力一半隨心所欲,是不可能成就的。

“須是策勵此心,勇猛奮發,撥出心肝與他去做!如兩邊擂起戰鼓,莫問前頭如何,只認卷將去!如此,方做得工夫。若半上落下,半沉半浮,濟得甚事!” 朱熹 .《朱子語錄》

我們繼續上節的內容,這節主要是bean的加載。

我們從ServerMain的方法中的getBean("")作為入口來看:

public Object getBean(String name) throws BeansException {return this.doGetBean(name, (Class)null, (Object[])null, false);}

繼續調用,都在AbstractBeanFactory中進行,下邊這段就是恐怖的bean加載了。我們可以翻到最后看下返回了Bean,當然bean是范性的,先拋開中間的過程不說,這里返回的就是實實在在的我們需要的Bean了,似乎一切都在這個方法里,沒錯所有的“恩怨”都在這里。

protected <T> T doGetBean(String name, Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {final String beanName = this.transformedBeanName(name);Object sharedInstance = this.getSingleton(beanName);Object bean;if (sharedInstance != null && args == null) {if (this.logger.isDebugEnabled()) {if (this.isSingletonCurrentlyInCreation(beanName)) {this.logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference");} else {this.logger.debug("Returning cached instance of singleton bean '" + beanName + "'");}}bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);} else {if (this.isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}BeanFactory parentBeanFactory = this.getParentBeanFactory();if (parentBeanFactory != null && !this.containsBeanDefinition(beanName)) {String nameToLookup = this.originalBeanName(name);if (args != null) {return parentBeanFactory.getBean(nameToLookup, args);}return parentBeanFactory.getBean(nameToLookup, requiredType);}if (!typeCheckOnly) {this.markBeanAsCreated(beanName);}try {final RootBeanDefinition mbd = this.getMergedLocalBeanDefinition(beanName);this.checkMergedBeanDefinition(mbd, beanName, args);String[] dependsOn = mbd.getDependsOn();String[] var11;if (dependsOn != null) {var11 = dependsOn;int var12 = dependsOn.length;for(int var13 = 0; var13 < var12; ++var13) {String dependsOnBean = var11[var13];if (this.isDependent(beanName, dependsOnBean)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");}this.registerDependentBean(dependsOnBean, beanName);this.getBean(dependsOnBean);}}if (mbd.isSingleton()) {sharedInstance = this.getSingleton(beanName, new ObjectFactory<Object>() {public Object getObject() throws BeansException {try {return AbstractBeanFactory.this.createBean(beanName, mbd, args);} catch (BeansException var2) {AbstractBeanFactory.this.destroySingleton(beanName);throw var2;}}});bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);} else if (mbd.isPrototype()) {var11 = null;Object prototypeInstance;try {this.beforePrototypeCreation(beanName);prototypeInstance = this.createBean(beanName, mbd, args);} finally {this.afterPrototypeCreation(beanName);}bean = this.getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);} else {String scopeName = mbd.getScope();Scope scope = (Scope)this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");}try {Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {public Object getObject() throws BeansException {AbstractBeanFactory.this.beforePrototypeCreation(beanName);Object var1;try {var1 = AbstractBeanFactory.this.createBean(beanName, mbd, args);} finally {AbstractBeanFactory.this.afterPrototypeCreation(beanName);}return var1;}});bean = this.getObjectForBeanInstance(scopedInstance, name, beanName, mbd);} catch (IllegalStateException var21) {throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active for the current thread; " + "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", var21);}}} catch (BeansException var23) {this.cleanupAfterBeanCreationFailure(beanName);throw var23;}}if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {try {return this.getTypeConverter().convertIfNecessary(bean, requiredType);} catch (TypeMismatchException var22) {if (this.logger.isDebugEnabled()) {this.logger.debug("Failed to convert bean '" + name + "' to required type [" + ClassUtils.getQualifiedName(requiredType) + "]", var22);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}} else {return bean;}}

好,下邊我們就開始這場江湖的血雨腥風。

首先第一句就是:

final String beanName = this.transformedBeanName(name);

這句做的事情,好像不知道所云,因為beanName不是作為參數傳進來了嗎,還要再轉換是什么意思,稍微想一下就知道了,我們獲取bean的時候傳過來的name參數,有可能是別名。

如果是別名這里就需要轉換一下了,因為我們需要真正的名稱。

翻看下代碼:

protected String transformedBeanName(String name) {return this.canonicalName(BeanFactoryUtils.transformedBeanName(name));}

括號里邊的部分的代碼如下:

public static String transformedBeanName(String name) {Assert.notNull(name, "'name' must not be null");String beanName;for(beanName = name; beanName.startsWith("&"); beanName = beanName.substring("&".length())) {}return beanName;}

如果name是以&開頭的,那么去除開頭的&符號。繼續:

public String canonicalName(String name) {String canonicalName = name;String resolvedName;do {resolvedName = (String)this.aliasMap.get(canonicalName);if (resolvedName != null) {canonicalName = resolvedName;}} while(resolvedName != null);return canonicalName;}

這里很容易看出來,就是根據名稱去別名map中獲取有沒有對應的名稱。目的就是獲取別名對應的真實Bean名稱。

接下來這句getSingleton就涉及到偉大的又扯淡的各種面試都會問到的循環依賴問題了,其實不復雜,但是沒認真研究過代碼。關于循環依賴的問題,可以看下個章節。這里重點還是創建Bean這個主題。

我們繼續上邊的doCreateBean(name, requiredType, args[], typeCheckOnly)的代碼。轉換完名字之后,緊接的一句是getSingleton(beanName).

@Override@Nullablepublic Object getSingleton(String beanName) {return getSingleton(beanName, true);}/*** 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*/@Nullableprotected 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();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}

這里我們觀察注釋,能夠了解一部分:返回已這個beanName注冊的實例。并且檢查已經初始化的實例,允許當前創建的實例有一個早期的引用(用來解決循環依賴問題)。

我們深入代碼來看一下:

首先從singletonObjects.get(beanName)從緩存里獲取一下,看有沒有,如果有直接返回。如果沒有,并且當前beanName正在創建,那么加鎖后邊的這部分代碼:

判斷beanName是否在earlySingletonObjects列表中,如果不在并且允許早期引用,那么就獲取beanName對應的ObjectFactory。然后調用ObjectFactory.getObject()返回實例。并將該實例添加到earlySingletonObjects中。這里確實就是解決循環引用的核心了,解決循環依賴的核心就是這里的這個singletonFactories.get(beanName)獲取singletonFactory,然后調用getOjbect返回實例。說的通俗一點兒就是可能對象還沒有創建,但是能夠創建這個對象的ObjectFactroy會提前放入緩存中,這樣,當后續創建過程中,需要引用一個之前還沒有創建完的bean時,就會調用這里的ObjectFactory.getObject()返回一個實例對象。

這個部分我們在下一篇專門將循環依賴的文章里詳細闡述。在這里,這個getSingleton在整體流程上,最核心的是從緩存中嘗試獲取bean。

我們繼續看下代碼,我們用粗體標示了一個方法:getObjectForBeanInstance(scopedInstance, name, beanName, mdb)。我們看到,后續的幾種情況里,無論是singleton/prototype/還是其他實例模式,得到bean之后,做的事情都是這個getObjectForBeanInstance方法,我們來跟進看下:

    /** 獲取給定bean實例的對象,要么bean實例本身,要么當它是一個FactroyBean時,它創建出來的對象**/protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {// 如果指定的name是&開頭即工廠相關的,但又不是FactoryBean類型,則拋出異常,類型驗證不通過if (BeanFactoryUtils.isFactoryDereference(name)) {if (beanInstance instanceof NullBean) {return beanInstance;}if (!(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());}}
// 現在我們有個這個bean實例,但是這個bean實例可能是普通bean也可能是FactoryBean,如果是FactoryBean,那么我們使用它來獲取工廠實例,如果調用者需要的是
FactoryBean本身,那么beanName參數需要帶"&"
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {return beanInstance;}// 到這里就明確是一個FactoryBean,因為如果不是上邊已經返回了Object object = null;if (mbd == null) {object = getCachedObjectForFactoryBean(beanName);}if (object == null) {// Return bean instance from factory.FactoryBean<?> factory = (FactoryBean<?>) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.if (mbd == null && containsBeanDefinition(beanName)) {mbd = getMergedLocalBeanDefinition(beanName);}boolean synthetic = (mbd != null && mbd.isSynthetic());object = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;}

1:判斷是否是FactoryBean,判斷依據是 beanName是否是"&"開頭的。如果是&開頭,則表示是獲取FactoryBean本身,如果不是&開頭,則是獲取FactroyBean的方法返回的Bean。如果是&開頭,但是本身并不是FactoryBean類型,則拋出異常。

2:如果本身不是FactoryBean類型或者beanName不是以“&”開頭的,那么直接返回Bean本身。

3:判斷BeanDefinitions中是否存在該beanName。這里做的事情其實是將我們解析時候生成的GenericBeanDefinition轉換成RootBeanDefinition.細節這里就不說了。

4:最后委托給getObjectFromFactoryBean(factory, beanName, !synthetic)方法類獲取真正的實例。

我們繼續往下看:

     /**  獲得從給定的FactoryBean獲取出來的對象*/protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {if (factory.isSingleton() && containsSingleton(beanName)) {synchronized (getSingletonMutex()) {Object object = this.factoryBeanObjectCache.get(beanName);if (object == null) {object = doGetObjectFromFactoryBean(factory, beanName);// Only post-process and store if not put there already during getObject() call above// (e.g. because of circular reference processing triggered by custom getBean calls)Object alreadyThere = this.factoryBeanObjectCache.get(beanName);if (alreadyThere != null) {object = alreadyThere;}else {if (shouldPostProcess) {if (isSingletonCurrentlyInCreation(beanName)) {// Temporarily return non-post-processed object, not storing it yet..return object;}beforeSingletonCreation(beanName);try {object = postProcessObjectFromFactoryBean(object, beanName);}catch (Throwable ex) {throw new BeanCreationException(beanName,"Post-processing of FactoryBean's singleton object failed", ex);}finally {afterSingletonCreation(beanName);}}if (containsSingleton(beanName)) {this.factoryBeanObjectCache.put(beanName, object);}}}return object;}}else {Object object = doGetObjectFromFactoryBean(factory, beanName);if (shouldPostProcess) {try {object = postProcessObjectFromFactoryBean(object, beanName);}catch (Throwable ex) {throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);}}return object;}}

核心其實就是這句doGetObjectFromFactoryBean(factory, beanName)。里邊的if里是判斷是否是單例,而里邊的內容跟else的區別就是如果是單例,那么就嘗試從緩存中獲取,如果緩存中沒有才調用到doGetObjectFactoryBean(factory, beanName)。還有里邊的beforeSingletonCreation和afterSingletonCreation則都是保證創建過程中,不會重復創建實例,是為了保證單例性。

好了,我們還是繼續一層一層的往下看吧。

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)throws BeanCreationException {Object object;try {if (System.getSecurityManager() != null) {AccessControlContext acc = getAccessControlContext();try {object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);}catch (PrivilegedActionException pae) {throw pae.getException();}}else {object = factory.getObject();}}catch (FactoryBeanNotInitializedException ex) {throw new BeanCurrentlyInCreationException(beanName, ex.toString());}catch (Throwable ex) {throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);}// Do not accept a null value for a FactoryBean that's not fully// initialized yet: Many FactoryBeans just return null then.if (object == null) {if (isSingletonCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");}object = new NullBean();}return object;}

終于到了最后獲取對象的地方了,這里getObject()的調用為整個通過FactoryBean獲取實例的解析過程畫上美麗的句號。

承接上文,我們對緩存中獲取bean和FactoryBean方式獲取Bean進行了闡述。對getBean("")方法進行了闡述。這一篇我們先深入單例的創建來詳細說一下spring循環依賴問題的解決。

我們從doGetBean方法繼續,我們主要看下singleton這一部分:

// Create bean instance.if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);throw ex;}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}

我們繼續getSingleton(beanName, singletonFactory)。

    /*** 返回beanName注冊過的單例對象,如果沒有,那么創建并注冊該beanName的實例*/public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName);  // 1if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while 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 + "'");}beforeSingletonCreation(beanName); // 2boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {singletonObject = singletonFactory.getObject(); // 3newSingleton = true;}catch (IllegalStateException ex) {// Has the singleton object implicitly appeared in the meantime ->// if yes, proceed with it since the exception indicates that state.singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}afterSingletonCreation(beanName); // 4}if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;}}

這里其實最核心的就是singletonFactory.getObject()。我們梳理下步驟:

1:嘗試從緩存獲取beanName對應的bean

2:如果沒有,調用beforeSingletonCreation(beanName),將beanName放入singletonCurrentlyInCreation列表。

3:通過調用參數傳入的FactoryBean的getObject方法,獲取實例化bean

4:加載完成后,處理之后的方法調用。這里做的事情跟beforeSingletonCreation正好相反,把beanName從singletonCurrentlyInCreation中刪除

5:緩存生成的object。并刪除生成過程中的相關狀態。

/*** Add the given singleton object to the singleton cache of this factory.* <p>To be called for eager registration of singletons.* @param beanName the name of the bean* @param singletonObject the singleton object*/protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject); // 放入緩存this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}

6:返回bean,這個bean就是上邊getSingleton(beanName, singletonFactory)的這個參數,在doGetBean中定義的方法。

                    sharedInstance = getSingleton(beanName, () -> { // 這里是jdk8引入的函數是寫法,這里其實就是ObjectFactroy的一個匿名類實現try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.
                            destroySingleton(beanName);throw ex;}});

接下來就是創建bean的代碼了。

我們來詳細看下這個createBean(beanName, mdb, args)

/*** Central method of this class: creates a bean instance,* populates the bean instance, applies post-processors, etc.* @see #doCreateBean*/@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {if (logger.isTraceEnabled()) {logger.trace("Creating instance of bean '" + beanName + "'");}RootBeanDefinition mbdToUse = mbd;// Make sure bean class is actually resolv1ed at this point, and// clone the bean definition in case of a dynamically resolved Class// which cannot be stored in the shared merged bean definition.Class<?> resolvedClass = resolveBeanClass(mbd, beanName);if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {mbdToUse = new RootBeanDefinition(mbd);mbdToUse.setBeanClass(resolvedClass);}// Prepare method overrides.try {mbdToUse.prepareMethodOverrides();}catch (BeanDefinitionValidationException ex) {throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),beanName, "Validation of method overrides failed", ex);}try {// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.Object bean = resolveBeforeInstantiation(beanName, mbdToUse);if (bean != null) {return bean;}}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,"BeanPostProcessor before instantiation of bean failed", ex);}try {Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {// A previously detected exception with proper bean creation context already,// or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.throw ex;}catch (Throwable ex) {throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);}}

1:根據mdb獲取beanName對應的class。

2:對override屬性進行處理

3:應用初始化前的處理器

4:創建bean

我們來詳細看下override 的處理

/*** Validate and prepare the method overrides defined for this bean.* Checks for existence of a method with the specified name.* @throws BeanDefinitionValidationException in case of validation failure*/public void prepareMethodOverrides() throws BeanDefinitionValidationException {// Check that lookup methods exists.if (hasMethodOverrides()) {Set<MethodOverride> overrides = getMethodOverrides().getOverrides();synchronized (overrides) {for (MethodOverride mo : overrides) {prepareMethodOverride(mo);}}}}/*** Validate and prepare the given method override.* Checks for existence of a method with the specified name,* marking it as not overloaded if none found.* @param mo the MethodOverride object to validate* @throws BeanDefinitionValidationException in case of validation failure*/protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());if (count == 0) {throw new BeanDefinitionValidationException("Invalid method override: no method with name '" + mo.getMethodName() +"' on class [" + getBeanClassName() + "]");}else if (count == 1) {// Mark override as not overloaded, to avoid the overhead of arg type checking.mo.setOverloaded(false);}}

這里我們要理解下lookup-method和override-method的問題。這兩個配置我們在解析xml的時候說過但沒有太詳細介紹,這兩個的作用lookup-method。(這里不太明白還,暫時放這里,后續bean生成的時候看下到底代碼如何實現的,再過來看)

轉載于:https://www.cnblogs.com/aquariusm/p/11156741.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/247576.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/247576.shtml
英文地址,請注明出處:http://en.pswp.cn/news/247576.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

NodeJS解決跨域問題:Access-Control-Allow-Origin

今天在玩vue-resource時&#xff0c;后臺使用nodejs來提供數據&#xff0c;由于需要跨域&#xff0c;在網上也找到了解決方法。 vue-resource代碼(其實就是ajax技術)&#xff1a; this.$http.get({url:"http://localhost:3000/getdata"}) .then(function (data) {co…

windows10系統下MongoDB的安裝及環境配置

windows10系統下MongoDB的安裝及環境配置&#xff1a; MongoDB的安裝 下載地址&#xff1a; https://www.mongodb.com/download-center (這是windows10環境下的教程&#xff01;請注意&#xff01;) 下載后&#xff0c;我們點擊mongodb-win32-x86_64-2008plus-ssl-3.4.3-signed…

Net EF to MySQL生成edmx文件時報錯:StrongTypingException:表“TableDetails中列“IsPrimaryKey的值為DBNull...

使用Net寫項目&#xff0c;數據庫用的MySQL&#xff0c;EF生成edmx文件時&#xff0c;報錯&#xff0c;StrongTypingException:表“TableDetails"中列“IsPrimaryKey"的值為DBNull。 解決方法&#xff1a; 1.重啟MySQL服務 2.MySQL中運行下以下命令&#xff1a; use …

MongoDB之在mac上設置環境變量

要下班&#xff0c;簡介做個筆記。設置環境變量在基于unix/linux的操作系統下進行程序開發&#xff0c;使用環境變量將會方便。通過設置環境變量將可以在任意目錄通過輸入程序名來執行設定目錄下的程序。不需要通過cd將工作目錄改變到程序目錄再執行程序。而且免去了輸入"…

popup a new windows

popup a new windows window.open(url, newwindow, height500, width850, top0, left0, toolbarno, menubarno, scrollbarsno, resizableno,locationno, statusno); 轉載于:https://www.cnblogs.com/sandy_liao/archive/2010/06/24/1764533.html

CSS clip:rect矩形剪裁功能

CSS中有一個屬性叫做clip&#xff0c;為修剪&#xff0c;剪裁之意。配合其屬性關鍵字rect可以實現元素的矩形裁剪效果。此屬性安安穩穩地存在于CSS2.1中&#xff0c;且使用上基本上沒有類似于max-height/display:table-cell等瀏覽器的兼容性問題。 根據Dreamweaver的自動提示&a…

CSS隱藏元素的十四種方法

通過設置width:0或者height:0隱藏一個元素&#xff0c;文字隱藏可以設置color為背景色或transparent&#xff0c;但內容還在&#xff0c;所以用font-size:0&#xff1b; 將元素的opacity設置為0&#xff0c;元素本身還在&#xff0c;只是看不見&#xff1b; 通過絕對定位將元…

jquery.lazyload.js詳解

簡介lazyload.js用于長頁面圖片的延遲加載&#xff0c;視口外的圖片會在窗口滾動到它的位置時再進行加載&#xff0c;這是與預加載相反的。優點&#xff1a;它可以提高頁面加載速度&#xff1b;在某些情況清晰它也可以幫助減少服務器負載。安裝bower安裝&#xff1a;$ bower in…

Spring Boot Cache使用與整合

參考&#xff1a; 史上最全的Spring Boot Cache使用與整合Spring Cache擴展&#xff1a;注解失效時間主動刷新緩存 項目地址使用本地Caffeine緩存 引入依賴包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starte…

vue-cli的打包配置文件

轉載原文: 詳解 vue-cli 的打包配置文件代碼&#xff08;給大家寫寫注釋&#xff09;. 一、vue-cli都做了什么 1、build/dev-server.js 文件 項目node的啟動文件&#xff0c;這里面做了webpack配置和node操作&#xff0c; 2、build/webpack.base.conf.js webpack基本配置文件…

Node.js 部署免費/自動續訂 HTTPS

統計了使用 Chrome 瀏覽器&#xff0c;訪問的站點統計中&#xff0c;HTTPS 使用率的增長情況&#xff1a;而在今年 2 月份&#xff0c;Chrome 團隊也宣布&#xff0c;將在 2018 年 7 月份發布的 Chrome 68 中&#xff0c;將沒有部署 HTTPS 的網站標記為 "不安全"。簡…

GSON 循環引用的對象轉為 JSON 造成棧溢出

對象轉 JSON 可能引發棧溢出的異常&#xff0c;一般是因為對象中的循環引用引起不斷遞歸。 常見的作法就是&#xff1a; 換一種 JSON 的序列化工具&#xff0c;比如 fastjson 默認支持消除對同一對象循環引用transient 修飾屬性顯式排除對象的某些屬性1. java對象引用成環說明 …

一些雜七雜八的前端知識1

一、this指向 this是函數運行時自動生成的一個內部對象&#xff0c;只能在函數內部使用 1. 指向全局變量 純粹的函數調用 2. 作為對象方法的調用 對象調用某個函數&#xff0c;這個函數里面所包含的this也就指向使用這個函數的對象了 3. 函數構造新對象時調用 new 4. a…

最新的vue webpack模板沒有dev-server.js文件,進行后臺數據模擬筆記

最新的vue里dev-server.js被替換成了webpack-dev-conf.js 在模擬后臺數據的時候直接在webpack-dev-conf.js文件中修改 第一步&#xff0c;在const portfinder require(‘portfinder’)后添加//第一步 const express require(express) const app express()//請求server var a…

20080331 - What is a PID, How is it useful when troubleshooting a system

PID Process Identifier, 是一個全局唯一的用來標識進程的整數。在多任務系統中&#xff0c;可用來診斷系統中發生錯誤的進程。 轉載于:https://www.cnblogs.com/likun/archive/2008/03/31/1130458.html

記一次el-input使用的坑

記一次el-input使用的坑 el-input使用不同與原生input&#xff0c;所以在vue中改變綁定的數據時需注意 <el-input v-model"form.schedule" input"validateNumber($event)" />要想在input時改變form.schedule的值來改變輸入框顯示的值&#xff0c;以…

使用pm2啟動Node和Vue項目教程

安裝pm2 $ npm install -g pm2 命令行全局安裝pm2 將pm2加入到命令中去?1234ln -s /usr/local/src/node-v8.9.1-linux-x64/bin/pm2 /usr/local/bin/pm2ln -s /usr/local/src/node-v8.9.1-linux-x64/bin/pm2-dev /usr/local/bin/pm2-devln -s /usr/local/src/node-v8.9.1-lin…

對正則的研究

視頻鏈接地址&#xff08;視頻格式可按需增刪&#xff09; /^https?:\/\/.*?(swf|avi|flv|mpg|rm|mov|wav|asf|3gp|mkv|rmvb|mp4)$/i 圖片鏈接地址&#xff08;圖片格式可按需增刪&#xff09; /^https?:\/\/.*?(gif|png|jpg|jpeg|webp|svg|psd|bmp|tif)$/i 24小時制時間&a…

MVVM原理還你

眾所周知當下是MVVM盛行的時代&#xff0c;從早期的Angular到現在的React和Vue&#xff0c;再從最初的三分天下到現在的兩虎相爭。 無疑不給我們的開發帶來了一種前所未有的新體驗&#xff0c;告別了操作DOM的思維&#xff0c;換上了數據驅動頁面的思想&#xff0c;果然時代的進…

poj1316

1&#xff0e;鏈接地址 https://vjudge.net/problem/POJ-1316 2&#xff0e;問題描述 In 1949 the Indian mathematician D.R. Kaprekar discovered a class of numbers called self-numbers. For any positive integer n, define d(n) to be n plus the sum of the digits of …