接口定义

用于推断一个特定的beanDefinition是否能作为指定依赖的候选者的策略接口

public interface AutowireCandidateResolver {
// 默认情况下直接根据bd中的定义返回,如果没有进行特殊配置的话为true
default boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
return bdHolder.getBeanDefinition().isAutowireCandidate();
} // 指定的依赖是否是必要的
default boolean isRequired(DependencyDescriptor descriptor) {
return descriptor.isRequired();
} // QualifierAnnotationAutowireCandidateResolver做了实现,判断是否有@Qualifier注解
// 一共有两种注解:
// 1.Spring内置的@Qualifier注解,org.springframework.beans.factory.annotation.Qualifier
// 2.添加了JSR-330相关依赖,javax.inject.Qualifier注解
// 默认情况下返回false
default boolean hasQualifier(DependencyDescriptor descriptor) {
return false;
} // QualifierAnnotationAutowireCandidateResolver做了实现
// 获取一个该依赖一个建议的值
@Nullable
default Object getSuggestedValue(DependencyDescriptor descriptor) {
return null;
} // 对某个依赖我们想要延迟注入,但是在创建Bean的过程中这个依赖又是必须的
// 通过下面这个方法就能为延迟注入的依赖先生成一个代理注入到bean中
@Nullable
default Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
return null;
} }

继承关系

可以看到继承关系都是单层的,我们就一个一个往下看

SimpleAutowireCandidateResolver

相比于接口没有什么区别,实现也就是父接口中的默认实现,一般也不会使用这个类

public class SimpleAutowireCandidateResolver implements AutowireCandidateResolver {

	@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
return bdHolder.getBeanDefinition().isAutowireCandidate();
} @Override
public boolean isRequired(DependencyDescriptor descriptor) {
return descriptor.isRequired();
} @Override
@Nullable
public Object getSuggestedValue(DependencyDescriptor descriptor) {
return null;
} @Override
@Nullable
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
return null;
} }

GenericTypeAwareAutowireCandidateResolver

额外增加了对泛型的处理能力

public class GenericTypeAwareAutowireCandidateResolver extends SimpleAutowireCandidateResolver
implements BeanFactoryAware { @Nullable
private BeanFactory beanFactory; @Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
} @Nullable
protected final BeanFactory getBeanFactory() {
return this.beanFactory;
} @Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
if (!super.isAutowireCandidate(bdHolder, descriptor)) {
// 如果bd中已经配置了这个bean不做为依赖进行注入的话,直接返回false
return false;
}
// 检查泛型是否匹配
return checkGenericTypeMatch(bdHolder, descriptor);
} }

QualifierAnnotationAutowireCandidateResolver

增加了对@Qualifier注解以及@Value注解的处理能力

public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwareAutowireCandidateResolver {

	private final Set<Class<? extends Annotation>> qualifierTypes = new LinkedHashSet<>(2);
// @Value注解
private Class<? extends Annotation> valueAnnotationType = Value.class; // @Qualifier注解
@SuppressWarnings("unchecked")
public QualifierAnnotationAutowireCandidateResolver() {
this.qualifierTypes.add(Qualifier.class);
try {
this.qualifierTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Qualifier",
QualifierAnnotationAutowireCandidateResolver.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
} // ....... @Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
// 类型上已经匹配了
boolean match = super.isAutowireCandidate(bdHolder, descriptor);
if (match) {
// 还需要判断是否满足@Qualifier注解的要求
match = checkQualifiers(bdHolder, descriptor.getAnnotations());
if (match) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
Method method = methodParam.getMethod();
if (method == null || void.class == method.getReturnType()) {
match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
}
}
}
}
return match;
} // ..... // 是否是@Qualifier注解
protected boolean isQualifier(Class<? extends Annotation> annotationType) {
for (Class<? extends Annotation> qualifierType : this.qualifierTypes) {
if (annotationType.equals(qualifierType) || annotationType.isAnnotationPresent(qualifierType)) {
return true;
}
}
return false;
} @Override
@Nullable
public Object getSuggestedValue(DependencyDescriptor descriptor) {
Object value = findValue(descriptor.getAnnotations());
if (value == null) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
value = findValue(methodParam.getMethodAnnotations());
}
}
return value;
} // 查找@Value注解
@Nullable
protected Object findValue(Annotation[] annotationsToSearch) {
if (annotationsToSearch.length > 0) {
AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(
AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);
if (attr != null) {
return extractValue(attr);
}
}
return null;
} // 获取@Value注解中的值
protected Object extractValue(AnnotationAttributes attr) {
Object value = attr.get(AnnotationUtils.VALUE);
if (value == null) {
throw new IllegalStateException("Value annotation must have a value attribute");
}
return value;
} }

