加入收藏 | 设为首页 | 会员中心 | 我要投稿 鞍山站长网 (https://www.0412zz.com/)- 应用安全、运维、云计算、5G、云通信!
当前位置: 首页 > 综合聚焦 > 移动互联 > 评测 > 正文

Springboot源码分析之Spring循环依赖揭秘

发布时间:2019-09-09 13:11:44 所属栏目:评测 来源:佚名
导读:摘要: 若你是一个有经验的程序员,那你在开发中必然碰到过这种现象:事务不生效。或许刚说到这,有的小伙伴就会大惊失色了。 Spring 不是解决了循环依赖问题吗,它是怎么又会发生循环依赖的呢?,接下来就让我们一起揭秘 Spring 循环依赖的最本质原因。 S

@Lazy 一般含义是懒加载,它只会作用于 BeanDefinition.setLazyInit() 。而此处给它增加了一个能力:延迟处理(代理处理)

  1. // @since 4.0 出现得挺晚,它支持到了@Lazy  是功能最全的AutowireCandidateResolver 
  2.     public class ContextAnnotationAutowireCandidateResolver extends QualifierAnnotationAutowireCandidateResolver { 
  3.         // 这是此类本身唯一做的事,此处精析  
  4.         // 返回该 lazy proxy 表示延迟初始化,实现过程是查看在 @Autowired 注解处是否使用了 @Lazy = true 注解  
  5.         @Override 
  6.         @Nullable 
  7.         public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, @Nullable String beanName) { 
  8.             // 如果isLazy=true  那就返回一个代理,否则返回null 
  9.             // 相当于若标注了@Lazy注解,就会返回一个代理(当然@Lazy注解的value值不能是false) 
  10.             return (isLazy(descriptor) ? buildLazyResolutionProxy(descriptor, beanName) : null); 
  11.         } 
  12.      
  13.         // 这个比较简单,@Lazy注解标注了就行(value属性默认值是true) 
  14.         // @Lazy支持标注在属性上和方法入参上~~~  这里都会解析 
  15.         protected boolean isLazy(DependencyDescriptor descriptor) { 
  16.             for (Annotation ann : descriptor.getAnnotations()) { 
  17.                 Lazy lazy = AnnotationUtils.getAnnotation(ann, Lazy.class); 
  18.                 if (lazy != null && lazy.value()) { 
  19.                     return true; 
  20.                 } 
  21.             } 
  22.             MethodParameter methodParam = descriptor.getMethodParameter(); 
  23.             if (methodParam != null) { 
  24.                 Method method = methodParam.getMethod(); 
  25.                 if (method == null || void.class == method.getReturnType()) { 
  26.                     Lazy lazy = AnnotationUtils.getAnnotation(methodParam.getAnnotatedElement(), Lazy.class); 
  27.                     if (lazy != null && lazy.value()) { 
  28.                         return true; 
  29.                     } 
  30.                 } 
  31.             } 
  32.             return false; 
  33.         } 
  34.      
  35.         // 核心内容,是本类的灵魂~~~ 
  36.         protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) { 
  37.             Assert.state(getBeanFactory() instanceof DefaultListableBeanFactory, 
  38.                     "BeanFactory needs to be a DefaultListableBeanFactory"); 
  39.      
  40.             // 这里毫不客气的使用了面向实现类编程,使用了DefaultListableBeanFactory.doResolveDependency()方法~~~ 
  41.             final DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) getBeanFactory(); 
  42.      
  43.             //TargetSource 是它实现懒加载的核心原因,在AOP那一章节了重点提到过这个接口,此处不再叙述 
  44.             // 它有很多的著名实现如HotSwappableTargetSource、SingletonTargetSource、LazyInitTargetSource、 
  45.             //SimpleBeanTargetSource、ThreadLocalTargetSource、PrototypeTargetSource等等非常多 
  46.             // 此处因为只需要自己用,所以采用匿名内部类的方式实现~~~ 此处最重要是看getTarget方法,它在被使用的时候(也就是代理对象真正使用的时候执行~~~) 
  47.             TargetSource ts = new TargetSource() { 
  48.                 @Override 
  49.                 public Class<?> getTargetClass() { 
  50.                     return descriptor.getDependencyType(); 
  51.                 } 
  52.                 @Override 
  53.                 public boolean isStatic() { 
  54.                     return false; 
  55.                 } 
  56.          
  57.                 // getTarget是调用代理方法的时候会调用的,所以执行每个代理方法都会执行此方法,这也是为何doResolveDependency 
  58.                 // 我个人认为它在效率上,是存在一定的问题的~~~所以此处建议尽量少用@Lazy~~~    
  59.                 //不过效率上应该还好,对比http、序列化反序列化处理,简直不值一提  所以还是无所谓  用吧 
  60.                 @Override 
  61.                 public Object getTarget() { 
  62.                     Object target = beanFactory.doResolveDependency(descriptor, beanName, null, null); 
  63.                     if (target == null) { 
  64.                         Class<?> type = getTargetClass(); 
  65.                         // 对多值注入的空值的友好处理(不要用null) 
  66.                         if (Map.class == type) { 
  67.                             return Collections.emptyMap(); 
  68.                         } else if (List.class == type) { 
  69.                             return Collections.emptyList(); 
  70.                         } else if (Set.class == type || Collection.class == type) { 
  71.                             return Collections.emptySet(); 
  72.                         } 
  73.                         throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(), 
  74.                                 "Optional dependency not present for lazy injection point"); 
  75.                     } 
  76.                     return target; 
  77.                 } 
  78.                 @Override 
  79.                 public void releaseTarget(Object target) { 
  80.                 } 
  81.             };    
  82.      
  83.             // 使用ProxyFactory  给ts生成一个代理 
  84.             // 由此可见最终生成的代理对象的目标对象其实是TargetSource,而TargetSource的目标才是我们业务的对象 
  85.             ProxyFactory pf = new ProxyFactory(); 
  86.             pf.setTargetSource(ts); 
  87.             Class<?> dependencyType = descriptor.getDependencyType(); 
  88.              
  89.             // 如果注入的语句是这么写的private AInterface a;  那这类就是借口 值是true 
  90.             // 把这个接口类型也得放进去(不然这个代理都不属于这个类型,反射set的时候岂不直接报错了吗????) 
  91.             if (dependencyType.isInterface()) { 
  92.                 pf.addInterface(dependencyType); 
  93.             } 
  94.             return pf.getProxy(beanFactory.getBeanClassLoader()); 
  95.         } 
  96.     } 

(编辑:鞍山站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读