SpringBoot-Bean创建流程_springboot 创建bean-程序员宅基地

技术标签: spring bean创建流程  Bean初始化  Bean创建流程  # SB2源码学习  initializeBean  springboot  

版本:2.1.7.RELEASE
有一点需要先明确:

Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring在创建好交给使用者之后则不会再管理后续的生命周期。

Bean生命周期

在跟进这部分代码之前,我们首先需要对 Spring 中 bean 的生命周期有个宏观的认识

image.png
详细流程
在这里插入图片描述

finishBeanFactoryInitialization

refresh()中最最重要的一个方法该方法负责初始化所有的单例bean。
到目前为止,应该说是是 BeanFactory 已经创建完成,并且所有的实现了 BeanFactoryPostProcessor 接口的 Bean 都已经初始化并且其中的 postProcessBeanFactory(factory) 方法已经得到回调执行了。而且 Spring 已经“手动”注册了一些特殊的 Bean,如 environment、systemProperties 等。

剩下的就是初始化 singleton beans 了,大多数我们的业务中都是单例bean,就像我们写的@Controller、@Service的类(没有设置懒加载的)都是在这个地方初始化,以供我们使用,如果没有设置懒加载,那么 Spring 会在接下来初始化所有的 singleton beans。


	/**
	 * Finish the initialization of this context's bean factory,
	 * initializing all remaining singleton beans.
	 */
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    
		// Initialize conversion service for this context.
		// 判断beanFactory是否有CONVERSION_SERVICE_BEAN_NAME的实现,如果有的话设置属性。为上下文初始化类型转换器。
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
    
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		// 检查上下文中是否存在类型转换器
		if (!beanFactory.hasEmbeddedValueResolver()) {
    
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
    
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		//标记正在实例化当中,禁止对 bean 的定义再修改。
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		// 进行单例bean的实例化
		beanFactory.preInstantiateSingletons();
	}

preInstantiateSingletons

最重要的就是preInstantiateSingletons这个方法,在DefaultListableBeanFactory中

public void preInstantiateSingletons() throws BeansException {
    
    // this.beanDefinitionNames 保存了所有的 beanNames
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
    // 触发所有的非懒加载的 singleton beans 的初始化操作
    for (String beanName : beanNames) {
    
        // 合并父 beanDefinition 与子 beanDefinition,涉及到 bean 继承的关系,前面提到过:子 bean 继承父 bean 的配置信息
        // 目录中介绍BeanDefinition
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // 非抽象、非懒加载的 singletons。如果配置了 'abstract = true',那是不需要初始化的
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    
            // 处理 FactoryBean(如果不熟悉,附录中有介绍)
            if (isFactoryBean(beanName)) {
    
                // FactoryBean 的话,在 beanName 前面加上 ‘&’ 符号。再调用 getBean
                Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                if (bean instanceof FactoryBean) {
    
                    final FactoryBean<?> factory = (FactoryBean<?>) bean;
                    boolean isEagerInit;
                    // 这里需要判断是不是 SmartFactoryBean,
                    // 因为 SmartFactoryBean 会定义一个 isEagerInit() 方法来决定 getObject() 的实例对象是否懒加载
                    if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
    
                        isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                        ((SmartFactoryBean<?>) factory)::isEagerInit,
                                getAccessControlContext());
                    }
                    else {
    
                        isEagerInit = (factory instanceof SmartFactoryBean &&
                                ((SmartFactoryBean<?>) factory).isEagerInit());
                    }
                    // 对非懒加载的 bean 实例化
                    if (isEagerInit) {
    
                        getBean(beanName);
                    }
                }
            }
           // 对于普通的 Bean,只要调用 getBean(beanName) 这个方法就可以进行初始化了
            else {
    
                getBean(beanName);
            }
        }
    }
     // 到这里说明所有的非懒加载的 singleton beans 已经完成了初始化
     // 如果我们定义的 bean 是实现了 SmartInitializingSingleton 接口的,那么在这里回调它的 afterSingletonsInstantiated 方法
     // 通过名字可以知道它表示单例对象初始化后需要做的操作
    for (String beanName : beanNames) {
    
        Object singletonInstance = getSingleton(beanName);
        if (singletonInstance instanceof SmartInitializingSingleton) {
    
            final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
            if (System.getSecurityManager() != null) {
    
                AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
    
                    smartSingleton.afterSingletonsInstantiated();
                    return null;
                }, getAccessControlContext());
            }
            else {
    
                smartSingleton.afterSingletonsInstantiated();
            }
        }
    }
}

