Spring IoC设计与实现
IoC容器设计
类设计如下所示:
- BeanFactory:最顶层接口,提供IoC容器最基本的功能。
- HierarchicalBeanFactory:在BeanFactory基础上提供了获取父类工厂方法。
- ConfigurableListableBeanFactory:提供了更多bean的管理功能,包括bean注册删除等
- ApplicationContext:面向用户使用的工厂类,提供了更多的附加功能,如支持不同的信息源、访问资源、支持应用事件等、
IoC容器的初始化过程
初始化过程包括BeanDefinition的Resource定位、加载和注入三个过程,以ClassPathXmlApplicationContext为例分析初始化过程。代码如下:
1.设置xml
<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myBean" class="io.github.xw.model.MyBean">
<!-- 可以设置 bean 的属性 -->
<property name="message" value="Hello, Spring!"/>
</bean>
</beans>
2.声明bean
public class MyBean {
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void printMessage() {
System.out.println(message);
}
}
3.测试
public class ClassPathXmlApplicationContextMain {
public static void main(String[] args) {
// 创建 ClassPathXmlApplicationContext 上下文
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取 "myBean" 实例
MyBean myBean = context.getBean("myBean", MyBean.class);
// 使用 "myBean"
myBean.printMessage();
// 关闭上下文
((ClassPathXmlApplicationContext) context).close();
}
}
resource定位过程
查看构造器逻辑,首先设置了configLocations,然后调用refresh方法,具体查看refresh方法逻辑。
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
关键方法实现:AbstractXmlApplicationContext#loadBeanDefinitions,该方法具体调用是在refresh方法里面,后面具体再分析。
//获取资源并定位加载
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
通过getConfigResources和getConfigLocations获取到资源后,接下来就是对资源的解析,将xml声明的数据转换成Spring的标准对象BeanDefinition,并进行载入。
BeanDefinition的加载和解析
该过程由BeanDefinitionReader实现,具体类关系图如下:
对于ClassPathXmlApplicationContext对应的是XmlBeanDefinitionReader,关键方法如下:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
....
//通过流读取xml文件
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
...
}
继续查看doLoadBeanDefinitions方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//将xml配置转换成doc对象
Document doc = doLoadDocument(inputSource, resource);
//这里启动的是对BeanDefinition解析的详细过程,这个解析会使用到Spring的Bean
//配置规则,是我们下面需要详细讲解的内容
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
查看registerBeanDefinitions方法:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//得到BeanDefinitionDocumentReader来对XML的BeanDefinition进行解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//具体解析过程在这里完成,解析成BeanDefinition对象中并设置到BeanDefinitionHolder中去
//具体流程不再分析
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
通过上述流程将xml内容解析成BeanDefinition对象,完成解析工作。
BeanDefinition注册
Bean注册逻辑在DefaultListableBeanFactory#registerBeanDefinition,实现BeanDefinitionRegistry接口
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
//判断同名beanName定义是否已经存在
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
//如果存在,不允许同名的话抛出异常
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
.....
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//判断是否已经开始创建
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
//
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// 把Bean的名字存入到beanDefinitionNames的同时,把beanName作为Map的key,把peanDefinition
//作为value存入到Ioc容器持有的beanDefinitionMap中去
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
else if (isConfigurationFrozen()) {
clearByTypeCache();
}
}
完成了BeanDefinition的注册,就完成了IoC容器的初始化过程。此时,在使用的IoC容器DefaultListableBeanFactory中已经建立了整个Bean的配置信息,而且这些BeanDefinition已经可以被容器使用了,它们都在beanDefinitionMap.里被检索和使用。容器的作用就是对这些言息进行处理和维护。这些信息是容器建立依赖反转的基础。
实现一个自定义的ApplicationContext
从json文件读取简单的配置,并进行加载解析。核心代码如下:
实现一个json格式Reader读取器进行加载解析:
package io.github.xw.ioc;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.xml.sax.InputSource;
import java.io.IOException;
import java.io.InputStream;
/**
* @author xw
*/
public class JsonBeanDefinitionReader extends AbstractBeanDefinitionReader {
/**
* Create a new AbstractBeanDefinitionReader for the given bean factory.
* <p>
* If the passed-in bean factory does not only implement the BeanDefinitionRegistry interface but also the
* ResourceLoader interface, it will be used as default ResourceLoader as well. This will usually be the case for
* {@link ApplicationContext} implementations.
* <p>
* If given a plain BeanDefinitionRegistry, the default ResourceLoader will be a
* {@link PathMatchingResourcePatternResolver}.
* <p>
* If the passed-in bean factory also implements {@link EnvironmentCapable} its environment will be used by this
* reader. Otherwise, the reader will initialize and use a {@link StandardEnvironment}. All ApplicationContext
* implementations are EnvironmentCapable, while normal BeanFactory implementations are not.
*
* @param registry
* the BeanFactory to load bean definitions into, in the form of a BeanDefinitionRegistry
* @see #setResourceLoader
* @see #setEnvironment
*/
protected JsonBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
try (InputStream inputStream = resource.getInputStream()) {
//从json文件读取
byte[] bytes = inputStream.readAllBytes();
String content = new String(bytes);
JsonObjectDefine jsonObjectDefine = JSON.parseObject(content, JsonObjectDefine.class);
//转换成beandefinition
AbstractBeanDefinition bd = new GenericBeanDefinition();
bd.setResource(resource);
bd.setDescription("");
bd.setBeanClassName(jsonObjectDefine.getClassName());
jsonObjectDefine.getProperties().forEach((k, v) -> {
PropertyValue pv = new PropertyValue(k, v);
bd.getPropertyValues().addPropertyValue(pv);
});
//进行注册
BeanDefinitionHolder beanDefinitionHolder =
new BeanDefinitionHolder(bd, jsonObjectDefine.getId(), null);
BeanDefinitionReaderUtils.registerBeanDefinition(beanDefinitionHolder, getRegistry());
return 1;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
声明context:
package io.github.xw.ioc;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.ResourceEntityResolver;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.support.AbstractRefreshableConfigApplicationContext;
import org.springframework.core.io.Resource;
import java.io.IOException;
/**
* @author xw
* @date 2023/10/10
*/
public class JsonApplicationContext extends AbstractRefreshableConfigApplicationContext {
public JsonApplicationContext(String path) {
this.setConfigLocations(path);
refresh();
}
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
JsonBeanDefinitionReader beanDefinitionReader = new JsonBeanDefinitionReader(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));
//进行加载
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(JsonBeanDefinitionReader reader) throws BeansException, IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
}
测试结果如下:
IoC容器的依赖注入
bean的依赖注入核心代码在AbstractBeanFactory#doGetBean中
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
//先从缓存中取得Bean,处理那些已经被创建过的单件模式的Bean,对这种Bean的请求不需要
//重复地创建
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
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 + "'");
}
}
// 这里的getobjectForBeanInstance完成的是FactoryBean的相关处理,以取得FactoryBean的生产结果,BeanFactory和FactoryBean的区别已经在前面讲过,这个过程在后
// 面还会详细地分析
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
/*这里对Ioc容器中的BeanDefintion是否存在进行检查,检查是否能在当前的BeanFactory中取
得需要的Bean。如果在当前的工厂中取不到,则到双亲BeanFactory中去取,如果当前的双亲工
厂取不到,那就顺着双亲BeanFactory链一直向上查找*/
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
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);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
//根据bean的名字获取BeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
//获取当前Bean的所有依赖Bean,这样会触发getBean的递归调用,直到取到一个没有
//任何依赖的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 new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
/*这里通过调用createBean方法创建singleton bean的实例,这里有一个回调函数
getobject,会在getsingleton中调用objectFactory的createBean*/
// 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;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//创建prototype bean的地方
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);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
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);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
插件具体的实现方法AbstractAutowireCapableBeanFactory#doCreateBean,调用链路如下图所示
代码如下:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
//如果是单例bean,先把缓存中的同名bean清除
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
....
// Initialize the bean instance.
//对bean进行初始化,在这里进行依赖注入。
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
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) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> 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 " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
在这里有createBeanInstance与populateBean两个方法与依赖注入关系比较密切。
createBeanInstance方法主要完成bean的实例化。代码如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
//确保需要创建的Bean实例的类可以实例化
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);
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same 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) {
return autowireConstructor(beanName, mbd, null, null);
}
else {
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
//使用构造函数进行实例化
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);
}
// No special handling: simply use no-arg constructor.
//无参构造器初始,用CGLIB对Bean进行实例化,在CglibSubclassingInstantiationStrategy中可以看到具体的实例化过程
return instantiateBean(beanName, mbd);
}
populateBean负责处理实例化对象之间的依赖关系,完成整个依赖注入的过程。代码如下:
@SuppressWarnings("deprecation") // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
....
//开始进行依赖注入过程,先处理autowaire注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
//根据名字注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
//根据类型注入
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
....
if (pvs != null) {
//进行属性注入,不再具体分析
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
补充说明:
AUTOWIRE_BY_NAME:Spring容器会根据属性的名称来查找匹配的依赖对象。它要求属性的名称与要注入的依赖对象的bean名称相匹配。如果找到匹配的bean名称,Spring容器将注入该对象
AUTOWIRE_BY_TYPE:Spring容器会根据属性的类型来查找匹配的依赖对象。它要求属性的类型与要注入的依赖对象的bean类型相匹配。如果找到匹配的bean类型,Spring容器将注入该对象。
至此已经完成了对各种Bean属性的依赖注入过程。在Bean的创建和对象注入的过程中,依据BeanDefinition中的信息来递归完成依赖注入,在对Bean的属性进行依赖注入时,解析的过程是一个递归的过程。这样,根据依赖关系,一层一层地完成Bean的创建和注入,直到最后完成当前Bean的创建。有了这
个顶层Bean的创建和对它的属性依赖注入的完成,意味着和当前Bean相关的整个依赖链的注入也完成了。这里会存在一个问题,那就是循环依赖,如果存在这样的依赖关系,如A->B,B->C,C->A,Spring IoC又是怎么去处理的呢?
设计一个循环依赖的例子,代码如下:
public class ClassA {
private ClassB classB;
public void setClassB(ClassB classB) {
this.classB = classB;
}
public void doSomethingA() {
System.out.println("ClassA is doing something.");
classB.doSomethingB();
}
}
public class ClassB {
private ClassC classC;
public void setClassC(ClassC classC) {
this.classC = classC;
}
public void doSomethingB() {
System.out.println("ClassB is doing something.");
classC.doSomethingC();
}
}
public class ClassC {
private ClassA classA;
public void setClassA(ClassA classA) {
this.classA = classA;
}
public void doSomethingC() {
System.out.println("ClassC is doing something.");
}
}
Spring通过三级缓存来解决循环依赖。
//org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
//一级缓存,存储的是spring初始好的对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
//三级缓存。缓存的是对象工厂
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
//二级缓存。存储的是早期的单例对象,仅仅实例化好了,但是没有进行初始化
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
对于上述A B C实例的初始化过程如下所示:
通过三级缓存就解决bean的循环依赖问题,其实只需要二级缓存就能处理循环依赖,引入三级缓存的目的是为了解决代理对象的循环依赖。首先查看bean的声明周期及初始化过程。
首先明白一个点,只有BeanPostProcessors后置处理完成后才认为一个bean真正初始化完成。spring Aop的代理对象也是通过
BeanPostProcessor` 来完成的,为AnnotationAwareAspectAutoProxyCreator,为了尽可能的延缓 BeanPostProcessor 的调用,Spring 才采用了三级缓存,存入一个 Objectactory 对象,并不创建,而是当发生了循环依赖的时候,采取三级缓存获取到三级缓存来创建对象,因为发生了循环依赖的时候,不得不提前调用 BeanPostProcessor 来完成实例的初始化。
Bean生命周期
- BeanNameAware's setBeanName:设置beanName
- BeanClassLoaderAware's setBeanClassLoader:设置类加载器
- BeanFactoryAware's setBeanFactory:将当前的 BeanFactory(Spring 容器)传递给该 bean
- EnvironmentAware's setEnvironment:设置环境变量
- EmbeddedValueResolverAware's setEmbeddedValueResolver:是 Spring 框架中的一个接口,用于支持解析占位符表达式(Placeholder Expression)的功能。
- ResourceLoaderAware's setResourceLoader (only applicable when running in an application context):将
ResourceLoader
对象注入到实现了该接口的 bean 中 - ApplicationEventPublisherAware's setApplicationEventPublisher (only applicable when running in an application context):将
ApplicationEventPublisher
注入到实现了该接口的 bean 中 - MessageSourceAware's setMessageSource (only applicable when running in an application context):设置消息源
- ApplicationContextAware's setApplicationContext (only applicable when running in an application context):设置上下文
- ServletContextAware's setServletContext (only applicable when running in a web application context):设置servlet上下文
- postProcessBeforeInitialization methods of BeanPostProcessors:前置处理
- InitializingBean's afterPropertiesSet:设置完属性后调用
- a custom init-method definition:执行自定义的初始方法
- postProcessAfterInitialization methods of BeanPostProcessors 后置处理
在Bean的初始化过程中,内置了很多扩展方式支持用户对bean进行扩展,笔者写了一个小示例:
public class MyBean implements EmbeddedValueResolverAware, InitializingBean {
private StringValueResolver embeddedValueResolver;
private String message;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public void printMessage() {
System.out.println(message);
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
System.out.println("EmbeddedValueResolverAware.setEmbeddedValueResolver方法");
this.embeddedValueResolver=resolver;
String resolvedValue = embeddedValueResolver.resolveStringValue("${my.property}");
}
public void customMethodInit(){
System.out.println("自定义方法调用");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean afterPropertiesSet");
System.out.println(this.message);
}
}
自定义Bean后置处理器:
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor前置处理");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor后置处理");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
配置xml:
<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myBean" class="io.github.xw.model.MyBean" init-method="customMethodInit">
<!-- 可以设置 bean 的属性 -->
<property name="message" value="Hello, Spring!"/>
</bean>
<bean id="customBeanPostProcessor" class="io.github.xw.ioc.lifecycle.CustomBeanPostProcessor" >
</bean>
</beans>
结果如下:
总结
Spring内置了很多的实现将不同来源的bean定义转成BeanDefinition,在Bean的创建和对象依赖注入的过程中,需要依据BeanDefinition中的信息来递归地完
成依赖注入。从上面的几个递归过程中可以看到,这些递归都是以getBean为入口的。一个递归是在上下文体系中查找需要的Bean和创建Bean的递归调用,另一个递归是在依赖注入时,通过递归调用容器的getBean方法,得到当前Bean的依赖Bean,同时也触发对依赖Bean的创建和注人。在对Bean的属性进行依赖注入时,解析的过程也是一个递归的过程。这样,根据依赖关系,一层一层地完成Bean的创建和注入,直到最后完成当前Bean的创建。有了这个顶层Bean的创建和对它的属性依赖注入的完成,意味着和当前Bean相关的整个依赖链的注入也完成了。
参考资料:
- 《Spring技术内幕》