ContextAnnotationAutowireCandidateResolver

这个类是最底层的子类,集成了所有的方法,并且额外提供了对依赖进行延迟处理的能力

public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotationAutowireCandidateResolver {

    // 如果依赖需要进行延迟处理,那么构建一个代理对象先注入到bean中,不会直接去创建依赖对象
@Override
@Nullable
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) {
return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null);
} // 依赖是否需要延迟处理
protected boolean isLazy(DependencyDescriptor descriptor) {
for (Annotation ann : descriptor.getAnnotations()) {
Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class);
if (lazy != null && lazy.value()) {
return true;
}
}
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
Method method = methodParam.getMethod();
if (method == null || void.class == method.getReturnType()) {
Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class);
if (lazy != null && lazy.value()) {
return true;
}
}
}
return false;
} // 构建延迟处理的代理对象
protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {
final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory(); // 创建了一个TargetSource
TargetSource ts = new TargetSource() {
@Override
public Class<?> getTargetClass() {
return descriptor.getDependencyType();
}
@Override
public boolean isStatic() {
return false;
}
// target是我们实际想要使用的对象,如果不进行延迟处理,那么注入到bean中的应该就是这个对象
// 但是因为要进行延迟注入依赖,所有会向外暴露一个TargetSource,这个TargetSource的目标为实际想要使用的对象,生成代理时会基于TargetSource进行生成。在运行期间(完成注入后)我们使用这个延迟处理的依赖时实际调用的会是target中的方法。
@Override
public Object getTarget() {
Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null);
if (target == null) {
Class<?> type = getTargetClass();
if (Map.class == type) {
return Collections.emptyMap();
}
else if (List.class == type) {
return Collections.emptyList();
}
else if (Set.class == type || Collection.class == type) {
return Collections.emptySet();
}
throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(),
"Optional dependency not present for lazy injection point");
}
return target;
}
@Override
public void releaseTarget(Object target) {
}
}; // 使用ProxyFactory,给TargetSource生成一个代理
ProxyFactory pf = new ProxyFactory();
pf.setTargetSource(ts);
Class<?> dependencyType = descriptor.getDependencyType();
// 如果依赖的类型是一个接口,需要让代理类也实现这个接口
if (dependencyType.isInterface()) {
pf.addInterface(dependencyType);
}
// 生成代理
return pf.getProxy(beanFactory.getBeanClassLoader());
} }

总结

  • SimpleAutowireCandidateResolver:单纯的将接口变成了可实例化的类,方法实现跟接口保持一致
  • GenericTypeAwareAutowireCandidateResolver: 判断泛型是否匹配,支持泛型依赖注入(From Spring4.0)
  • QualifierAnnotationAutowireCandidateResolver :处理 @Qualifier 和 @Value 注解
  • ContextAnnotationAutowireCandidateResolver :处理依赖级别的 @Lazy 注解,重写了getLazyResolutionProxyIfNecessary 方法。