getBean

接下来,我们就进入到 getBean(beanName) 方法了,这个方法我们经常用来从 BeanFactory 中获取一个 Bean,而初始化的过程也封装到了这个方法里。

AbstractBeanFactory

@Override
public Object getBean(String name) throws BeansException {
    
    return doGetBean(name, null, null, false);
}

// getBean 方法是我们经常用来获取 bean 的,但它也同时封装了初始化的过程,已经初始化过了就从容器中直接返回,否则就先初始化再返回
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                          @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    

	//通过三种形式获取beanName
	// 一个是原始的beanName,一个是加了&的,一个是别名
    final String beanName = transformedBeanName(name);
    // 这个是返回值
    Object bean;

    // 尝试从单例缓存集合里获取bean实例
    Object sharedInstance = getSingleton(beanName);
	//如果先前已经创建过单例Bean的实例,并且调用的getBean方法传入的参数为空
	//则执行if里面的逻辑
	//args之所以要求为空是因为如果有args,则需要做进一步赋值,因此无法直接返回 
    if (sharedInstance != null && args == null) {
    
        if (logger.isTraceEnabled()) {
    
            //如果Bean还在创建中,则说明是循环引用
            if (isSingletonCurrentlyInCreation(beanName)) {
    
                logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
    
                logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        // 下面这个方法,如果是普通 Bean 的话,直接返回 sharedInstance,如果是 FactoryBean 的话,返回它创建的那个实例对象。
        // 如果对 FactoryBean 不熟悉,附录中有介绍。
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    } 
    // else 内部是初始化 bean 的逻辑
    else {
    
        // 当前 beanName 的 prototype 类型的 bean 正在被创建则抛异常
        // 往往是因为陷入了循环引用。prototype 类型的 bean 的循环引用是没法被解决的。这跟 Java 里面的一样,会导致栈溢出。
        if (isPrototypeCurrentlyInCreation(beanName)) {
    
            throw new BeanCurrentlyInCreationException(beanName);
        }

        BeanFactory parentBeanFactory = getParentBeanFactory();
        // 从当前容器中找不到指定名称的bean,此时递归去parentFactory查找
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
    
            // 如果当前容器不存在这个 BeanDefinition,试试父容器中有没有
            String nameToLookup = originalBeanName(name);
            //如果parent容器依旧是AbstractBeanFactory的实例
		   //instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例
            if (parentBeanFactory instanceof AbstractBeanFactory) {
    
                // Delegation to parent with explicit args.
                return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                        nameToLookup, requiredType, args, typeCheckOnly);
            }
            else if (args != null) {
    
                // Delegation to parent with explicit args.
                // 如果有参数,则委派父级容器根据指定名称和显式的参数查找
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else if (requiredType != null) {
    
                // No args -> delegate to standard getBean method.
                //委派父级容器根据指定名称和类型查找
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
            else {
    
                //委派父级容器根据指定名称查找
                return (T) parentBeanFactory.getBean(nameToLookup);
            }
        }
        // typeCheckOnly 为 false,将当前 beanName 放入一个 alreadyCreated 的 Set 集合中
        if (!typeCheckOnly) {
    
            markBeanAsCreated(beanName);
        }
       /**
        * 稍稍总结一下:
        * 到这里的话,要准备创建 Bean 了,对于 singleton 的 Bean 来说,容器中还没创建过此 Bean;
        * 对于 prototype 的 Bean 来说,本来就是要创建一个新的 Bean。
        */
        try {
    
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // 先初始化依赖的所有 Bean,注意,这里的依赖指的是 depends-on 中定义的依赖
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
    
                for (String dep : dependsOn) {
    
                    // 检查是不是有循环依赖
                    // 这里的依赖还是 depends-on 中定义的依赖
                    if (isDependent(beanName, dep)) {
    
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                    }
                    // 注册一下依赖关系
                    registerDependentBean(dep, beanName);
                    try {
    
                        // 先初始化被依赖项
                        getBean(dep);
                    }
                    catch (NoSuchBeanDefinitionException ex) {
    
                        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                    }
                }
            }

            // 如果是 singleton scope 的,创建 singleton 的实例
            if (mbd.isSingleton()) {
    
                 // 这里并没有直接调用 createBean 方法创建 bean 实例,而是通过 getSingleton(String, ObjectFactory) 方法获取 bean 实例。  
                 // getSingleton(String, ObjectFactory) 方法会在内部调用 ObjectFactory 的 getObject() 方法创建 bean,并会在创建完成后,
                 // 将 bean 放入缓存中。
                sharedInstance = getSingleton(beanName, () -> {
    
                    try {
    
                        // 执行创建 Bean,详情后面再说
                        return createBean(beanName, mbd, args);
                    }
                    catch (BeansException ex) {
    
                        destroySingleton(beanName);
                        throw ex;
                    }
                });
                // 跟上面的一样,如果是普通 Bean 的话,直接返回 sharedInstance,如果是 FactoryBean 的话,返回它创建的那个实例对象。
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            // 如果是 prototype scope 的,创建 prototype 的实例
            else if (mbd.isPrototype()) {
    
                // prototype 对象每次获取都会创建新的实例
                Object prototypeInstance = null;
                try {
    
                    beforePrototypeCreation(beanName);
                    // 执行创建 Bean
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
    
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            // 如果不是 singleton 和 prototype 的话,需要委托给相应的实现类来处理
            else {
    
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
    
                    throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
                }
                try {
    
                    Object scopedInstance = scope.get(beanName, () -> {
    
                        beforePrototypeCreation(beanName);
                        try {
    
                            // 执行创建 Bean
                            return createBean(beanName, mbd, args);
                        }
                        finally {
    
                            afterPrototypeCreation(beanName);
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
    
                    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",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
    
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // 最后,检查一下类型对不对,不对的话就抛异常,对的话就返回了
    if (requiredType != null && !requiredType.isInstance(bean)) {
    
        try {
    
            T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
    
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return convertedBean;
        }
        catch (TypeMismatchException ex) {
    
            if (logger.isTraceEnabled()) {
    
                logger.trace("Failed to convert bean '" + name + "' to required type '" +
                        ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

singleton 和 prototype 对象的区别在于是否通过 getSingleton 这个方法调用,我们来看看 getSingleton 方法是如何运作的

getSingleton

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
    
        // 从 singletonObjects 获取实例,singletonObjects 中缓存的实例都是完全实例化好的 bean,可以直接使用
        Object singletonObject = this.singletonObjects.get(beanName);
        // 如果 singletonObject = null,表明还没创建,或者还没完全创建好。
        if (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);
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
    
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
    
                // 调用 singletonFactory 的 getObject 方法,就是传入的匿名类,最终也是调用 createBean
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            }
            catch (IllegalStateException ex) {
    
                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);
            }
            if (newSingleton) {
    
                // 将创建好的 bean 存入缓存
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}

我们可以看到 getSingleton 内部也是调用 createBean 方法。singletonFactory.getObject();就是调用createBean方法

createBean

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
        throws BeanCreationException {
    

    if (logger.isTraceEnabled()) {
    
        logger.trace("Creating instance of bean '" + beanName + "'");
    }
    RootBeanDefinition mbdToUse = mbd;

    //判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载
    Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    
        //克隆一份BeanDefinition,用来设置上加载出来的class对象
        //之所以后续用该副本操作,是因为不希望将解析的class绑定到缓存里的BeanDefinition
	    //因为class有可能是每次都需要动态解析出来的
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    // 涉及到一个概念:方法覆写。具体涉及到 lookup-method 和 replace-method最后介绍
    try {
    
        mbdToUse.prepareMethodOverrides();
    }
    catch (BeanDefinitionValidationException ex) {
    
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                beanName, "Validation of method overrides failed", ex);
    }

    try {
    
		//如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建Bean的代理对象
		//resolveBeforeInstantiation只是针对有自定义的targetsource,
		// 因为自定义的targetsource不是spring的bean那么肯定不需要进行后续的一系列的实例化,初始化。
		// 所以可以在resolveBeforeInstantiation直接进行proxy
        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 {
    
        // 重头戏,创建 bean
        Object beanInstance = doCreateBean(beanName, mbdToUse, args);
        if (logger.isTraceEnabled()) {
    
            logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        return beanInstance;
    }
    catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
    
        throw ex;
    }
    catch (Throwable ex) {
    
        throw new BeanCreationException(
                mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
    }
}
resolveBeforeInstantiation
	@Nullable
	protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    
		Object bean = null;

		// 如果还没被解析
		if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
    
			// Make sure bean class is actually resolved at this point.
			if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    
				
				// 确定bean的的类型(class类)
				Class<?> targetType = determineTargetType(beanName, mbd);
				if (targetType != null) {
    
				
					// 执行后置处理器在初始化前
					bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
					if (bean != null) {
    
						// 执行后置处理器在初始化后
						bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
					}
				}
			}
			mbd.beforeInstantiationResolved = (bean != null);
		}
		return bean;
	}

applyBeanPostProcessorsAfterInitialization这个是与aop有关的这里不展开说了

createBean 并不是真正初始化 bean 的方法,而是对 doCreateBean 的预处理。它主要做了两件事情:确保 BeanDefinition 中的 Class 被加载和标记方法覆写。真正创建 bean 对象的逻辑在 doCreateBean 方法里面。

doCreateBean

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
        throws BeanCreationException {
     
     
    // BeanWrapper 是一个基础接口,由接口名可看出这个接口的实现类用于包裹 bean 实例。
    // 通过 BeanWrapper 的实现类可以方便的设置/获取 bean 实例的属性
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
    
        //从未完成创建的包装Bean缓存中清理并获取相关中的包装Bean实例,毕竟是单例的,只能存一份
        instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
    }
    if (instanceWrapper == null) {
    
        //创建bean的时候,这里创建bean的实例有三种方法
	    //1.工厂方法创建
		//2.构造方法的方式注入
		//3.无参构造方法注入
        instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    // 此处的 bean 可以认为是一个原始的 bean 实例,暂未填充属性
    final Object bean = instanceWrapper.getWrappedInstance();
    Class<?> beanType = instanceWrapper.getWrappedClass();
    if (beanType != NullBean.class) {
    
        mbd.resolvedTargetType = beanType;
    }

    // 涉及接口:MergedBeanDefinitionPostProcessor,用于处理已“合并的 BeanDefinition”,这块细节就不展开了
    synchronized (mbd.postProcessingLock) {
    
        if (!mbd.postProcessed) {
    
            try {
    
                //被@Autowired、@Value标记的属性在这里获取
                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
            }
            catch (Throwable ex) {
    
                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Post-processing of merged bean definition failed", ex);
            }
            mbd.postProcessed = true;
        }
    }

    // earlySingletonExposure 是一个重要的变量,用于解决循环依赖,该变量表示是否提前暴露,
    //向容器中缓存单例模式的Bean对象,以防循环引用
	//判断是否是早期引用的bean,如果是,则允许其提前暴露引用
	//这里判断的逻辑主要有三个:
	//1.是否为单例
	//2.是否允许循环引用
	//3.是否是在创建中的bean
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
            isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
    
        if (logger.isTraceEnabled()) {
    
            logger.trace("Eagerly caching bean '" + beanName +
                    "' to allow for resolving potential circular references");
        }
        // 添加工厂对象到 singletonFactories 缓存中
        addSingletonFactory(beanName, new ObjectFactory<Object>() {
    
            @Override
            public Object getObject() throws BeansException {
    
                // 获取早期 bean 的引用,如果 bean 中的方法被 AOP 切点所匹配到,此时 AOP 相关逻辑会介入
                return getEarlyBeanReference(beanName, mbd, bean);
            }
        });
    }
	//Bean对象的初始化,依赖注入在此触发
	//这个exposedObject在初始化完成之后返回作为依赖注入完成后的Bean
    Object exposedObject = bean;
    try {
    
        // 这一步也是非常关键的,这一步负责属性装配,因为前面的实例只是实例化了,并没有设值,这里就是设值
        populateBean(beanName, mbd, instanceWrapper);
		//初始化bean,过程如下:
		//1:判断是否实现了BeanNameAware,BeanClassLoaderAware,
		//   BeanFactoryAware方法,如果有,则设置相关的属性
		//2: 调用bean初始化的前置(BeanPostProcessor)操作
		//3: 执行初始化的方法。
		//	如果有initializingBean,则调用afterPropertiesSet
		//	如果有InitMethod,则调用初始方法
		//4: 调用bean初始化的后置(BeanPostProcessor)操作
        exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    catch (Throwable ex) {
    
        if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
    
            throw (BeanCreationException) ex;
        }
        else {
    
            throw new BeanCreationException(
                    mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
        }
    }
    //若允许循环依赖,则解决相关的循环依赖
    if (earlySingletonExposure) {
    
        //获取指定名称的已注册的单例模式Bean对象
        Object earlySingletonReference = getSingleton(beanName, false);
        if (earlySingletonReference != null) {
    
            //如果经过initializeBean执行后返回的bean还是同一个(不是代理对象实例,即没有被增强)
            if (exposedObject == bean) {
    
                // 确保根据名称获取到的的已注册的Bean和正在实例化的Bean是同一个
                exposedObject = earlySingletonReference;
            }
           //如果上面的if没通过,则表明引用的bean和注入的bean不一致,则需要看看依赖于此Bean的先前是否已经注入了不完善的Bean
		  // allowRawInjectionDespiteWrapping 标注是否允许此Bean的原始类型被注入到其它Bean里面,
		  // 即使自己最终会被包装(代理)
		  // dependentBeanMap记录着每个依赖于此Bean的Bean实例集合
		  //当发生循环引用时不允许新创建实例对象
            else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
    
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
                //获取依赖于当前Bean的Bean实例
                for (String dependentBean : dependentBeans) {
    
                    //移除掉只是用来进行类型检查的单例Bean
                    if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
    
                        actualDependentBeans.add(dependentBean);
                    }
                }
               /**
			   * 因为bean创建后其所依赖的bean一定是已经创建的
			   * actualDependentBeans不为空则表示当前bean创建后其依赖的bean却没有全部创建完,也就是说存在循环依赖
			   */
                if (!actualDependentBeans.isEmpty()) {
    
                    throw new BeanCurrentlyInCreationException(beanName,
                            "Bean with name '" + beanName + "' has been injected into other beans [" +
                                    StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                    "] in its raw version as part of a circular reference, but has eventually been " +
                                    "wrapped. This means that said other beans do not use the final version of the " +
                                    "bean. This is often the result of over-eager type matching - consider using " +
                                    "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
            }
        }
    }

    // 注册销毁逻辑
    try {
    
        registerDisposableBeanIfNecessary(beanName, bean, mbd);
    }
    catch (BeanDefinitionValidationException ex) {
    
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
    }

    return exposedObject;
}

我们看到 doCreateBean 内部的逻辑非常多,我们先来总结一下 doCreateBean 方法的执行流程吧,如下:

  • 从缓存中获取 BeanWrapper 实现类对象,并清理相关记录
  • 若未命中缓存,则创建 bean 实例,并将实例包裹在 BeanWrapper 实现类对象中返回
  • 应用 MergedBeanDefinitionPostProcessor 后置处理器相关逻辑
  • 根据条件决定是否提前暴露 bean 的早期引用(early reference),用于处理循环依赖问题
  • 调用 populateBean 方法向 bean 实例中填充属性
  • 调用 initializeBean 方法完成余下的初始化工作
  • 注册销毁逻辑

接下来我们挑 doCreateBean 中的三个细节出来说说。一个是创建 Bean 实例的 createBeanInstance 方法,一个是依赖注入的 populateBean 方法,还有就是回调方法 initializeBean。

createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    
    // 确保已经加载了此 class
    Class<?> beanClass = resolveBeanClass(mbd, beanName);
    
    // 校验一下这个类的访问权限
    if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
    
        throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
    }

    Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
    if (instanceSupplier != null) {
    
        return obtainFromSupplier(instanceSupplier, beanName);
    }

    // 如果工厂方法不为空,则通过工厂方法构建 bean 对象。工厂方式可以见附录
    if (mbd.getFactoryMethodName() != null) {
    
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // 如果不是第一次创建,比如第二次创建 prototype bean。这种情况下,我们可以从第一次创建知道,
    // 采用无参构造函数,还是构造函数依赖注入来完成实例化。
    // 这里的 resolved 和 mbd.constructorArgumentsResolved 将会在 bean 第一次实例化的过程中被设置,在后面的源码中会分析到,先继续往下看。
    boolean resolved = false;
    boolean autowireNecessary = false;
    if (args == null) {
    
        synchronized (mbd.constructorArgumentLock) {
    
            if (mbd.resolvedConstructorOrFactoryMethod != null) {
    
                resolved = true;
                autowireNecessary = mbd.constructorArgumentsResolved;
            }
        }
    }
    if (resolved) {
    
        if (autowireNecessary) {
    
            // 通过有参构造器构造 bean 对象
            return autowireConstructor(beanName, mbd, null, null);
        }
        else {
    
            // 通过无参构造器构造 bean 对象
            return instantiateBean(beanName, mbd);
        }
    }

    // 判断是否采用有参构造函数
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
    if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
            mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
    
        // 通过有参构造器构造 bean 对象
        return autowireConstructor(beanName, mbd, ctors, args);
    }

    // 通过无参构造器构造 bean 对象
    return instantiateBean(beanName, mbd);
}
  • 检测类的访问权限,若禁止访问,则抛出异常
  • 若工厂方法不为空,则通过工厂方法构建 bean 对象,并返回结果
  • 若构造方式已解析过,则走快捷路径构建 bean 对象,并返回结果
  • 如第三步不满足,则通过组合条件决定使用哪种方式构建 bean 对象
autowireConstructor(有参构造器构造 bean 对象)

该方法的核心逻辑是根据参数值类型筛选合适的构造方法。解析出合适的构造方法后,剩下的工作就是构建 bean 对象了,这个工作交给了实例化策略去做。

instantiateBean(无参构造器构造 bean 对象)

调用实例化策略创建实例,默认情况下使用反射创建对象。如果 bean 的配置信息中 包含 lookup-method 和 replace-method,则通过 CGLIB 创建 bean 对象

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    
    try {
    
        Object beanInstance;
        final BeanFactory parent = this;
        // if 条件分支里的一大坨是 Java 安全相关的代码,可以忽略,直接看 else 分支
        if (System.getSecurityManager() != null) {
    
            beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
    
                @Override
                public Object run() {
    
                    return getInstantiationStrategy().instantiate(mbd, beanName, parent);
                }
            }, getAccessControlContext());
        }
        else {
    
            /**
             * 调用实例化策略创建实例,默认情况下使用反射创建对象。如果 bean 的配置信息中
             * 包含 lookup-method 和 replace-method,则通过 CGLIB 创建 bean 对象
             */
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
        }
        // 创建 BeanWrapperImpl 对象
        BeanWrapper bw = new BeanWrapperImpl(beanInstance);
        initBeanWrapper(bw);
        return bw;
    }
    catch (Throwable ex) {
    
        throw new BeanCreationException(
                mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
    }
}
populateBean(为bean填充属性)

AbstractAutowireCapableBeanFactory

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
    
   // bean 实例的所有属性都在这里了
   PropertyValues pvs = mbd.getPropertyValues();

   if (bw == null) {
    
      if (!pvs.isEmpty()) {
    
         throw new BeanCreationException(
               mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
      }
      else {
    
         return;
      }
   }

   // 到这步的时候,bean 实例化完成(通过工厂方法或构造方法),但是还没开始属性设值,
   // InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态设置,比如忽略属性值的设置
   boolean continueWithPropertyPopulation = true;
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
    
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
    
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            // 如果返回 false,代表不需要进行后续的属性设值,也不需要再经过其他的 BeanPostProcessor 的处理
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }

   if (!continueWithPropertyPopulation) {
    
      return;
   }

   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
    
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

      // 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
    
         autowireByName(beanName, mbd, bw, newPvs);
      }

      // 通过类型装配。复杂一些
      if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
    
         autowireByType(beanName, mbd, bw, newPvs);
      }

      pvs = newPvs;
   }

   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

   if (hasInstAwareBpps || needsDepCheck) {
    
      PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      if (hasInstAwareBpps) {
    
         for (BeanPostProcessor bp : getBeanPostProcessors()) {
    
            if (bp instanceof InstantiationAwareBeanPostProcessor) {
    
               InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
               // 这里有个非常有用的 BeanPostProcessor 进到这里: AutowiredAnnotationBeanPostProcessor
               // 对采用 @Autowired、@Value 注解的依赖进行设值
               pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvs == null) {
    
                  return;
               }
            }
         }
      }
      if (needsDepCheck) {
    
         checkDependencies(beanName, mbd, filteredPds, pvs);
      }
   }
   // 设置 bean 实例的属性值
   applyPropertyValues(beanName, mbd, bw, pvs);
}
initializeBean(处理回调)

属性注入完成后,这一步其实就是处理各种回调了。

AbstractAutowireCapableBeanFactory

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
    
   if (System.getSecurityManager() != null) {
    
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
    
         @Override
         public Object run() {
    
            invokeAwareMethods(beanName, bean);
            return null;
         }
      }, getAccessControlContext());
   }
   else {
    
      // 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
    
      // BeanPostProcessor 的 postProcessBeforeInitialization 回调
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
    
      // 处理 bean 中定义的 init-method,
      // 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
    
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }

   if (mbd == null || !mbd.isSynthetic()) {
    
      // BeanPostProcessor 的 postProcessAfterInitialization 回调
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

BeanPostProcessor 的两个回调方法都发生在这边,在spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑。这里说的初始化方法,指的是下面两种:

  • 1)bean实现了InitializingBean接口,对应的方法为afterPropertiesSet
  • 2)在bean定义的时候,通过init-method设置的方法

