Spring提供了xml、注解、JavaConfig多种方式来配置bean,不论何种方式,Spring最终都会将bean封装成BeanDefinition对象,Spring创建bean的依据也是通过BeanDefinition来完成的。
当我们调用getBean()方法获取bean实例时,不管是单例bean还是原型bean,首次调用时容器内都不存在可用的bean实例,这时就不得不去创建bean了,我们分析下Spring创建bean的过程。

Spring Bean的创建过程是非常复杂的,但是整体流程又是清晰的。创建bean的入口函数在AbstractAutowireCapableBeanFactory#createBean(),Spring首先会触发一个扩展点InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(),如果扩展点返回了可用的bean,这里会进行短路操作,Spring将不再去实例化目标bean,这样做的好处是,扩展点可以在这里返回一个代理对象去避免目标bean被实例化。
如果扩展点没有返回可用的bean对象,Spring会自己去实例化bean,实例化bean的方式有三种,取决于BeanDefinition的配置。Bean实例化完了之后,Spring会通过扩展点的方式来收集Bean的注解属性和方法,比如:@Autowired、@Value、init-method等等,信息收集完毕会通过populateBean()方法对bean进行属性填充,其实就是注入依赖。属性填充完毕,紧接着会对bean进行初始化,触发bean实现的各种Aware接口,生命周期方法,以及BeanPostProcessor扩展点。
以上执行完毕后,此时的bean就已经是一个可用的bean了,可以直接返回了。但是,bean可能还会有destroy-method方法,需要在bean销毁时被调用,所以最后还需要把这一类bean暂存到Map容器中,以便销毁时触发。
根据beanName创建bean,首先需要知道bean对应的class。解析class有2种方式,如果mbd存在BeanClass就直接用,否则根据BeanClassName加载class。
/**
* 解析BeanClass
* 1.存在BeanClass
* 2.根据BeanClassName加载Class
*/
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
紧接着准备MethodOverrides,因为Spring支持lookup-method和replace-method功能,针对这两类方法Spring统一保存在MethodOverrides里面,如果bean存在MethodOverrides,则需要创建代理对象来增强。
这里的准备阶段,其实是解析MethodOverride是否存在重载方法,如果不存在重载方法,会将overloaded设为false,增强调用时就不用再根据参数类型去判断该调用哪个重载方法了。
/**
* 准备重写方法,解析是否有重载方法
* 1.lookup-method
* 2.replace-method
* 如果存在MethodOverride,则创建代理对象
*/
try {
mbdToUse.prepareMethodOverrides();
} catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
然后Spring触发扩展点InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(),如果扩展点返回了可用的bean,Spring将不再对目标bean进行实例化。这里你可以返回一个代理对象,然后自己决定什么时候实例化目标bean。
try {
/**
* 触发InstantiationAwareBeanPostProcessor扩展
* 允许它返回代理对象,来避免目标Bean实例化
* @see InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation(java.lang.Class, java.lang.String)
*/
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
/**
* 如果InstantiationAwareBeanPostProcessor返回了代理对象,则不再实例化目标Bean,短路操作
*/
return bean;
}
} catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
resolveBeforeInstantiation()其实就是从容器中取出所有的InstantiationAwareBeanPostProcessor实现类,然后依次调用postProcessBeforeInstantiation()方法。如果扩展点返回了bean对象,紧接着会马上触发postProcessAfterInitialization()方法,跳过目标bean的实例化。
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 应用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation处理器
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
/**
* 如果扩展点返回了可用bean,不再实例化目标bean,紧接着应用after处理器
* 应用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation处理器
*/
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
如果InstantiationAwareBeanPostProcessor扩展点没有返回可用bean,Spring会对目标bean实例化,紧接着调用doCreateBean()方法。
实例化bean的方法是AbstractAutowireCapableBeanFactory#createBeanInstance(),实例化bean的方式有三种:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
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方法声明的bean,则调用工厂方法来生成bean
* 从容器中取出factoryBean,反射调用@Bean方法生成bean
*/
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
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) {
// 构造函数注入
return autowireConstructor(beanName, mbd, null, null);
} else {
// 无参构造函数
return instantiateBean(beanName, mbd);
}
}
// 根据参数解析构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// 无需特殊处理:只需使用无参构造函数。
return instantiateBean(beanName, mbd);
}
通过**createBeanInstance()**方法实例化的bean只是一个不可用的bean对象,因为这个时候bean的属性还没有填充,依赖也没有注入,初始化方法也没有被调用,后置处理器也还没有执行。
紧接着,Spring会对bean做一些信息收集,收集的信息包括@Autowired、@Value、@Resource等注解,init-method、destroy-method方法等,将这些信息封装成Member对象,存放到RootBeanDefinition的externallyManagedConfigMembers属性里。
收集工作是通过扩展点MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition()进行的,Spring内置了多个实现类来收集信息,通过名字基本就能看出来它们要收集哪些信息。
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
/**
* 触发扩展点
* 解析bean的 @Autowired @Value @Resource注解
* init destory-method方法
* 存放到BD的externallyManagedConfigMembers中
* @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Class, java.lang.String)
*/
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
Bean的信息收集完毕,还有一个问题需要解决。Spring是允许Bean之间存在循环依赖的,比如BeanA有一个属性BeanB,BeanB也有一个属性BeanA,两者互相依赖对方。Spring创建BeanA时发现它依赖BeanB,就会去创建BeanB,创建BeanB时又发现它依赖BeanA,此时又会去创建BeanA,循环依赖就此产生。为了打破这个死循环,Spring的解决方案是,不等BeanA完全创建好,就提前暴露到缓存中,这样在创建BeanB时就可以直接依赖这个半成品BeanA了,循环就此打破。
如果允许提前暴露bean,那么Spring还会触发一个扩展点SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference()来获得提前暴露bean的引用,默认是直接原样返回bean。
/**
* 这个时候bean还没初始化,是否要提前暴露Bean?以便循环依赖
* 条件:单例 & 允许循环依赖 & 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,
/**
* 获取提前暴露Bean的引用,默认原样返回bean
* 触发扩展点,AOP在这里将advice织入bean中
* @see SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference(java.lang.Object, java.lang.String)
*/
() -> getEarlyBeanReference(beanName, mbd, bean));
}
bean实例生成了,bean的信息也收集完毕了,接下来就是对bean进行属性填充了,方法是populateBean()。
Spring此时又会触发一个扩展点InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation(),返回值代表是否要继续填充bean,默认返回true。
/**
* 触发扩展点,返回值代表是否要继续填充bean
* @see InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation(java.lang.Object, java.lang.String)
*/
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
如果需要继续填充bean,则通过InstantiationAwareBeanPostProcessor#postProcessProperties()扩展点来完成的bean的填充。执行完这一步,Bean的属性会完成填充,依赖也会被注入。
/**
* 触发扩展点,这里会注入@Autowired、@Resource、@Value等属性
* @see InstantiationAwareBeanPostProcessor#postProcessProperties(org.springframework.beans.PropertyValues, java.lang.Object, java.lang.String) InstantiationAwareBeanPostProcessor#postProcessProperties(org.springframework.beans.PropertyValues, java.lang.Object, java.lang.String)
* @see InstantiationAwareBeanPostProcessor#postProcessPropertyValues(org.springframework.beans.PropertyValues, java.beans.PropertyDescriptor[], java.lang.Object, java.lang.String)
*/
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 对所有需要依赖检查的属性进行后处理
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
属性填充,依赖注入完,接下来就是bean的初始化。
首先会调用invokeAwareMethods()方法来触发Bean实现的各类Aware接口。
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
然后触发扩展点BeanPostProcessor#postProcessBeforeInitialization()。
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
/**
* 触发扩展点
* @see BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
*/
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
如果bean实现了InitializingBean接口,Spring紧接着会触发InitializingBean#afterPropertiesSet()扩展点,再执行init-method。
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
//判断该bean 如果实现了InitializingBean接口,则调用bean的afterPropertiesSet方法
boolean isInitializingBean = (bean instanceof InitializingBean);
// 执行afterPropertiesSet方法
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
} catch (PrivilegedActionException pae) {
throw pae.getException();
}
} else {
((InitializingBean) bean).afterPropertiesSet();
}
}
// 执行initMethod方法
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
//判断是否指定了init-method方法,如果指定了init-method方法,则再调用制定的init-method
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
//调用init-method方法中指定的方法, 是通过反射实现
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
initMethods执行完毕,接着触发BeanPostProcessor#postProcessAfterInitialization()扩展点对bean做最后的扩展。
if (mbd == null || !mbd.isSynthetic()) {
/**
* 触发扩展点
* @see BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
*/
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
到此为止,bean就创建完毕了,是一个完整的可用的bean了。最后一步,是判断bean是否存在destroy-method,如果有还需要把bean注册到Map容器中,以便bean销毁时调用。
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() && requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
} else {
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + mbd.getScope() + "'");
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在
如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法
我正在尝试按0-9和a-z的顺序创建数字和字母列表。我有一组值value_array=['0','1','2','3','4','5','6','7','8','9','a','b','光盘','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','','u','v','w','x','y','z']和一个组合列表的数组,按顺序,这些数字可以产生x个字符,比方说三个list_array=[]和一个当前字母和数字组合的数组(在将它插入列表数组之前我会把它变成一个字符串,]current_combo['0','0','0']
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/