很多人想读Spring的源码都不知道从何看起,我个人的观点,大家知道我们学习一门语言的时候,都是开始于HelloWorld的编写,我觉的Spring的学习也可以开始于最简单的HelloWorld。
直接上代码
首先我们需要一个HelloWorld的实体类:
package org.xiomanixi.spring.analyse.bean;
/**
* @program: spring_analyse
* @description: Spring实现HelloWorld
* @author: xiaomanixi 小码blog
* @create: 2020-05-10 21:35
**/
public class HelloWorld {
private static final String HELLO_WORLD = "Hello World !";
public String getHelloWorld(){
return HELLO_WORLD;
}
}
然后需要配置一个xml文件,用来配置bean:
最后需要一个测试类,我们通过xml来构造bean:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.xiomanixi.spring.analyse.bean.HelloWorld;
/**
* @program: spring_analyse
* @description: Spring实现HW测试类
* @author: xiaomanixi 小码blog
* @create: 2020-05-10 21:42
**/
public class HelloWorldTest {
public static void main(String[] args) {
//读取xml配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("/hello_world.xml");
//读取配置好的Bean
HelloWorld helloWorld = (HelloWorld)context.getBean("helloWorld");
//执行对象方法
System.out.println(helloWorld.getHelloWorld());
}
}
如果你是一个Java小白,会使用Spring就足够了,但是如果你是个Java爱好者,想要提升自己,谋求更好的发展,你就要好好研究一下这段代码了。
根据上面的实例,我们可以提出两个问题:
- ApplicationContext context = new ClassPathXmlApplicationContext("/hello_world.xml") 容器创建的时候做了什么?
- getBean 是如何实现的?
没错,其实就是Spring是如何构造容器并获取到对象的?我们来分析一下Spring的源代码。
首先来看ClassPathXmlApplicationContext的类继承关系,这样我们会有一个宏观的认识:
怎么查看ApplicationContext的构造过程呢,对于复杂的实现,最好的办法就是debug断点调试来看完整的执行路径。
ClassPathXmlApplicationContext构造器源码,断点调试进入AbstractXmlApplicationContext类
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
这个方法的注释是: Create a new ClassPathXmlApplicationContext, loading the definitions from the given XML file and automatically refreshing the context. 创建一个xml上下文路径,加载路径,并自动刷新上下文。
我们通过super不断调用父类的构造器直到AbstractApplicationContext,查看AbstractApplicationContext构造器源码:
/**
* Create a new AbstractApplicationContext with no parent.
*/
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
/**
* Create a new AbstractApplicationContext with the given parent context.
* @param parent the parent context
*/
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
setParent(parent);
}
其中 getResourcePatternResolver的作用是创建一个资源处理器:
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
到目前为止,ClassPathXmlApplicationContext已经有了两个资源加载器(一个由AbstractApplicationContext继承DefaultResourceLoader而来,一个是AbstractApplicationContext主动创建的PathMatchingResourcePatternResolver)
DefaultResourceLoader只能加载一个特定类路径的资源,PathMatchingResourcePatternResolver可以根据Ant风格加载多个资源。
每个父类的构造方法返回后调用AbstractRefreshableConfigApplicationContext的setConfigLocations(configLocations)方法,此方法的目的在于将占位符(placeholder)解析成实际的地址:主要构造方法是setConfigLocations,我们进入这个方法就到达了AbstractRefreshableConfigApplicationContext类:
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
这个方法的主要作用是设置配置文件路径,主要方法是resolvePath(解决路径)。进入resolvePath:
protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}
其中getEnvironment获取环境参数:
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
getEnvironment()方法是由ConfigurableApplicationContext接口定义,在AbstractApplicationContext实现,其实就是判断environment 是否为空,不为空就创建一个StandardEnvironment,可获取的环境参数是系统参数或者是JVM参数,如下:
关于 Environment的作用解释:Environment是什么
顺着代码继续走,可以发现解析占位符的核心方法是parseStringValue,实现如下:
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, @Nullable Set visitedPlaceholders) {
int startIndex = value.indexOf(this.placeholderPrefix);
if (startIndex == -1) {
return value;
}
StringBuilder result = new StringBuilder(value);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
if (visitedPlaceholders == null) {
visitedPlaceholders = new HashSet<>(4);
}
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// Recursive invocation, parsing placeholders contained in the placeholder key.
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// Now obtain the value for the fully resolved key...
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
if (propVal == null && this.valueSeparator != null) {
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
if (propVal != null) {
// Recursive invocation, parsing placeholders contained in the
// previously resolved placeholder value.
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
if (logger.isTraceEnabled()) {
logger.trace("Resolved placeholder '" + placeholder + "'");
}
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
}
else if (this.ignoreUnresolvablePlaceholders) {
// Proceed with unprocessed value.
startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
throw new IllegalArgumentException("Could not resolve placeholder '" +
placeholder + "'" + " in value \"" + value + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return result.toString();
}
Spring bean解析就在refresh方法,Spring所有的初始化都在这个方法中完成,该方法在AbstractApplicationContext实现:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
根据注释得知prepareRefresh主要是准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置。
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
下一步就是创建beanFactory,调用AbstractApplicationContext的obtainFreshBeanFactory方法获取obtainFreshBeanFactory 。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
return getBeanFactory();
}
我们来看refreshBeanFactory在AbstractRefreshableApplicationContext中的具体实现:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) { //如果已经存在的BeanFactory则销毁
destroyBeans();
closeBeanFactory();
}
try {
//1、创建一个DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//2、定制beanFactory,由AbstractRefreshableApplicationContext实现
customizeBeanFactory(beanFactory);
//3、加载bean,由AbstractXmlApplicationContext实现
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
第2步定制bean,customizeBeanFactory方法具体实现:
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
加载bean的loadBeanDefinitions具体实现:
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
看了很多资料,网上一张图我觉的是Spring getBean实现的很好的原理逻辑示意图,给我们展示了一个完整的调用过程:
我们参考上图的调用链,结合代码断点调试,来看getBean的实现,getBean远没有我想象的那么简单。
首先是AbstractApplicationContext中:
@Override
public Object getBean(String name) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name);
}
调用了抽象beanFactory工厂,调用AbstractBeanFactory的getBean:
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
我们来看doGetBean的实现:
protected T doGetBean(final String name, @Nullable final Class requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
//会包括解析别名等操作
final String beanName = transformedBeanName(name);
Object bean;
// 先检查单例列表中是否已经注册了这个bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 检查bean是否并发被创建
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 检查是否在父类工厂中,逻辑和这个差不多,这里省略....
//标记bean正在被创建
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
//合并父类中的方法及属性,下面会细讲
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//检查这个bean是否为抽象类
checkMergedBeanDefinition(mbd, beanName, args);
// 这里是为了保证获取的bean的依赖都需要先生成
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
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 ex;
}
}
}
// 创建单例的bean,看下方的createBean方法
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
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 {
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;
}
}
// 检查需要的类型和实际传参类型是否一致. 这里省略....
return (T) bean;
}
上面的代码什么意思呢?过程是这样的:
其中重要的方法你注意到了吗,getSingleton方法,获取bean单例,实现如下:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
上述流程是:
这里这么设计是为了解决循环依赖的问题。若A依赖B,B依赖C,C又依赖A,这样三个bean就形成了一个环(这里只是针对set方法注入的bean,构造器注入还是会有循环依赖的问题而抛出异常的),spring会将创建的bean实例提前暴露在缓存中,一旦下一个bean创建的时候需要依赖上个bean,则直接使用ObjectFactory来获取bean。
doGetBean还需要注意这段代码:
// 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,是DefaultSingletonBeanRegistry类中实现的:
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);
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);
//定义异常
...
try {
singletonObject = singletonFactory.getObject();
newSingleton = 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) {
//封装异常
...
}
finally {
...
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
不管是singleton还是Prototype还是其他的scope,在从作用域中获取不到bean的情况下,都是调用的createBean。
我们看一下createBean的实现:
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
RootBeanDefinition mbdToUse = mbd;
// 要保证RootBeanDefinition的beanClass是存在的
Class> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 这一块没什么研究,注解意思是(检查所有带有override的方法是否都是存在的)
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
}
try {
//这一块我猜测大概是看咱们自己有提供实例化的方法不,若有,则不会走下面的doCreateBean方法。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
}
try {
//创建bean的真正方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}
return beanInstance;
}
catch (Exception e){
throw e;
}
}
穿件Bean的真正方法是doCreateBean,我们来看他的实现:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 创建这个bean,真正构建时有分两种情况,jdk反射和cglib动态代理
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 允许后置处理器来修改这个BeanDefinition
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
// 用来解决循环依赖问题的,上面已经有过详细解释了。看上面循环依赖模块
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");
}
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
//进行属性的注入,调用bean的set方法进行字段的初始化
populateBean(beanName, mbd, instanceWrapper);
//进行一些初始化方法的调用,比如afterPropertiesSet等等。
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
//在出现循环依赖后,从earlySingletonObjects中获取的bean对象和initializeBean后
//的不一致,证明被后置处理器处理过了,前后bean不一致,需要抛出异常
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
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.");
}
}
}
}
// 注册bean的销毁方法
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
doCreateBean大概有以下步骤:
来看createBeanInstance中调用的instantiateBean的实现:
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction
这里是createBeanInstance方法中最终调用的方法,这里有三个流程:
populateBean源码部分:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
......
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// 这里是根据bean名称进行依赖注入的
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// 这里是根据bean的类型进行依赖注入的
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
......
if (pvs != null) {
//实际上注入属性值的方法,这里是populateBean方法的重点
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
这里注释下applyPropertyValues的部分源码:
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
MutablePropertyValues mpvs = null;
List original;
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
if (mpvs.isConverted()) {
// 这里可以迅速返回。当这个PropertyValues对象中的值都是处理过后便可以触发。状态值会在下面几行代码设置。
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// 这里是个深拷贝,解析所有引用的值。
List deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
//这里的resolveValueIfNecessary是一个需要关注的方法,有兴趣的小伙伴可以点进去看看,
//里面封装了针对各种类型的属性的解析,例如List,Map,Set等等类型。
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
//为了避免每次创建都去转换属性
if (resolvedValue == originalValue) {
//这里的触发条件必须为该属性得是有写权限的,并且里面不能带有“.”和“[”这个符号,这里我的理解是
//teacher.name以及student[1].name这样的propertyName便不能触发这个条件
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
//这一块的条件比上一个多了几个,源值必须是string类型,且不能是动态的,并且不能是集合和数组中的任意一个。
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
//条件在这里触发后就不会打开快捷返回的开关了
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
//设置converted状态值,供其组装属性时快捷返回。
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// 将我们深拷贝出来的值设置到包装类BeanWrapperImpl包装的对象上
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
setPropertyValues方法的源码最终调用的是AbstractNestablePropertyAccessor类的setPropertyValue方法,在这里BeanWrapperImpl是它的实现类,从名字上看也能猜出来这个类是个处理嵌套属性的访问器。
public void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException {
AbstractNestablePropertyAccessor nestedPa;
try {
//这里可以解析嵌套的属性
nestedPa = getPropertyAccessorForPropertyPath(propertyName);
}
catch (NotReadablePropertyException ex) {
throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,
"Nested property in path '" + propertyName + "' does not exist", ex);
}
//这里获取到了最终解析到的属性名
PropertyTokenHolder tokens = getPropertyNameTokens(getFinalPath(nestedPa, propertyName));
//给最终解析到的属性名赋值操作
nestedPa.setPropertyValue(tokens, new PropertyValue(propertyName, value));
}
上面有个getPropertyAccessorForPropertyPath方法,点进去会发现他会有个解析“.”和“[]”的方法getNestedPropertySeparatorIndex,它的作用我举个例子来说明一下:一个班级有多个学生,我想设置某个学生的名字,班级是个Class对象,里面有属性:private Student[] students
这里我想修改下student[2]的name属性,我就必须先用getStudent方法取出 Student[] 数组,然后再在 Student[] 数组中找到索引为2的Student,最后修改Student身上的name属性。
以上就是Spring的getBean的实现。