创建对象这个过程是比较重要的,它一共有三步:实例化对象——属性注入——处理回调。Spring 实例化对象分为工厂方式和构造器方式,构造器方式有分为有参构造器和无参构造器。有参构造器会根据传入的参数自动选择合适的构造器实例化对象。实例化之后 Spring 又会为对象注入属性。这里又分为配置文件的方式和注解的方式,注解方式有一系列规则选择最合适的实例注入。最后 Spring 调用 BeanPostProcessor 的前置回调和后置回调,我们发现这两个回调是在同一个方法中实现的,只不过中间处理了 init-method 方法。然后 Spring 会把对象放入缓存中,以后可以直接取出。

方法覆写

lookup-method

我们通过 BeanFactory getBean 方法获取 bean 实例时,对于 singleton 类型的 bean,BeanFactory 每次返回的都是同一个 bean。对于 prototype 类型的 bean,BeanFactory 则会返回一个新的 bean。现在考虑这样一种情况,一个 singleton 类型的 bean 中有一个 prototype 类型的成员变量。BeanFactory 在实例化 singleton 类型的 bean 时,会向其注入一个 prototype 类型的实例。但是 singleton 类型的 bean 只会实例化一次,那么它内部的 prototype 类型的成员变量也就不会再被改变。但如果我们每次从 singleton bean 中获取这个 prototype 成员变量时,都想获取一个新的对象。这个时候怎么办?

