spring之CommonAnnotationBeanPostProcessor源码
1 作用
首先来说一下这个BeanPostProcessor
的作用
(1)处理@Resource
注解,实现ByName
的自动注入功能。
(2)处理@PostConstruct
和@PreDestroy
注解,指定初始化方法和销毁方法,使用注解的方法相比于实现接口可以降低spring的耦合。
接下来我们看一下这个BeanPostProcessor
的类图,从类图上我们就能知道上述功能的处理方法是哪个
(1)
InstantiationAwareBeanPostProcessor
这个接口有三个方法,执行时机分别如下所示 1)
postProcessBeforeInstantiation
实例化前。空方法 2)
postProcessAfterInstantiation
属性赋值前,即实例化后。空方法 3)
postProcessProperties
属性赋值前,但在postProcessAfterInstantiation
执行之后。实现自动注入功能。进入
CommonAnnotationBeanPostProcessor
源码,我们可以发现postProcessBeforeInstantiation
和postProcessAfterInstantiation
方法都是空的。重要的方法就是postProcessProperties
这一个,我们稍后看源码。(2)
MergedBeanDefinitionPostProcessor
这个接口有两个方法,执行时机分别如下所示 1)
postProcessMergedBeanDefinition
实例化后,但在postProcessAfterInstantiation
执行之前。解析@Resource
、@PostConstruct
、@PreDestroy
的注解信息。 2)
resetBeanDefinition
经过上面分析,我们知道最先执行的方法是MergedBeanDefinitionPostProcessor
的postProcessMergedBeanDefinition
方法,我们先看这个方法源码。
2 自动注入功能实现
首先看CommonAnnotationBeanPostProcessor
的构造方法
public CommonAnnotationBeanPostProcessor() {
//设置优先级
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
//下面这两个类不就是我们常用的设置初始化方法和销毁方法的注解吗
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
2.1 postProcessMergedBeanDefinition
这个方法在bean实例化后首先被执行
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//2.1.1处理生命周期注解(@PostConstruct、@PreDestroy)
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
//2.1.2处理自动注入注解(@Resource)
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
2.1.1处理生命周期注解(@PostConstruct、@PreDestroy)
去父类的postProcessMergedBeanDefinition
方法
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
//(1)找到beanType类的生命周期元数据
LifecycleMetadata metadata = findLifecycleMetadata(beanType);
//(2)将生命周期元数据保存到beanDefinition中
metadata.checkConfigMembers(beanDefinition);
}
(1)找到beanType类的生命周期元数据
这个方法的套路(逻辑)和我们分析
AutowiredAnnotationBeanPostProcessor
中@Autowired
注入原理差不多啊,所以说学习spring源码,你只要咬牙坚持下来,后面你会发现越来越容易。
private LifecycleMetadata findLifecycleMetadata(Class<?> clazz) {
/**
* 先查缓存中有没有生命周期元数据
* this.lifecycleMetadataCache是一个map集合,它的key就是当前类的clazz
* value是当前类的生命周期元数据
*/
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);
//缓存,key就是当前类的clazz
this.lifecycleMetadataCache.put(clazz, metadata);
}
return metadata;
}
}
return metadata;
}
直接去获取生命周期元数据
private LifecycleMetadata buildLifecycleMetadata(final Class<?> clazz) {
/**
* this.initAnnotationType为PostConstruct.class
* this.destroyAnnotationType为PreDestroy.class
* 在CommonAnnotationBeanPostProcessor默认的构造方法中赋值
* AnnotationUtils.isCandidateClass()是判断clazz中是否存在PostConstruct和PreDestroy注解
*/
if (!AnnotationUtils.isCandidateClass(clazz, Arrays.asList(this.initAnnotationType, this.destroyAnnotationType))) {
//不存在PostConstruct和PreDestroy注解,直接返回一个空的生命周期元数据
return this.emptyLifecycleMetadata;
}
List<LifecycleElement> initMethods = new ArrayList<>();
List<LifecycleElement> destroyMethods = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<LifecycleElement> currInitMethods = new ArrayList<>();
final List<LifecycleElement> currDestroyMethods = new ArrayList<>();
/**
* ReflectionUtils.doWithLocalMethods()方法很简单,其实就是遍历targetClass所有的
* 方法,将它作为参数回调接口方法。这个方法我在说@Autowired原理的时候已经详细解释过了,这里
* 不在多费唇舌
* 真正的处理逻辑在参数2的lamada表达式中
*/
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
/****************************处理@PostConstruct注解******************************/
//method.isAnnotationPresent()判断方法上有没有指定的注解(反射的知识)
if (this.initAnnotationType != null && method.isAnnotationPresent(this.initAnnotationType)) {
//(1)构建LifecycleElement
LifecycleElement element = new LifecycleElement(method);
//加入到初始化方法集合中
currInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Found init method on class [" + clazz.getName() + "]: " + method);
}
}
/****************************处理@PreDestroy注解******************************/
if (this.destroyAnnotationType != null && method.isAnnotationPresent(this.destroyAnnotationType)) {
currDestroyMethods.add(new LifecycleElement(method));
if (logger.isTraceEnabled()) {
logger.trace("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 (initMethods.isEmpty() && destroyMethods.isEmpty() ? this.emptyLifecycleMetadata :
//(2)构建LifecycleMetadata
new LifecycleMetadata(clazz, initMethods, destroyMethods));
}
(1) 构建
LifecycleElement
public LifecycleElement(Method method) { //生命周期方法不能有参数 if (method.getParameterCount() != 0) { throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method); } this.method = method; /** * 如果生命周期方法是私有的,identifier就是类或接口的完全限定名+"."+方法名 * 否则identifier就是方法名 */ this.identifier = (Modifier.isPrivate(method.getModifiers()) ? ClassUtils.getQualifiedMethodName(method) : method.getName()); }
(2)构建
LifecycleMetadata
public LifecycleMetadata(Class<?> targetClass, Collection<LifecycleElement> initMethods, Collection<LifecycleElement> destroyMethods) { //指定当前生命周期元数据所属的类 this.targetClass = targetClass; //指定当前生命周期元数据中类的初始化方法 this.initMethods = initMethods; //指定当前生命周期元数据中类的销毁方法 this.destroyMethods = destroyMethods; }
(2)将生命周期元数据保存到beanDefinition中
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
/****************************缓存初始化方法******************************/
Set<LifecycleElement> checkedInitMethods = new LinkedHashSet<>(this.initMethods.size());
for (LifecycleElement element : this.initMethods) {
//要么是完全限定名,要么是方法名
String methodIdentifier = element.getIdentifier();
//(1)判断methodIdentifier是否已经被指定为初始化方法
if (!beanDefinition.isExternallyManagedInitMethod(methodIdentifier)) {
//(2)没有就将该方法注册为初始化方法
beanDefinition.registerExternallyManagedInitMethod(methodIdentifier);
//添加到已检查的方法集合中
checkedInitMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Registered init method on class [" + this.targetClass.getName() + "]: " + element);
}
}
}
/****************************缓存初销毁方法******************************/
//流程都差不多
Set<LifecycleElement> checkedDestroyMethods = new LinkedHashSet<>(this.destroyMethods.size());
for (LifecycleElement element : this.destroyMethods) {
String methodIdentifier = element.getIdentifier();
if (!beanDefinition.isExternallyManagedDestroyMethod(methodIdentifier)) {
beanDefinition.registerExternallyManagedDestroyMethod(methodIdentifier);
checkedDestroyMethods.add(element);
if (logger.isTraceEnabled()) {
logger.trace("Registered destroy method on class [" + this.targetClass.getName() + "]: " + element);
}
}
}
this.checkedInitMethods = checkedInitMethods;
this.checkedDestroyMethods = checkedDestroyMethods;
}
(1)判断methodIdentifier是否已经被指定为生命周期初始化方法
public boolean isExternallyManagedInitMethod(String initMethod) { synchronized (this.postProcessingLock) { return (this.externallyManagedInitMethods != null && this.externallyManagedInitMethods.contains(initMethod)); } }
(2)将该方法注册为生命周期初始化方法
public void registerExternallyManagedInitMethod(String initMethod) { synchronized (this.postProcessingLock) { if (this.externallyManagedInitMethods == null) { this.externallyManagedInitMethods = new HashSet<>(1); } //set集合,初始化方法不只一个 this.externallyManagedInitMethods.add(initMethod); } }
(3) 生命周期注解方法执行
方法执行是在CommonAnnotationBeanPostProcessor
的postProcessBeforeInitialization
方法完成的,即bean初始化方法(xml中init-method="xxx",@Bean(initMethod = "xxxx"))
调用前执行。
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//获取所有生命周期元数据
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
//执行生命周期初始化方法
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
执行生命周期初始化方法
public void invokeInitMethods(Object target, String beanName) throws Throwable {
Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
Collection<LifecycleElement> initMethodsToIterate =
(checkedInitMethods != null ? checkedInitMethods : this.initMethods);
if (!initMethodsToIterate.isEmpty()) {
for (LifecycleElement element : initMethodsToIterate) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
}
//执行LifecycleElement的invoke方法
element.invoke(target);
}
}
}
执行LifecycleElement的invoke方法
public void invoke(Object target) throws Throwable {
//反射执行生命周期初始化方法
ReflectionUtils.makeAccessible(this.method);
this.method.invoke(target, (Object[]) null);
}
到此有关生命周期注解就处理完成了
2.1.2处理自动注入注解(@Resource)
(1)找到beanType类的注入(注解)元数据
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
//判断是否需要重新解析clazz
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
//解析clazz,获取注入(注解)元数据
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
解析clazz,获取注入(注解)元数据
在看这个方法之前,必须补充一段代码。这个是
CommonAnnotationBeanPostProcessor
的类静态代码块,每次创建对象的时候都会执行static { webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef"); ejbClass = loadAnnotationType("javax.ejb.EJB"); //我们只看这一行代码,他向resourceAnnotationTypes这个集合中添加了Resource的clazz对象 //实际上就是@Resource注解 resourceAnnotationTypes.add(Resource.class); if (webServiceRefClass != null) { resourceAnnotationTypes.add(webServiceRefClass); } if (ejbClass != null) { resourceAnnotationTypes.add(ejbClass); } }
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
//判断clazz是否包含resourceAnnotationTypes中的注解
if (!AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
/********************************处理属性*********************************/
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//webServiceRef相关,不用管
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, field, null));
}
//ejb相关,不用管
else if (ejbClass != null && field.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
//这里开始处理有@Resource注解的属性了
else if (field.isAnnotationPresent(Resource.class)) {
//@Resource不能加载静态属性上
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
//默认构造方法上初始化了ignoredResourceTypes="javax.xml.ws.WebServiceContext"
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
//构建ResourceElement对象加入到currElements集合中
//我们看一下ResourceElement的构造方法
currElements.add(new ResourceElement(field, field, null));
}
}
});
/********************************处理方法*********************************/
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
//获取桥接方法,你就把它当成一个普通的方法对象
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
//webServiceRef相关,不用管
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
//ejb相关,不用管
else if (ejbClass != null && bridgedMethod.isAnnotationPresent(ejbClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
//这里开始处理有@Resource注解的方法了
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
//@Resource不能加载静态方法上
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
//获取方法所有参数的类型
Class<?>[] paramTypes = method.getParameterTypes();
//@Resource注解只能加载单参数的方法上
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
//忽略参数名字为javax.xml.ws.WebServiceContext的方法
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
/**
* 该方法在@Autowired注解原理的时候已经说过了
* 就是判断当前方法是不是clazz类某个属性的get或set方法,如果是,就
* 返回这个属性的属性描述
*/
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
//构建ResourceElement对象加入到currElements集合中
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
elements.addAll(0, currElements);
//接着去找父类的@Resource注解
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
//构建InjectionMetadata
return InjectionMetadata.forElements(elements, clazz);
}
ResourceElement
的构造方法这个构造方法不简单,它做了很重要的事,解析了类成员上面
@Resource
、@Lazy
注解信息。不看这个构造方法, 你就不知道后面使用的各种值的来源。public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) { super(member, pd); //获取@Resource注解信息 Resource resource = ae.getAnnotation(Resource.class); //获取注解name属性值 String resourceName = resource.name(); //获取注解type属性值 Class<?> resourceType = resource.type(); /** * this.isDefaultName表示是否使用默认名 * 注解name属性值为空的时候,就表示使用默认名 * 属性的名字或者方法名截取后的值 */ this.isDefaultName = !StringUtils.hasLength(resourceName); //使用默认名 if (this.isDefaultName) { //获取属性名或方法名 resourceName = this.member.getName(); //以set开头的方法 if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) { //实际上就是截取方法名,去掉set,然后将首字母转小写 resourceName = Introspector.decapitalize(resourceName.substring(3)); } } /** * CommonAnnotationBeanPostProcessor实现了BeanFactoryAware接口 * 在这个BeanPostProcessor对象创建过程中会自动调用接口的setBeanFactory()方法 * 注入BeanFactory对象, * 此时会使用BeanFactory创建一个新的EmbeddedValueResolver * new EmbeddedValueResolver((ConfigurableBeanFactory) beanFactory); * * 不使用默认值就调用EmbeddedValueResolver对指定的名字解析一下 */ else if (embeddedValueResolver != null) { resourceName = embeddedValueResolver.resolveStringValue(resourceName); } //resourceType的默认值为Object.class //此时在@Resource上指定注入类型 if (Object.class != resourceType) { //(1)检查指定的类型resourceType是否匹配属性或方法参数 checkResourceType(resourceType); } else { // No resource type specified... check field/method. //(2)获取注入类型 resourceType = getResourceType(); } this.name = (resourceName != null ? resourceName : ""); this.lookupType = resourceType; //这个忽略,没用过 String lookupValue = resource.lookup(); this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName()); //@Lazy注解处理 Lazy lazy = ae.getAnnotation(Lazy.class); this.lazyLookup = (lazy != null && lazy.value()); }
(1)检查指定的类型resourceType是否匹配属性或方法参数
protected final void checkResourceType(Class<?> resourceType) { /*******************************属性**********************************/ if (this.isField) { Class<?> fieldType = ((Field) this.member).getType(); //指定的类型和属性类型必须包含继承关系,否则抛异常 if (!(resourceType.isAssignableFrom(fieldType) || fieldType.isAssignableFrom(resourceType))) { throw new IllegalStateException("Specified field type [" + fieldType + "] is incompatible with resource type [" + resourceType.getName() + "]"); } } /*******************************方法**********************************/ else { /** * this.pd就是PropertyDescriptor,在上面提到过 * 当有@Resource注解的方法是当前类某个属性的get或set方法时, * 就返回这个属性的属性描述PropertyDescriptor,然后设置到ResourceElement中 * 所以: * 如果该方法是某个属性的get或set方法,就检查这个属性的类型和指定类型的继承关系 * 否则就检查方法第一个参数的类型和指定类型的继承关系 */ Class<?> paramType = (this.pd != null ? this.pd.getPropertyType() : ((Method) this.member).getParameterTypes()[0]); if (!(resourceType.isAssignableFrom(paramType) || paramType.isAssignableFrom(resourceType))) { throw new IllegalStateException("Specified parameter type [" + paramType + "] is incompatible with resource type [" + resourceType.getName() + "]"); } } }
(2)获取注入类型
protected final Class<?> getResourceType() { //获取属性类型 if (this.isField) { return ((Field) this.member).getType(); } //方法是对应属性的get或set方法,此时获取属性类型 else if (this.pd != null) { return this.pd.getPropertyType(); } //获取方法第一个参数类型 else { return ((Method) this.member).getParameterTypes()[0]; } }
(2)将注入(注解)元数据保存到beanDefinition中
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
//遍历
for (InjectedElement element : this.injectedElements) {
Member member = element.getMember();
//将当前需要自动注入的属性或方法保存到BeanDefinition中
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
beanDefinition.registerExternallyManagedConfigMember(member);
checkedElements.add(element);
}
}
this.checkedElements = checkedElements;
}
(3)执行自动注入
首先你得明白一点,spring中注解方式的自动注入都是在
InstantiationAwareBeanPostProcessor
的postProcessProperties
方法完成的
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//获取@Resource注解的注入元数据,前面已经讲过了
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//执行注入
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
执行注入
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
//遍历获取每个需要被注入的元素(属性或方法)
for (InjectedElement element : elementsToIterate) {
//无论是属性或方法都封装为ResourceElement
element.inject(target, beanName, pvs);
}
}
}
调用
ResourceElement
的inject
方法,实现byName
自动注入/** * Either this or {@link #getResourceToInject} needs to be overridden. */ protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable { /*********************************属性******************************/ if (this.isField) { Field field = (Field) this.member; //不需要set方法,直接强行赋值 ReflectionUtils.makeAccessible(field); //getResourceToInject(target, requestingBeanName)重点是这个方法 field.set(target, getResourceToInject(target, requestingBeanName)); } /*********************************方法******************************/ else { if (checkPropertySkipping(pvs)) { return; } try { Method method = (Method) this.member; //不管方法的修饰符,强行执行方法 ReflectionUtils.makeAccessible(method); method.invoke(target, getResourceToInject(target, requestingBeanName)); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }
getResourceToInject(target, requestingBeanName)
, 它会去spring容器中获取requestingBeanName
对应的bean对象。protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) { /** * (1)懒加载自动注入,创建一个代理对象返回 * (2)否则直接去spring容器中获取requestingBeanName对应的bean对象 */ return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) : getResource(this, requestingBeanName)); }
(1)懒加载自动注入,获取代理对象
/** * Obtain a lazily resolving resource proxy for the given name and type, * delegating to {@link #getResource} on demand once a method call comes in. * @param element the descriptor for the annotated field/method * @param requestingBeanName the name of the requesting bean * @return the resource object (never {@code null}) * @since 4.2 * @see #getResource * @see Lazy */ protected Object buildLazyResourceProxy(final LookupElement element, final @Nullable String requestingBeanName) { //创建一个目标资源 TargetSource ts = new TargetSource() { @Override public Class<?> getTargetClass() { return element.lookupType; } @Override public boolean isStatic() { return false; } @Override public Object getTarget() { //代理类的目标对象也是getResource方法获取的 return getResource(element, requestingBeanName); } @Override public void releaseTarget(Object target) { } }; //代理工厂 ProxyFactory pf = new ProxyFactory(); pf.setTargetSource(ts); //设置接口 if (element.lookupType.isInterface()) { pf.addInterface(element.lookupType); } //类加载器 ClassLoader classLoader = (this.beanFactory instanceof ConfigurableBeanFactory ? ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() : null); //获取代理对象 return pf.getProxy(classLoader); }
获取代理对象的流程还是比较简单的,我这里不再深究。
(2)非懒加载自动注入,获取原对象
/** * Obtain the resource object for the given name and type. * @param element the descriptor for the annotated field/method * @param requestingBeanName the name of the requesting bean * @return the resource object (never {@code null}) * @throws NoSuchBeanDefinitionException if no corresponding target resource found */ protected Object getResource(LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { if (StringUtils.hasLength(element.mappedName)) { return this.jndiFactory.getBean(element.mappedName, element.lookupType); } if (this.alwaysUseJndiLookup) { return this.jndiFactory.getBean(element.name, element.lookupType); } //上面两个不用管,jndi相关,没用过 if (this.resourceFactory == null) { throw new NoSuchBeanDefinitionException(element.lookupType, "No resource factory configured - specify the 'resourceFactory' property"); } //获取匹配的依赖对象 return autowireResource(this.resourceFactory, element, requestingBeanName); }
获取匹配的依赖对象
/** * Obtain a resource object for the given name and type through autowiring * based on the given factory. * @param factory the factory to autowire against * @param element the descriptor for the annotated field/method * @param requestingBeanName the name of the requesting bean * requestingBeanName就是postProcessProperties方法的beanName参数,代表当前赋值阶段bean的名字 * @return the resource object (never {@code null}) * @throws NoSuchBeanDefinitionException if no corresponding target resource found */ protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName) throws NoSuchBeanDefinitionException { Object resource; Set<String> autowiredBeanNames; String name = element.name; if (factory instanceof AutowireCapableBeanFactory) { AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory; /** * 获取依赖描述 * 实际上就是 * new LookupDependencyDescriptor((Field) this.member, this.lookupType); * new LookupDependencyDescriptor((Method) this.member, this.lookupType); */ DependencyDescriptor descriptor = element.getDependencyDescriptor(); /** * 按类型获取依赖对象 * 此时!factory.containsBean(name)成立,容器中没有默认名对应的bean */ if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) { autowiredBeanNames = new LinkedHashSet<>(); //使用beanFactory解析依赖描述,获取依赖bean对象 //该方法上篇文章已经讲过,此处不再赘述,这个方法是核心重点方法,一定要看懂 resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null); if (resource == null) { throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object"); } } //按指定名name获取依赖对象 else { //本质上就是factory.getBean(name, element.lookupType); resource = beanFactory.resolveBeanByName(name, descriptor); autowiredBeanNames = Collections.singleton(name); } } //按指定名name获取依赖对象 else { resource = factory.getBean(name, element.lookupType); autowiredBeanNames = Collections.singleton(name); } //注册依赖关系 if (factory instanceof ConfigurableBeanFactory) { ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory; for (String autowiredBeanName : autowiredBeanNames) { if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) { beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName); } } } return resource; }
总结:(1)没有指定
@Resource
注解中的name
属性时,先判断容器中是否包含默认名对应的bean,不包含就按类型注入,否则就按默认名获取依赖对象。(2)指定
@Resource
注解中的name
属性时,直接按照指定的name
获取依赖对象。
至此,@Resource
注解的注入流程就已经讲完了。
3 总结
(1)@PostConstruct
、@PreDestroy
、@Resource
均在MergedBeanDefinitionPostProcessor
接口的postProcessMergedBeanDefinition
被解析。除此之外,这个方法还会将这几个注解标注的成员记录到BeanDefinition
中。
(2)@Resource
的自动注入功能是在InstantiationAwareBeanPostProcessor
接口的postProcessProperties
方法中完成的。
(3)@Resource
的自动注入不单是ByName
,当我们手动指定@Resource
注解中的name
属性时,直接按照指定的name
获取依赖对象。否则会先判断容器中有没有默认名(属性名或方法名截取set或第一个参数名)对应的bean,有就注入该bean,无就按类型注入。
(4)@Resource
标注在方法上,方法有且只能有一个参数。