Spring依赖注入(DI)核心接口AutowireCandidateResolver深度分析,解析@Lazy、@Qualifier注解的原理
2020-03-05 07:16
645 查看
AutowireCandidateResolver
- 用于确定特定的Bean定义是否符合特定的依赖项的候选者的策略接口。
public interface AutowireCandidateResolver { /** * 判断给定的bean定义是否允许被依赖注入(bean定义的默认值都是true) * @param bdHolder bean名称和别名的持有者 * @param descriptor 目标方法和其参数或字段的描述符 */ default boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) { return bdHolder.getBeanDefinition().isAutowireCandidate(); } /** * 给定的descriptor是否是必须的 * @param descriptor 目标方法参数或字段的描述符 */ default boolean isRequired(DependencyDescriptor descriptor) { return descriptor.isRequired(); } /** * 确定给定的描述符是否标注了@Qualifier * @param descriptor 目标方法参数或字段的描述符 */ default boolean hasQualifier(DependencyDescriptor descriptor) { return false; } /** * 返回@value标注的文本 * @param descriptor 目标方法参数或字段的描述符 */ @Nullable default Object getSuggestedValue(DependencyDescriptor descriptor) { return null; } /** * 如果注入点injection point需要的话,就创建一个proxy来作为最终的解决方案ContextAnnotationAutowireCandidateResolver * @param descriptor 目标方法参数或字段的描述符 * @param beanName bean名字 */ @Nullable default Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) { return null; } }
SimpleAutowireCandidateResolver是最简单的实现,适配器形式的存在,不可直接使用~
GenericTypeAwareAutowireCandidateResolver从名字可以看出和泛型有关。Spring4.0后的泛型依赖注入主要是它来实现的,所以这个类也是Spring4.0后出现的
QualifierAnnotationAutowireCandidateResolver这个实现类非常非常的重要,它不仅仅能处理@Qualifier、@Value,还能够处理泛型依赖注入,因此功能已经很完善了~~~ 在Spring2.5之后都使用它来处理依赖关系~
QualifierAnnotationAutowireCandidateResolver
public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwareAutowireCandidateResolver { //默认支持@Qualifier注解,这个可以通过addQualifierType增加我们自定义的注解 private final Set<Class<? extends Annotation>> qualifierTypes = new LinkedHashSet<>(2); //默认支持@value注解 private Class<? extends Annotation> valueAnnotationType = Value.class; 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. } } public QualifierAnnotationAutowireCandidateResolver(Class<? extends Annotation> qualifierType) { Assert.notNull(qualifierType, "'qualifierType' must not be null"); this.qualifierTypes.add(qualifierType); } public QualifierAnnotationAutowireCandidateResolver(Set<Class<? extends Annotation>> qualifierTypes) { Assert.notNull(qualifierTypes, "'qualifierTypes' must not be null"); this.qualifierTypes.addAll(qualifierTypes); } // 我们可以调用这个方法来自定义注解 public void addQualifierType(Class<? extends Annotation> qualifierType) { this.qualifierTypes.add(qualifierType); } //@Value注解类型Spring也是允许我们改成自己的类型的 public void setValueAnnotationType(Class<? extends Annotation> valueAnnotationType) { this.valueAnnotationType = valueAnnotationType; } //判断bdHolder所提供的bean定义是否为注入的候选。 @Override public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) { boolean match = super.isAutowireCandidate(bdHolder, descriptor); // 这里发现,及时父类都匹配上了,我本来还得再次校验一把~~~ if (match) { //qualifierTypes里的注解在此处生效(默认qualifierTypes里只有@Qualifier注解),最终可能匹配出一个或者0个出来 match = checkQualifiers(bdHolder, descriptor.getAnnotations()); if (match) { // 这里处理的是方法入参们~~~~ 只有方法有入参才需要继续解析 MethodParameter methodParam = descriptor.getMethodParameter(); if (methodParam != null) { //获取这个入参它所属于的方法 Method method = methodParam.getMethod(); // 如果它不是任何方法或者属于方法的返回值是void 才去看它头上标注的@Qualifier注解 if (method == null || void.class == method.getReturnType()) { match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations()); } } } } return match; } ... 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; } ... // 标注的所有注解里是否在qualifierTypes集合里,当然了默认我们可以理解是否有@Qualifier这个注解~ public boolean hasQualifier(DependencyDescriptor descriptor) { for (Annotation ann : descriptor.getAnnotations()) { if (isQualifier(ann.annotationType())) { return true; } } return false; } /** * Determine whether the given dependency declares an autowired annotation, * checking its required flag. * @see Autowired#required() */ @Override public boolean isRequired(DependencyDescriptor descriptor) { if (!super.isRequired(descriptor)) { return false; } Autowired autowired = descriptor.getAnnotation(Autowired.class); return (autowired == null || autowired.required()); } // @since 3.0 这是本类的另外一个核心 解析@Value注解 // 需要注意的是此类它不负责解析占位符啥的 只复杂把字符串返回 // 最终是交给value = evaluateBeanDefinitionString(strVal, bd);它处理~~~ @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; } }
这个注解的功能已经非常强大了,Spring4.0之前都是使用的它去解决候选、依赖问题,但也不建议直接使用,因为下面这个,也就是它的子类更为强大~
ContextAnnotationAutowireCandidateResolver
官方把这个类描述为:策略接口的完整实现。它不仅仅支持上面所有描述的功能,还支持@Lazy懒处理~~~(注意此处懒处理(延迟处理),不是懒加载~)
@Lazy一般含义是懒加载,它只会作用于BeanDefinition.setLazyInit()。而此处给它增加了一个能力:延迟处理(代理处理)
public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotationAutowireCandidateResolver { public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) { // 如果isLazy=true 那就返回一个代理,否则返回null // 相当于若标注了@Lazy注解,就会返回一个代理(当然@Lazy注解的value值不能是false) return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null); } // 这个比较简单,@Lazy注解标注了就行(value属性默认值是true) // @Lazy支持标注在属性上和方法入参上~~~ 这里都会解析 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; } @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 pf = new ProxyFactory(); pf.setTargetSource(ts); Class<?> dependencyType = descriptor.getDependencyType(); if (dependencyType.isInterface()) { pf.addInterface(dependencyType); } return pf.getProxy(beanFactory.getBeanClassLoader()); } }
它很好的用到了TargetSource这个接口,结合动态代理来支持到了@Lazy注解。
标注有@Lazy注解完成注入的时候,最终注入只是一个此处临时生成的代理对象,只有在真正执行目标方法的时候才会去容器内拿到真是的bean实例来执行目标方法。
通过@Lazy注解能够解决很多情况下的循环依赖问题,它的基本思想是先’随便’给你创建一个代理对象先放着,等你真正执行方法的时候再实际去容器内找出目标实例执行~
我们要明白这种解决问题的思路带来的好处是能够解决很多场景下的循环依赖问题,但是要知道它每次执行目标方法的时候都会去执行TargetSource.getTarget()方法,所以需要做好缓存,避免对执行效率的影响(实测执行效率上的影响可以忽略不计)
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- Spring5.0源码深度解析之Spring核心注解
- Spring5.0源码深度解析之Spring基于注解启动流程分析
- SpringMVC源码深度解析之SpringServletContainerInitializer原理分析
- SpringMVC源码深度解析之SpringServletContainerInitializer原理分析
- 【Spring】Spring的IOC(控制反转)/DI(依赖注入)原理(三):Spring启动加载配置文件源码分析
- Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源
- Spring对注解(Annotation)处理源码分析2——解析和注入注解配置的资源
- Spring 注解:@Autowired、@Controller、@Service 原理层面分析
- spring注解源码分析-解析和注入注解配置的资源
- Spring核心容器IOC原理实例解析
- Spring源码解析 - AbstractBeanFactory 实现接口与父类分析
- Spring注解@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier 解析
- Spring第七弹—依赖注入之注解方式注入及编码解析@Resource原理
- spring源码------@Conditional注解的解析Condition接口,以及springboot中的扩展
- java自定义注解原理深度解析
- Spring IoC和DI(反转控制和依赖注入)原理
- SpringBoot2 | Spring AOP 原理深度源码分析
- mycat 分页慢原理解析、mycat跨事务解惑、mycat注解调用存储过程分析
- Spring注解之@Lazy注解,源码分析和总结
- (八)Spring核心框架 - AOP的原理及源码解析