@Component
public class NewsProvider {
    
    @Autowired
    News news; // prototype bean

    public News getNews() {
    
        return news;
    }
}

这种情况下每次调用 getNews
获得的都是同一个对象。我们可以使用@Lookup 解决这个问题:

@Component
public class NewsProvider {
    
    @Autowired
    News news; // prototype bean

    @Lookup
    public News getNews() {
    
        return news;
    }
}

标注了@Lookup 后 Spring 会采用 CGLIB 生成字节码的方式来生成一个子类,这个子类的 getNews 方法每次返回的都是一个新的 News 对象。

replaced-method

replaced-method 的作用是替换掉 bean 中的一些方法,同样是基于 CGLIB 实现的。首先定义一个 bean:

public class Car {
    

    public void run() {
    
        System.out.print("run...");
    }
}

然后定义一个方法覆写类,需要继承 MethodReplacer 接口:

public class CarReplacer implements MethodReplacer {
    
    @Override
    public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
    
        System.out.print("replacer...");
        return null;
    }
}

配置文件

<bean id="car" class="com.huzb.demo.Car" >
    <replaced-method name="run" replacer="carReplacer"/>
</bean>
<bean id="carReplacer" class="com.huzb.demo.CarReplacer" />

这样调用 Car 的实例的 run 方法的时候会打印“replacer…”而不是“run…”。

