SpringIoC依赖注入的过程(二)
上文讲到spring通过AbstractAutowireCapableBeanFactory的doCreateBean方法来创建并且初始化一个bean,doCreateBean首先生成一个未初始化的bean,然后再对它进行依赖注入、属性解析以及回调bean的方法等等。本文将继续讲解spring是如何做到这些的。
衔接上文,分析doCreateBean的源码,紧接着bean创建后的第一段代码如下:
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
mbd.postProcessed = true;
}
}
具体做了什么事情,跟到applyMergedBeanDefinitionPostProcessors方法中看
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class beanType, String beanName)
throws BeansException {
try {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
catch (Exception ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing failed of bean type [" + beanType + "] failed", ex);
}
}
上面的
applyMergedBeanDefinitionPostProcessors方法中,调用了所有MergedBeanDefinitionPostProcessor后置处理器的postProcessMergedBeanDefinition。那么,MergedBeanDefinitionPostProcessor有哪些呢?CommonAnnotationBeanPostProcessor是其中一个,看看它执行了什么操作
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
if (beanType != null) {
InjectionMetadata metadata = findResourceMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);
}
}
CommonAnnotationBeanPostProcessor又调用了父类的postProcessMergedBeanDefinition方法,它的父类就是InitDestroyAnnotationBeanPostProcessor。从名字上可以看出,它就是管理通过标注声明的初始化以及销毁bean的方法的。它的postProcessMergedBeanDefinition方法是这样的
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);
}
}
根据bean的类型找到LifecycleMetadata,然后用它配置BeanDefinition。
LifecycleMetadata是什么呢,我们先来看看它是怎么来的
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
if (this.lifecycleMetadataCache == null) {
// Happens after deserialization, during destruction...
return buildLifecycleMetadata(clazz);
}
// Quick check on the concurrent map first, with minimal locking.
LifecycleMetadata metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
synchronized (this.lifecycleMetadataCache) {
metadata = this.lifecycleMetadataCache.get(clazz);
if (metadata == null) {
metadata = buildLifecycleMetadata(clazz);
this.lifecycleMetadataCache.put(clazz, metadata);
}
return metadata;
}
}
return metadata;
}
private LifecycleMetadata buildLifecycleMetadata(Class<?> clazz) {
final boolean debug = logger.isDebugEnabled();
LinkedList<LifecycleElement> initMethods = new LinkedList<LifecycleElement>();
LinkedList<LifecycleElement> destroyMethods = new LinkedList<LifecycleElement>();
Class<?> targetClass = clazz;
do {
LinkedList<LifecycleElement> currInitMethods = new LinkedList<LifecycleElement>();
LinkedList<LifecycleElement> currDestroyMethods = new LinkedList<LifecycleElement>();
for (Method method : targetClass.getDeclaredMethods()) {
if (this.initAnnotationType != null) {
if (method.getAnnotation(this.initAnnotationType) != null) {
LifecycleElement element = new LifecycleElement(method);
currInitMethods.add(element);
if (debug) {
logger.debug("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
}
if (this.destroyAnnotationType != null) {
if (method.getAnnotation(this.destroyAnnotationType) != null) {
currDestroyMethods.add(new LifecycleElement(method));
if (debug) {
logger.debug("Found destroy method on class [" + clazz.getName() + "]: " + method);
}
}
}
}
initMethods.addAll(0, currInitMethods);
destroyMethods.addAll(currDestroyMethods);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new LifecycleMetadata(clazz, initMethods, destroyMethods);
}
同样,Spring对
LifecycleMetadata做了缓存,并且同样使用了类似于双重检查机制的单例模式,先判断缓存中有没有,若没有先对线程安全的map加锁,然后再次查看缓存中有没有,如果没有才去创建。创建LifecycleMetadata 的过程是怎样的呢?它由两个方法列表构成,一个是initMethods,另一个是destroyMethods。这两个方法列表是什么呢?就是在bean中声明了PostConstruct和PreDestroy标注的方法。buildLifecycleMetadata方法不仅寻找当前类声明PostConstruct和PreDestroy标注的方法,还会循环的查找父类中声明了这两个标注的方法。得到了LifecycleMetadata后它对BeanDefinition做了什么呢,来看LifecycleMetadata的checkConfigMembers方法的代码:
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
synchronized(this.initMethods) {
for (Iterator<LifecycleElement> it = this.initMethods.iterator(); it.hasNext();) {
String methodIdentifier = it.next().getIdentifier();
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
}
else {
it.remove();
}
}
}
synchronized(this.destroyMethods) {
for (Iterator<LifecycleElement> it = this.destroyMethods.iterator(); it.hasNext();) {
String methodIdentifier = it.next().getIdentifier();
if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {
beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier);
}
else {
it.remove();
}
}
}
}
简单的概括一下上面方法的行为就是把所有的
initMethods和
destroyMethods注册到BeanDefinition中去备用,什么时候用,后面会说到。说了这么多,才把InitDestroyAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法说完。接下来看看它的子类在父类处理完之后它又做了些啥。为了方便,再贴一边代码
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
if (beanType != null) {
InjectionMetadata metadata = findResourceMetadata(beanType);
metadata.checkConfigMembers(beanDefinition);
}
}
有了刚才的基础,一切都好理解了。它去寻找InjectionMetadata ,然后注册到BeanDefinition中备用。截止目前终于出现了注入的字眼,跟到findResourceMetadata中去看看它到底找到了什么。
private InjectionMetadata findResourceMetadata(final Class<?> clazz) {
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(clazz);
if (metadata == null) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(clazz);
if (metadata == null) {
LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
Class<?> targetClass = clazz;
do {
LinkedList<InjectionMetadata.InjectedElement> currElements = new LinkedList<InjectionMetadata.InjectedElement>();
for (Field field : targetClass.getDeclaredFields()) {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, null));
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, null));
}
}
}
for (Method method : targetClass.getDeclaredMethods()) {
method = BridgeMethodResolver.findBridgedMethod(method);
Method mostSpecificMethod = BridgeMethodResolver.findBridgedMethod(ClassUtils.getMostSpecificMethod(method, clazz));
if (method.equals(mostSpecificMethod)) {
if (webServiceRefClass != null && method.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
if (method.getParameterTypes().length != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
currElements.add(new WebServiceRefElement(method, pd));
}
else if (ejbRefClass != null && method.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if (method.getParameterTypes().length != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
currElements.add(new EjbRefElement(method, pd));
}
else if (method.isAnnotationPresent(Resource.class)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
if (!ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(method);
currElements.add(new ResourceElement(method, pd));
}
}
}
}
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
metadata = new InjectionMetadata(clazz, elements);
this.injectionMetadataCache.put(clazz, metadata);
}
}
}
return metadata;
}
还是原来的配方,还是原来的味道。不同的只是查找和注册的内容不同,前两个处理的是web service相关的东西,本人没用过,也就不详细说了。最后一个处理的是
Resource
标注,又发现了我们要找的东西了。我们继续寻找,还有哪些
MergedBeanDefinitionPostProcessor,都注册哪些东西?AutowiredAnnotationBeanPostProcessor注册了声明了
Autowired
标注的字段和方法。AbstractApplicationContext的内部类ApplicationListenerDetector向AbstractApplicationContext注册了单例bean的名字。常用的也就这么几个,下面是在我的工程里找出的所有MergedBeanDefinitionPostProcessor的子类。
说了这么多,才说完doCreateBean中的applyMergedBeanDefinitionPostProcessors,执行这个方法找到了需要注入的声明了Autowired标注和Resource标注的字段和方法,为下一步的注入做了准备。后续的操作下一篇文章继续。