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.mzph.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 …