BeanDefinition

beanDefinition 对象顾名思义保存的就是 bean 的定义信息。它用 Java 类的方式保存了我们在 xml 或者注解中对 bean 对象的配置。然后 Spring 就根据它里面保存的信息初始化 bean 对象。BeanDefinition 的接口定义如下:

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    
   // 我们可以看到,默认只提供 sington 和 prototype 两种,
   // 大家可能知道还有 request, session, globalSession, application, websocket 这几种,
   // 不过,它们属于基于 web 的扩展。
   String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
   String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

   // 比较不重要,直接跳过吧
   int ROLE_APPLICATION = 0;
   int ROLE_SUPPORT = 1;
   int ROLE_INFRASTRUCTURE = 2;

   // 设置父 bean,这里涉及到 bean 继承,不是 java 继承。一句话就是:继承父 bean 的配置信息
   void setParentName(String parentName);
   String getParentName();

   // 设置 bean 的类名称,将来是要通过反射来生成实例的
   void setBeanClassName(String beanClassName);
   String getBeanClassName();

   // 设置 bean 的 scope
   void setScope(String scope);
   String getScope();

   // 设置是否懒加载
   void setLazyInit(boolean lazyInit);
   boolean isLazyInit();

   // 设置该 bean 依赖的所有的 bean,注意,这里的依赖不是指属性依赖(如 @Autowire 标记的),
   // 是 depends-on="" 属性设置的值。一句话就是:不直接依赖于其它 bean 但希望其它 bean 先初始化
   void setDependsOn(String... dependsOn);
   String[] getDependsOn();

   // 设置该 bean 是否可以注入到其他 bean 中,只对根据类型注入有效,
   // 如果根据名称注入,即使这边设置了 false,也是可以的
   void setAutowireCandidate(boolean autowireCandidate);
   boolean isAutowireCandidate();

   // 设置是否 primary。同一接口的如果有多个实现,如果不指定名字的话,Spring 会优先选择设置 primary 为 true 的 bean
   void setPrimary(boolean primary);
   boolean isPrimary();

   // 如果该 Bean 采用工厂方法生成,指定工厂名称。
   // 一句话就是:有些实例不是用反射生成的,而是用工厂模式生成的
   void setFactoryBeanName(String factoryBeanName);
   // 获取工厂名称
   String getFactoryBeanName();
   // 指定工厂类中的 工厂方法名称
   void setFactoryMethodName(String factoryMethodName);
   // 获取工厂类中的 工厂方法名称
   String getFactoryMethodName();

   // 构造器参数
   ConstructorArgumentValues getConstructorArgumentValues();

   // Bean 中的属性值,后面给 bean 注入属性值的时候会说到
   MutablePropertyValues getPropertyValues();

   // 是否 singleton
   boolean isSingleton();

   // 是否 prototype
   boolean isPrototype();

   // 如果这个 Bean 是被设置为 abstract,那么不能实例化,
   // 常用于作为父 bean 用于继承,其实也很少用......
   boolean isAbstract();

   int getRole();
   String getDescription();
   String getResourceDescription();
   BeanDefinition getOriginatingBeanDefinition();
}

