文章目录
前言
@Resource注解和@Autowired注解是咱们使用Spring的两大利器,用来进行属性注入。这篇文章来简单分析下@Resource的原理
一、@Resource怎么用?
很简单的啦,譬如如下:
@Service
public class TestService {
@Resource
ResourceLockDAO testDao;
}
二、那么注入做了些啥
1.查找一个类的所有注入点
1.1 在Spring中Bean的生态位置
Spring的生态代码过程中,在推断出类的构造方法,且根据构造方法创建实例之后,就进行了该bean的注入点查询过程。
详见AbstractAutowireCapableBeanFactory的doCreateBean方法中的applyMergedBeanDefinitionPostProcessors,看源码么,点进去!!
/**
* Apply MergedBeanDefinitionPostProcessors to the specified bean definition,
* invoking their {@code postProcessMergedBeanDefinition} methods.
* @param mbd the merged bean definition for the bean
* @param beanType the actual type of the managed bean instance
* @param beanName the name of the bean
* @see MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition
*/
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
}
可以看到循环调用了所有BeanPostProcessor,找到MergedBeanDefinitionPostProcessor子类,调用其postProcessMergedBeanDefinition方法,此处不累赘,我直接说了,调用的CommonAnnotationBeanPostProcessor的对应方法。细心的你可能会发现,还有个叫AutowiredAnnotationBeanPostProcessor的类也有该方法,从类名,聪明的你应该猜到,这个类的该方法是为了处理@Autowired注解。
废话不多说,咱们来看看@Resource注解查询
1.2 detail,源码解读
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
咱们主要看findResourceMetadata方法
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);
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;
}
- 可以看到此处先从injectionMetadataCache这个map结构的cache里获取,如果获取不到才会进行下面的操作,大家是不是觉得没有必要,因为Spring是单例的,但是Spring只是默认是单例的,万一你使用的scope是原型呢?是吧?查找bean的注入点这个操作就不需要多次执行了。
- 看到此处的synchronized原语的上下代码,熟悉单例设计模式的同学应该兴奋了。因为这是咱们的单例模式–懒汉实现方式的原理,也就是双重检查锁,也就是在synchronized的前后分别进行判断,防止多线程同时处理,最后出错。
下面是最重要的代码逻辑,根据重要程度,此处源码不会全部贴上来,会进行适当删减
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 处理属性上的@Resource注解
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
// 如果有@WebServiceRef注解,也处理
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
// 如果有@EJB注解也处理
}
else if (field.isAnnotationPresent(Resource.class)) {
// 如果加了@Resource注解的field是static的,那

本文深入剖析Spring框架中@Resource注解的工作原理,包括如何使用、查找类的注入点及具体的注入过程。通过源码解读,揭示@Resource在Spring中的运作机制。
最低0.47元/天 解锁文章
376

被折叠的 条评论
为什么被折叠?



