上篇文章,我在开头将bean实例化过程比喻成寒武纪生命大爆发。如果你同意这个看法的话,那本文解析的bean的依赖注入就是生命的形式生物从两栖进化到爬行,从爬行进化到哺乳,从哺乳进化到类人猿,从低等进化到高等的过程。
本文撰写累计时常10小时,建议阅读时间5小时。去趟卫生间,等你回来我们就开始吧。
目录
1. applyMergedBeanDefinitionPostProcessors
1.1 CommonAnnotationBeanPostProcessor
1.2 AutowiredAnnotationBeanPostProcessor
2. populateBean
3. postProcessProperties方法
3.1 CommonAnnotationBeanPostProcessor方法的inject
3.1.1 doResolveDependency
3.1.2 String类型的依赖注入
3.1.3 普通类型的依赖注入
3.2 AutowiredAnnotationBeanPostProcessor方法的inject
4. 构造函数注入
5. 附录:本项目工程文件
上一篇文章,已经详细分析了bean的实例化过程。也就是doCreatBean方法中instanceWrapper = createBeanInstance(beanName, mbd, args);执行完成,将实例化后的bean封装在了wrapper中。随后再解封出来bean对象和bean对应的类型。接下来调用applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);方法。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 从BeanWrapper获得封装在它内部的bean和bean类型
final Object bean = instanceWrapper.getWrappedInstance();
Class> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 调用实现了MergedBeanDefinitionPostProcessor的bean后置处理器的postProcessMergedBeanDefinition方法。
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new xxx;
}
// 标记该bd已经合并处理完成了
mbd.postProcessed = true;
}
}
// 加入到bean工厂的earlySingletonObjects中,这个是Spring用来解决循环依赖的凭据(后续文章单独介绍循环依赖)
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 依赖注入填充属性
populateBean(beanName, mbd, instanceWrapper);
// bean属性填充完成后,就可以进行bean的初始化工作了。依赖注入初始化工作后续文章再详细介绍。
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
throw new xxx;
}
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 actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new xxx;
}
}
}
}
// 注册实现了DisposableBean接口的bean,该bean实现了void destroy()接口,在bean的生命周期销毁前可以触发回调进行善后工作。
// 需要注意的是,它对原型对象无效。
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new xxx;
}
return exposedObject;
}
调用实现了MergedBeanDefinitionPostProcessor的bean后置处理器的postProcessMergedBeanDefinition方法,其中有用到的后置处理器是CommonAnnotationBeanPostProcessor, AutowiredAnnotationBeanPostProcessor, ApplicationListenerDetector。
CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法如下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
// 解析bean属性上@Resource的注解,将其封装为metadata对象并缓存
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
// 对注入的metadata对象进行检查,没有注册的bd需要进行注册。最后添加到metadata对象的checkedElements集合中。
metadata.checkConfigMembers(beanDefinition);
}
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);中处理@PostConstruct 和 @PreDestroy方法添加到InitDestroyAnnotationBeanPostProcessor的lifecycleMetadataCache这个CurrentHashMap中,该map中的存放的结果是
metadata.checkConfigMembers(beanDefinition);对注入的medadata对象进行检查,没有注册的bd需要进行注册。最后添加到metadata对象的checkedElements集合中。
核心代码是findResourceMetadata(beanName, beanType, null);
InjectionMetadata findResourceMetadata(String beanName, final Class> clazz, @Nullable PropertyValues pvs) {
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 缓存中如果没有,则创建一个metadata
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
它的核心是buildResourceMetadata(clazz);它会沿着类及其父类解析出添加了@WebServiceRef, @EJB, @Resource注解的属性和方法,将其加入到elements中。然后将clazz和elements封装成一个InjectionMetadata对象findResourceMetadata方法。findResourceMetadata会将metadata对象缓存在commonAnnotationBeanPostProcessor后置处理器对象的injectionMetadataCache map中方便后续流程使用。
private InjectionMetadata buildResourceMetadata(final Class> clazz) {
List elements = new ArrayList<>();
Class> targetClass = clazz;
// 沿着class的继承路径,按层次寻找加上了@WebServiceRef, @EJB, @Resource注解的属性和方法,将其加入到currElements中。
do {
final List currElements = new ArrayList<>();
// 遍历Class中的所有field,判断每个field是否需要被注入
// 如果上述注解加在静态类,静态方法,会直接报错!
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
currElements.add(new WebServiceRefElement(field, field, null));
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
currElements.add(new EjbRefElement(field, field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
// 遍历Class中的所有method,判断每个method是否需要依赖项
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
//new的是一个ResourceElement实例,它是InjectionMetadata.InjectedElement的子类
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
// 将上面找到的currElements添加到elements中。
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法如下,核心方法是findAutowiringMetadata。
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class> clazz, @Nullable PropertyValues pvs) {
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 缓存中如果没有,则创建一个metadata
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
与findResourceMetadata中核心方法是是调用buildResourceMetadata类似,在findAutowiringMetadata中核心方法是调用buildAutowiringMetadata。最终也会将需要注入的属性或方法添加到elements中。并且返回封装好的metadata对象。上层也会将其缓存到injectionMetadataCache中。
private InjectionMetadata buildAutowiringMetadata(final Class> clazz) {
List elements = new ArrayList<>();
Class> targetClass = clazz;
do {
final List currElements = new ArrayList<>();
// 遍历Class中的所有field,根据注解判断每个field是否需要被注入
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 看看field是不是@Autowired 或 @Value
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
// 不支持静态类,直接返回。
return;
}
//确定带注释的字段或方法是否需要依赖项。
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 遍历Class中的所有method,根据注解判断每个method是否需要依赖项
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
//不支持静态方法,直接返回。
return;
}
//确定带注释的字段或方法是否需要依赖项。
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// new一个AutowiredMethodElement类,它是InjectionMetadata.InjectedElement的子类
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
ApplicationListenerDetector很简单,将beanName和是否是singleton的boolean变量放到ApplicationListenerDetector对象的Map
这样就到了今天的重头戏——populateBean(beanName, mbd, instanceWrapper);的分析了。该步骤是Spring进行依赖注入的入口,也就是属性填充的地方。
populate是“落户于...”的意思。Spring的开发者用这个词拟人化后非常贴切且让人感慨!下面我们就开始分析依赖注入的流程。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 如果对象为null,bd也没有属性值需要注入,则跳过bean初始化环节直接返回null。
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw xxx;
}
else {
return;
}
}
boolean continueWithPropertyPopulation = true;
// 遍历继承了InstantiationAwareBeanPostProcessor的仅有:ImportAwareBeanPostProcessor,CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 如果用户自定义的类中postProcessAfterInstantiation方法返回false,那么依赖注入流程就提前结束
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
// 看看bd中是否有缓存的值,没有就是null
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 默认是AUTOWIRE_NO。 约定优于配置!
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
// 获取属性值
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
// CommonAnnotationBeanPostProcessor
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;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
//应用给定的属性值,解析此bean工厂中对其他bean的任何运行时引用。
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
首先,如果传入的beanWrap对象为null,而bd还有需要注入的属性值。巧妇难为无米之炊,没办法,只要抛出异常。接着遍历实现了InstantiationAwareBeanPostProcessor接口的后置处理器,调用其postProcessAfterInstantiation方法。该方法会返回boolean变量,目前Spring内部使用的三个类ImportAwareBeanPostProcessor,CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor都是返回的false。如果用户自定义实现了InstantiationAwareBeanPostProcessor类,并将postProcessAfterInstantiation方法的返回值写为false。那么就会导致continueWithPropertyPopulation的值改为false。bean的依赖注入就提前结束了。
接下来一直到for循环之前的代码并不重要。核心的代码是PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);这里是遍历bean后置处理器,调用它们的postProcessProperties方法执行属性填充。
在上面循环中,postProcessProperties方法被调用的处理器主要有两个:CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor。前者处理@Resource注解,后者处理@Autowired注解。
CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor中的postProcessProperties方法
// CommonAnnotationBeanPostProcessor的postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// metadata ==null 或者 clazz不等于metadata中存放的目标class,就需要重新构建metadata。
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw 注入失败!
}
return pvs;
}
// AutowiredAnnotationBeanPostProcessor的postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (Exception ex) {
throw xxx;
}
return pvs;
}
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection checkedElements = this.checkedElements;
Collection elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
首先执行findXXXMetadata(beanName, bean.getClass(), pvs);方法获得metadata对象。这个对象首先从缓存获取,如果缓存中没有就立即创建一个新的metadata对象返回。一般来说在之前的applyMergedBeanDefinitionPostProcessors步骤已经缓存好了metadata对象,所以这里都能拿到。接下来都是调用的InjectionMetadata的inject方法。该方法会遍历metadata内所有缓存好的InjectedElement对象,即第1节中解析出来的注解属性或方法。然后调用element.inject(target, beanName, pvs)方法,就会分别调用了各自后置处理器中继承了InjectionMetadata.InjectedElement私有的内部类的inject方法实现多态。
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);核心反复
//核心方法是调用getResourceToInject方法
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
if分支是通过field注入,else是通过方法注入。它们均是通过getResourceToInject(target, requestingBeanName)寻找依赖项,通过一系列的空壳方法调用后,最终会调用CommonAnnotationBeanPostProcessor的autowireResource方法。
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
Set autowiredBeanNames;
// 属性名
String name = element.name;
if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
// 核心是执行resolveDependency中的doResolveDependency方法获得对象
resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
}
else {
// 去bean工厂中获取名字为name的bean, 类型是element.lookupType类型
resource = factory.getBean(name, element.lookupType);
// 得到bean工厂中的
autowiredBeanNames = Collections.singleton(name);
}
if (factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
for (String autowiredBeanName : autowiredBeanNames) {
// requestingBeanName是正在初始化的bean, autowiredBeanName是requestingBeanName依赖的属性。
// 比如:requestingBeanName = "gardenofEden" autowiredBeanName = "xiawa"
if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
return resource;
}
如果走if分支,核心方法是resolveDependency方法中的DefaultListableBeanFactory的doResolveDependency方法。如果是else分支那么就直接通过factory.getBean拿到需要注入的属性对象了。最后beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName)梳理好这些bean的依赖关系后就可以一路返回注入对象,最终在inject方法中执行field.set(target, getResourceToInject(target, requestingBeanName));完成注册了。
public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = canonicalName(beanName);
// Map> dependentBeanMap中存放的是各个bean的依赖关系。 key是bean的名字。value是一个LinkedHashSet,里面存放的其他bean的名字,这些bean都要依赖key。
// // 向key为canonicalName的Set中添加dependentBeanName
synchronized (this.dependentBeanMap) {
Set dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
if (!dependentBeans.add(dependentBeanName)) {
return;
}
}
// 向dependentBeanMap添加
synchronized (this.dependenciesForBeanMap) {
Set dependenciesForBean =
this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
dependenciesForBean.add(canonicalName);
}
}
registerDependentBean方法的作用举例来说,假如有A, B, C三个bean。 A依赖B,B也依赖A,除此之外C还依赖A, D也依赖A。那么最终dependentBeanMap中存放的数据结构是:
key:A value:{B, C, D}
key:B value:{A}
dependenciesForBeanMap中存放的数据结构是<被依赖bean, 依赖bean>
key:A value:{B}
key:B value:{A}
key:C value:{A}
key:D value:{A}
了解了autowireResource方法中的各个方法的作用后,我们就可以详细分析依赖注入的过程了。
我们主要分析if分支的流程。普通的Spring流程会由resolveDependency方法会调用doResolveDependency来分类处理注入属性对象类型是String,普通类对象,其他类型对象(数组,集合,map等类型)的场景。本文主要介绍String类型和普通类这两种场景,剩下的数组等类型注入过程大同小异,就留给读者们自行分析了。
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 看看有没有缓存过参数值。
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 参数值类型
Class> type = descriptor.getDependencyType();
// 获取@Value("${xxx}")注解中的注解参数 ${xxx}
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
// String类型的依赖注入
if (value instanceof String) {
// 从配置文件获取属性值
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
// 计算bean定义中包含的给定字符串,可能将其解析为表达式。
value = evaluateBeanDefinitionString(strVal, bd);
}
// 进行必要类型转换
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
// stream,Array,Collection,Map类型的依赖注入。
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 普通类型的依赖注入
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
// resolveCandidate中调用的就是beanFactory.getBean(beanName);
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally{
// 缓存起来
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
进入doResolveDependency还是老样子,首先看看有没有缓存,有的话就返回。然后拿到依赖项的类型Class> type = descriptor.getDependencyType()。接着执行
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
这行代码用于解析@Value注解。它能够获取@Value("${xxx}")注解中的注解参数 ${xxx}赋给result。如果result != null,并且它是String类型的话,就是从配置文件读取值注入到属性上了。
String类型的依赖注入主要是通过解析注解,找到配置文件中的属性然后替换placeHolder占位符完成的。它通过String strVal = resolveEmbeddedValue((String) value)这一行代码干活。它首先找到之前注册到bean工厂embeddedValueResolvers中的解析器解析该值。注册的地方就在实例化bean的第一个方法中finishBeanFactoryInitialization中的
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
而这个方法又是调用的注册在Environment对象propertyResolver.resolvePlaceholders(text);该解析器是在容器evnironment对象创建的时候就被注册上的。最终解析value这个值的方法会交给PropertyPlaceholderHelper的parseStringValue方法来操刀执行。
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, Set visitedPlaceholders) {
StringBuilder result = new StringBuilder(value);
// 确定 ${ 符号的其实位置,如果不存在就压根儿不用解析
int startIndex = value.indexOf(this.placeholderPrefix);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
// 找到${ 和 }的直接的内容作为placeholder并添加到visitedPlaceholders集合中
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
// 嵌套调用本方法,以解决传入的value中有嵌套的 ${} 如果发现解析的结果与集合中的重复,则抛出异常。
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);
// 递归解析获得完整的placeholder后,最终通过PropertySourcesPropertyResolver#getProperty(java.lang.String, java.lang.Class, boolean)方法读取propertySources
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;
}
}
}
// 看看获取到的值是否还有可能被解析,再次递归调用parseStringValue方法进行解析。
if (propVal != null) {
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
// 将result从${xxx} 替换为找到的value值。 比如本项目中是${race},替换为properties文件中的 "yellow"
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
}
else if (this.ignoreUnresolvablePlaceholders) {
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();
}
以Human.class中的注解@Value("${race}")为例。首先传入的value值已经是${race}了,然后确定${race}字符串中通过 "${"和"}"中间的内容作为placeholder。然后再次递归调用本方法placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders),目的是怕解析后placeholder中还有嵌套的${xxx}。当placeholder递归解析完成后,就可以去配置文件中寻找placeholder对应的值了。
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
它会通过PropertySourcesPropertyResolver#getProperty(java.lang.String, java.lang.Class
protected T getProperty(String key, Class targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
for (PropertySource> propertySource : this.propertySources) {
Object value = propertySource.getProperty(key);
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value);
}
// 将得到的值value转换成上层需要的类型targetValueType返回
return convertValueIfNecessary(value, targetValueType);
}
}
}
return null;
}
this.propertySources中的值是:
systemProperties
systemEnvironment
class path resource 也就是 [application.properties]
最终,result中的值被从配置文件中读取出的值替代,然后一路返回到上层doResolveDependency中的String strVal = resolveEmbeddedValue((String) value);然后进行bd合并和必要的类型转换后放回上层。最终返回到inject方法中,作为set函数的第二个入参完成对目标属性的注入。
field.set(target, getResourceToInject(target, requestingBeanName));
普通类型的依赖注入对象首先根据要注入的属性类型寻找到一批候选的bean,然后再确定这批bean中最适合的那一个bean然后装配上。doResolveDependency方法中Map
protected Map findAutowireCandidates(
@Nullable String beanName, Class> requiredType, DependencyDescriptor descriptor) {
// 获取给定类型的所有bean名
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map result = new LinkedHashMap<>(candidateNames.length);
// 如果实现了这几个接口的某个,就将其加入到result中。
for (Map.Entry, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
// 将符合要求的candidate放入result中。
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
//以下是针对数组和集合类的依赖注入,原理也是大同小异
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
1.首先获取出所有实现了注入属性类型的beanName放入String[] candidateNames中。
2.如果注入的类似属于以下4种中的某一个类型,比如BeanFactory,那么就将实现了beanFactory的那个对象加入result。
interface org.springframework.context.ApplicationEventPublisher
interface org.springframework.core.io.ResourceLoader
interface org.springframework.context.ApplicationContext
interface org.springframework.beans.factory.BeanFactory
3.将candidateNames中满足要求的bean加入到result中。如果该bean还未实例化,那么还要通过addCandidateEntry方法中的descriptor.resolveCandidate(candidateName, requiredType, this)方法调用beanFactory.getBean(beanName)或getType(candidateName)
实例化对应的bean才行。(代码很简单,就不再占用篇幅了)
public Object resolveCandidate(String beanName, Class> requiredType, BeanFactory beanFactory) throws BeansException {
return beanFactory.getBean(beanName);
}
4.如果是数组、集合类的候选对象也加入到result。
最后收集完result返回doResolveDependency的Map
/* * * * * * * * * * * * * * * * * *
* doResolveDependency方法的代码片段 *
* * * * * * * * * * * * * * * * * */
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
// resolveCandidate中调用的就是beanFactory.getBean(beanName);
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
如果找到的matchingBeans不止一个,那还要通过determineAutowireCandidate方法去看看@Primary和@Priority注解,最终确定好优先级顺序后返回优先级最高的作为注入的bean。如果优先级相同(没有上述2个注解视为优先级相同),那么再最后通过名称看看候选名称是否与此bean定义中存储的bean名称或别名匹配。如果还没有找到唯一的候选对象,那么就抛出NoUniqueBeanDefinitionException异常,构造和处理方法详情可查阅《关于Spring自动装配几个你所不知道的事》。
protected boolean matchesBeanName(String beanName, @Nullable String candidateName) {
return (candidateName != null &&
(candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));
}
如果刚好只有一个那就再好不过了,直接获取到instanceCandidate然后返回上层。最后返回到inject方法field.set(target, getResourceToInject(target, requestingBeanName))完成属性field的注入。
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
// 创建一个属于field的依赖描述器
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set autowiredBeanNames = new LinkedHashSet<>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
//获得依赖值
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
// 更新全局的dependentBeanMap和dependenciesForBeanMap,该缓存的容器就更新缓存并且缓存过后将this.cached = true, this.cachedFieldValue赋上包装对象方便后续使用。
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
// 最后,进行属性的赋值。
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
首先看看参数是否缓存,如果缓存就返回缓存在本AutowiredFieldElement中的参数值cachedFieldValue,如果这个Element对象继承了DependencyDescriptor接口,那么就通过beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter)方法获得注入对象。该方法的详细过程已经在3.1.1 doResolveDependency节讲述,这里不再赘述。
private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
if (cachedArgument instanceof DependencyDescriptor) {
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
Assert.state(this.beanFactory != null, "No BeanFactory available");
// 内部还是会调用DefaultListableBeanFactory#doResolveDependency的方法获得注入的依赖对象
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
}
else {
// 直接返回缓存的参数值
return cachedArgument;
}
}
如果没有缓存对象,在try块中也通过value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);获取注入对象。该方法的详细过程也已经在3.1.1 doResolveDependency节讲述,这里不再赘述。获取完注入对象后,在synchronized块中更新全局的dependentBeanMap和dependenciesForBeanMap,该缓存的容器就更新缓存并且缓存过后将this.cached = true, this.cachedFieldValue赋上包装对象方便后续使用。最后将value注入到bean的对应属性上。
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
上一篇文章留了一点悬念——带参构造函数在实例化bean时,入参的依赖注入是什么时候发生的呢?我们现在来解答。
在autowireConstructor方法长长的for{...}循环中,有如下一段代码(有精简)。构造参数argsHolder是通过createArgumentArray方法得到的。
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
createArgumentArray方法如下,重要的代码是Object autowiredArgument = resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter, fallback);方法。在它内部也是调用beanFactory的resolveDependency方法获取依赖注入对象的(上文已经详细分析)。
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
Set usedValueHolders = new HashSet<>(paramTypes.length);
Set autowiredBeanNames = new LinkedHashSet<>(4);
// 遍历所有需要注入的入参对象
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class> paramType = paramTypes[paramIndex];
// paramName是null的替换为""
String paramName = (paramNames != null ? paramNames[paramIndex] : "");
ConstructorArgumentValues.ValueHolder valueHolder = null;
if (resolvedValues != null) {
// 查找一个参数值,该值要么对应于构造函数参数列表中的给定索引,要么按类型进行一般匹配。
valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
// 如果找不到直接匹配且不打算自动连接,那么让我们尝试下一个泛型的、无类型的参数值作为回退:它可以在类型转换之后匹配(例如,String -> int)。
if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
// 查找与给定类型匹配的下一个泛型参数值,忽略当前解析过程中已经使用的参数值。
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
}
if (valueHolder != null) {
// 如果不为null,就作为候选项
usedValueHolders.add(valueHolder);
Object originalValue = valueHolder.getValue();
Object convertedValue;
if (valueHolder.isConverted()) {
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
Object sourceHolder = valueHolder.getSource();
if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
args.resolveNecessary = true;
args.preparedArguments[paramIndex] = sourceValue;
}
}
args.arguments[paramIndex] = convertedValue;
args.rawArguments[paramIndex] = originalValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
// 上面没有找到匹配项。那么就在这里尝试做依赖注入
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
args.resolveNecessary = true;
}
}
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
}
return args;
}
综上所述,Spring的依赖注入方法主要是依靠DefaultListableBeanFactory的resolveDependency方法来完成的。它调用内部的doResolveDependency方法,对String类型,普通类型,数组集合等类型进行了分类处理。Spring类型通过读取配置文件完成属性的注入,普通类型通过bean工厂的getBean方法获取(创建)缓存在bean工厂中的bean对象完成对应类型属性的依赖注入。到此Spring正常的IOC流程就几乎完成了。唯一剩下循环依赖的问题,我们下篇文章再重点分析这个棘手的问题,看看Spring是如何巧妙化解的。
依赖注入完成,标志着bean的创建过程进行了一半。时间也就从上一节的05:00来到06:00。远方的地平线上,启明星的光线已经划破了黑色的幕布,耀眼夺目。也许你不知道,它真正的名字叫做——金星!
工程目录和文件:
@Component("yadang")
public class Adam {
private String name;
@Autowired
private Eve eve;
@PostConstruct
private void init(){
name = "Adam";
}
public void sayHello(){
System.out.println("你好,我是" + name + ". 我爱" + eve.getName());
}
public String getName() {
return name;
}
}
@Component("xiawa")
public class Eve {
private String name;
@Autowired
private Adam adam;
@PostConstruct
private void init(){
name = "Eve";
}
public void sayHello(){
System.out.println("你好,我是" + name + ". 我爱" + adam.getName());
}
public String getName() {
return name;
}
}
@Component
@PropertySource("classpath:application.properties")
@DependsOn("xiawa")
public class Human {
@Value("${race}")
private String race;
private String nationality;
public Human(@Value("${nationality}") String nationality) {
this.nationality = nationality;
}
public void sayHello(){
System.out.println("大家好,欢迎来到伊甸园");
System.out.println("我们的国籍是:" + nationality);
}
}
public class Apple {}
@Component()
public class AppleFactory implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new Apple();
}
@Override
public Class> getObjectType() {
return Apple.class;
}
@Override
public boolean isSingleton() { return false; }
}
@Service
public class GardenofEden {
private String gardenName;
@Autowired
private Adam adam;
@Resource(name = "xiawa")
// @Resource //读者调试看看与上面使用name属性有何不同
private Eve eve;
@Autowired
private Human human;
public void sayHello(){
adam.sayHello();
eve.sayHello();
human.sayHello();
}
}
@ComponentScan("com.Hodey")
public class CaseApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(CaseApplication.class);
GardenofEden garden = ctx.getBean(GardenofEden.class);
garden.sayHello();
Apple apple1 = (Apple) ctx.getBean("appleFactory");
System.out.println(apple1);
Apple apple2 = (Apple) ctx.getBean("appleFactory");
System.out.println(apple2);
}
}
application.properties文件内容:
server.port=8090
nationality=China
race=yellow
项目最终执行结果:
你好,我是Adam. 我爱Eve
你好,我是Eve. 我爱Adam
大家好,欢迎来到伊甸园
我们的国籍是:China
com.Hodey.learn.factory.Apple@657c8ad9
com.Hodey.learn.factory.Apple@436a4e4b