FactoryBean

一般情况下,Spring通过反射机制利用bean的class属性指定实现类来实例化bean 。在某些情况下,实例化bean过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。Spring为此提供了一个org.Springframework.bean.factory.FactoryBean的工厂类接口,用户可以通过实现该接口定制实例化bean的逻辑。

https://segmentfault.com/a/1190000014497968

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/BushQiang/article/details/123645370

智能推荐

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

深度神经网络在训练初期的“梯度消失”或“梯度爆炸”的问题解决:数据标准化(Data Standardization),权重初始化(Weight Initialization),Dropout正则化等_在人工神经网络研究的初始阶段,辛顿针对训练过程中常出现的梯度消失现象, 提供相-程序员宅基地

文章浏览阅读101次。1986年,深度学习(Deep Learning)火爆,它提出了一个名为“深层神经网络”(Deep Neural Networks)的新型机器学习模型。随后几年,神经网络在图像、文本等领域取得了惊艳成果。但是,随着深度学习的应用范围越来越广泛,神经网络在遇到新的任务时出现性能下降或退化的问题。这主要是由于深度神经网络在训练初期面临着“梯度消失”或“梯度爆炸”的问题。_在人工神经网络研究的初始阶段,辛顿针对训练过程中常出现的梯度消失现象, 提供相