Spring杂谈 | Spring中的AutowireCandidateResolver的更多相关文章

  1. maven引入多个spring jar包中存在同名文件的问题

    项目打包后执行报错:Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespaceht ...

  2. [原创]java WEB学习笔记109:Spring学习---spring中事物管理

    博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好 ...

  3. [原创]java WEB学习笔记109:Spring学习---spring对JDBC的支持:使用 JdbcTemplate 查询数据库,简化 JDBC 模板查询,在 JDBC 模板中使用具名参数两种实现

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  4. 在Spring tools suite中使用git 共享项目

    我们都在eclipse 和 myeclipse中使用过cvs 和 svn 版本控制工具进行团队开发,今天我学习了另外一种版本控制工具git,下面我演示如何在Spring tools suite中使用g ...

  5. 在Spring的bean中注入HttpServletRequest解密

    我们可以在Spring的bean中轻松的注入HttpServletRequest,使用@Autowired HttpServletRequest request;就可以了. 但是,为什么我们可以直接这 ...

  6. Spring基础——在Spring Config 文件中配置 Bean

    一.基于 XML 的 Bean 的配置——通过全类名(反射) <bean <!-- id: bean 的名称在IOC容器内必须是唯一的若没有指定,则自动的将全限定类名作为 改 bean 的 ...

  7. 控制反转和spring在项目中可以带来的好处

    Spring实例化Bean的三种方式分别是: 1,xml配置使用bean的类构造器 <bean id="personService" class="cn.servi ...

  8. Spring MVC Controller中解析GET方式的中文参数会乱码的问题(tomcat如何解码)

    Spring MVC Controller中解析GET方式的中文参数会乱码的问题 问题描述 在工作上使用突然出现从get获取中文参数乱码(新装机器,tomcat重新下载和配置),查了半天终于找到解决办 ...

  9. Spring MVC程序中得到静态资源文件css,js,图片文件的路径问题总结

    上一篇 | 下一篇 Spring MVC程序中得到静态资源文件css,js,图片 文件的路径 问题总结 作者:轻舞肥羊 日期:2012-11-26 http://www.blogjava.net/fi ...

随机推荐

  1. AJ学IOS 之二维码学习,快速打开相机读取二维码

    AJ分享,必须精品 上一篇文章写了怎么生成二维码,这儿就说说怎么读取吧,反正也很简单,iOS封装的太强大了 步骤呢就是这样: 读取二维码需要导入AVFoundation框架#import <AV ...

  2. Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十二)之Error Handling with Exceptions

    The ideal time to catch an error is at compile time, before you even try to run the program. However ...

  3. Python中关于第三方库的补充

    Python语言的强大之处在于它的开源.正是因为它的开源,产生了成百上千的第三方库,涵盖了计算机的几乎所有的方向.第三方库的安装也并不是特别的复杂,通过在cmd中使用pip命令可以安装几乎所有的库,但 ...

  4. NCTF2019 小部分题解

    前言 礼拜五领航杯打的比较累,做不出WEB,D3CTF没用,做了NJCTF的一些题目(懒,睡觉到12点起) Misc 第一次比赛先去做misc,以前一直做WEB,以后要WEB+MISC做.礼拜六下午做 ...

  5. billu b0x2靶机渗透

    实战渗透靶机billu b0x2 攻击kali :192.168.41.147 靶机b0x2: 192.168.41.148 起手先nmap扫了一下 扫到了四个开放的端口,有ssh,http,rpcb ...

  6. [PHP] 调用微博API 发微博OAuth2.0

    在实际测试中出现很多问题, 第一就是按照文档调用ACCESS_TOKEN的时候费老劲啦,因为是编辑线上的,有好多中文空格,没有看出来!整了好久! 第二个就是在调用api发微博的时候出现乱码!必须把发送 ...

  7. vue路由中 Navigating to current location ("/router") is not allowed

    报错原因:多次点击同一路由,导致路由被多次添加 解决方法: router/index中添加以下代码: //router/index.js Vue.use(VueRouter) //导入vue路由 co ...

  8. iview使用之怎样给Page组件添加跳转按钮

    在项目开发过程中,我们会经常遇到使用分页的表格,然而在ivieiw中,我们通常只能使用Page组件自带的功能,如下图: 切换每页条数这些基本的功能都不说了,有时候我们需要在输入框里输入想要跳转到的页数 ...

  9. 支持向量机SVM知识梳理和在sklearn库中的应用

    SVM发展史 线性SVM=线性分类器+最大间隔 间隔(margin):边界的活动范围.The margin of a linear classifier is defined as the width ...

  10. Windows系统安装最新版本RabbitMQ3.8.3及报错解决

    今天想安装下RabbitMQ写几个用例看下,发现最新的安装包有些问题,不能直接安装使用,遇到一些问题,记录一下解决办法. 下载安装包 因为RabbitMQ是Erlang编写,安装时,需要先安装Erla ...