kill进程的几种方式_如何kill掉一个进程-程序员宅基地

文章浏览阅读461次。我们会先使用 ps、top 等命令获得进程的 PID,然后使用 kill 命令来杀掉该进程。killall和pkill是相似的,不过如果给出的进程名不完整,killall会报错。当然我们可以向进程发送一个终止运行的信号,此时的 kill 命令才是名至实归。,这样结束掉的进程不会进行资源的清理工作,所以如果你用它来终结掉 vim 的进程,就会发现临时文件 *.swp 没有被删除。命令:pid of xx进程,显示进程的进程号,同上pgrep。这是 kill 命令最主要的用法,也是本文要介绍的内容。_如何kill掉一个进程

随便推点

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

vscode打开markdown文件 不显示图片 预览markdown文件_vscodemarkdown图片无法显示-程序员宅基地

文章浏览阅读3.2k次,点赞3次,收藏4次。vscode打开markdown文件 不显示图片 预览markdown文件_vscodemarkdown图片无法显示

C++的64位扩展_c++ long64-程序员宅基地

文章浏览阅读516次。在做ACM题时,经常都会遇到一些比较大的整数。而常用的内置整数类型常常显得太小了:其中long 和 int 范围是[-2^31,2^31),即-2147483648~2147483647。而unsigned范围是[0,2^32),即0~4294967295。也就是说,常规的32位整数只能够处理40亿以下的数。  那遇到比40亿要大的数怎么办呢?这时就要用到C++的64位扩展了。不同的编译器对6_c++ long64

推荐文章

热门文章

相关标签