当前位置: 首页 > news >正文

微网站建设合同网站管理与建设

微网站建设合同,网站管理与建设,长沙seo公司排名,小程序图片制作文章目录一、什么是循环依赖1、代码实例2、重要信息二、源码分析1、初始化Student对Student中的ClassRoom进行Autowire操作2、Student的自动注入ClassRoom时#xff0c;又对ClassRoom的初始化3、ClassRoom的初始化#xff0c;又执行自动注入Student的逻辑4、Student注入Class… 文章目录一、什么是循环依赖1、代码实例2、重要信息二、源码分析1、初始化Student对Student中的ClassRoom进行Autowire操作2、Student的自动注入ClassRoom时又对ClassRoom的初始化3、ClassRoom的初始化又执行自动注入Student的逻辑4、Student注入ClassRoom5、初始化完成的Bean放入一级缓存三、总结1、二级缓存的用处2、汇总流程图参考资料一、什么是循环依赖 多个bean之间相互依赖形成了一个闭环。 比如:A依赖于B、B依赖于C、C依赖于A。 注意这里不是函数的循环调用是对象的相互依赖关系。循环调用其实就是一个死循环除非有终结条件。 1、代码实例 public class ClassRoom {private String name;Autowiredprivate CollectionStudent students;// get set }public class Student {private Long id;private String name;Autowiredprivate ClassRoom classRoom;// get set }public class CircularReferencesDemo {public static void main(String[] args) {AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext();// 注册 Configuration Classcontext.register(CircularReferencesDemo.class);// 如果设置为 false则抛出异常信息如currently in creation: Is there an unresolvable circular reference?// 默认值为 truecontext.setAllowCircularReferences(true);// 启动 Spring 应用上下文context.refresh();System.out.println(Student : context.getBean(Student.class));System.out.println(ClassRoom : context.getBean(ClassRoom.class));// 关闭 Spring 应用上下文context.close();}Beanpublic static Student student() {Student student new Student();student.setId(1L);student.setName(张三);return student;}Beanpublic static ClassRoom classRoom() {ClassRoom classRoom new ClassRoom();classRoom.setName(C122);return classRoom;} } 我们看到以上实例ClassRoom和Student是互相依赖的。 Spring默认是打开处理循环依赖的开关的我们可以使用setAllowCircularReferences方法手动设置关闭循环依赖。 开启解决循环依赖之后以上代码是可以执行没有问题的。关闭循环依赖以上就会出现循环依赖的异常如果确认项目中没有循环依赖的问题可以关闭以提高性能。 2、重要信息 本文的源码都是基于Spring5.2.2版本进行分析的其他版本或许有些许出入但是差别不大。 本文所说的循环引用都是指的是单例Bean原型Bean不在此分析中。 阅读本文需要明白一些前置知识点 1单例的Bean初始化时机-finishBeanFactoryInitialization方法执行时 Spring应用上下文生命周期详解及源码分析Spring IOC容器启动及关闭过程超详细解释上 2Bean的生命周期需要熟悉 Spring Bean生命周期——从源码角度详解Spring Bean的生命周期上 Spring Bean生命周期——从源码角度详解Spring Bean的生命周期下 3Autowire注入流程 Autowire源码分析Autowire是怎么实现依赖注入的 二、源码分析 我们先从IOC容器启动时执行的finishBeanFactoryInitialization方法开始入口此方法是单例Bean的创建入口然后执行preInstantiateSingletons方法正是开始创建单例Bean。 // org.springframework.context.support.AbstractApplicationContext#refresh Override public void refresh() throws BeansException, IllegalStateException {// 省略上面代码// Instantiate all remaining (non-lazy-init) singletons.// 关键方法完成BeanFactory的初始化finishBeanFactoryInitialization(beanFactory); // 省略下面代码// org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// 省略上面代码// Instantiate all remaining (non-lazy-init) singletons.// 关键方法初始化单例的BeanbeanFactory.preInstantiateSingletons(); }preInstantiateSingletons方法在DefaultListableBeanFactory中进行了实现。 // org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons Override public void preInstantiateSingletons() throws BeansException {// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() bd.isSingleton() !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean getBean(FACTORY_BEAN_PREFIX beanName);if (bean instanceof FactoryBean) {final FactoryBean? factory (FactoryBean?) bean;boolean isEagerInit;if (System.getSecurityManager() ! null factory instanceof SmartFactoryBean) {isEagerInit AccessController.doPrivileged((PrivilegedActionBoolean)((SmartFactoryBean?) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit (factory instanceof SmartFactoryBean ((SmartFactoryBean?) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else { // 关键方法获取Bean的入口getBean(beanName);}}}// 省略下面代码1、初始化Student 第一个首先是初始化我们的Student类getBean会调用doGetBean然后调用getSingleton方法重点解决循环依赖最重要的三级缓存 // org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean) Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject this.singletonObjects.get(beanName); // 一级缓存if (singletonObject null isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject this.earlySingletonObjects.get(beanName); // 二级缓存if (singletonObject null allowEarlyReference) {ObjectFactory? singletonFactory this.singletonFactories.get(beanName); // 三级缓存if (singletonFactory ! null) {singletonObject singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject; }第一次调用getSingleton方法不会获取到Bean获取的是null走下面的单例bean创建逻辑 // org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean// 省略上面代码 // Create bean instance. if (mbd.isSingleton()) {sharedInstance getSingleton(beanName, () - {try {return createBean(beanName, mbd, args); // 关键方法创建Bean开始正式进入Bena的生命周期}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});bean getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }// 省略下面代码createBean方法会调用doCreateBean方法doCreateBean方法会创建bean的实例然后完成属性的初始化Autowire还未开始然后会判断如果该Bean正在创建就会调用addSingletonFactory方法 // org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean// 省略上面创建bean的实例然后完成属性的初始化Autowire还未开始的代码 // Eagerly cache singletons to be able to resolve circular references // even when triggered by lifecycle interfaces like BeanFactoryAware. boolean earlySingletonExposure (mbd.isSingleton() this.allowCircularReferences isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace(Eagerly caching bean beanName to allow for resolving potential circular references);}addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean)); }// 省略下面Autowire的代码我们会发现此处对allowCircularReferences 进行了判断假如说我们打开了循环依赖的开关会走这个逻辑。 addSingletonFactory方法通过传入的单例对象工厂 // org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory protected void addSingletonFactory(String beanName, ObjectFactory? singletonFactory) {Assert.notNull(singletonFactory, Singleton factory must not be null);synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) { // 判断一级缓存如果不存在this.singletonFactories.put(beanName, singletonFactory); // 放入三级缓存this.earlySingletonObjects.remove(beanName); // 从二级缓存删掉其实并没有this.registeredSingletons.add(beanName); // 放入正在注册的单例Bean列表}} }我们注意到此时Student中的classRoom并没有被注入但是id和name属性已经被初始化了。 对Student中的ClassRoom进行Autowire操作 我们回到doCreateBean方法接下来会执行populateBean初始化属性值会调用Autowire的处理类AutowiredAnnotationBeanPostProcessor的postProcessProperties方法进行处理Autowire注入。 // populateBean方法此处省略部分代码PropertyDescriptor[] filteredPds null; if (hasInstAwareBpps) {if (pvs null) {pvs mbd.getPropertyValues();}for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp (InstantiationAwareBeanPostProcessor) bp;// 关键方法最终调用AutowiredAnnotationBeanPostProcessor的postProcessPropertiesPropertyValues pvsToUse ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse null) {if (filteredPds null) {filteredPds filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}pvsToUse ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse null) {return;}}pvs pvsToUse;}} }// org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {InjectionMetadata metadata findAutowiringMetadata(beanName, bean.getClass(), pvs);try {metadata.inject(bean, beanName, pvs); // 关键方法}catch (BeanCreationException ex) {throw ex;}catch (Throwable ex) {throw new BeanCreationException(beanName, Injection of autowired dependencies failed, ex);}return pvs; }// org.springframework.beans.factory.annotation.InjectionMetadata#inject public void inject(Object target, Nullable String beanName, Nullable PropertyValues pvs) throws Throwable {CollectionInjectedElement checkedElements this.checkedElements;CollectionInjectedElement elementsToIterate (checkedElements ! null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {for (InjectedElement element : elementsToIterate) {if (logger.isTraceEnabled()) {logger.trace(Processing injected element of bean beanName : element);}element.inject(target, beanName, pvs); // 关键方法}} }inject方法此处需要自动注入的是属性需要获取该属性的value值也就是ClassRoom此时ClassRoom尚未初始化。 // org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject // 此处省略部分源码 try {// value就是需要获取的ClassRoomvalue beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); }// org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency Override Nullable public Object resolveDependency(DependencyDescriptor descriptor, Nullable String requestingBeanName,Nullable SetString autowiredBeanNames, Nullable TypeConverter typeConverter) throws BeansException {descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());if (Optional.class descriptor.getDependencyType()) {return createOptionalDependency(descriptor, requestingBeanName);}else if (ObjectFactory.class descriptor.getDependencyType() ||ObjectProvider.class descriptor.getDependencyType()) {return new DependencyObjectProvider(descriptor, requestingBeanName);}else if (javaxInjectProviderClass descriptor.getDependencyType()) {return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);}else {Object result getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(descriptor, requestingBeanName);if (result null) {// 关键代码会走该逻辑result doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);}return result;} }// doResolveDependency方法省略部分源码会调用resolveCandidate if (instanceCandidate instanceof Class) {instanceCandidate descriptor.resolveCandidate(autowiredBeanName, type, this); }resolveCandidate会执行beanFactory.getBean方法又开始了对ClassRoom的getBean操作开始处理ClassRoom。 // public Object resolveCandidate(String beanName, Class? requiredType, BeanFactory beanFactory)throws BeansException {return beanFactory.getBean(beanName); }2、Student的自动注入ClassRoom时又对ClassRoom的初始化 我们跳过上面的分析来到addSingletonFactory方法 我们发现又将ClassRoom放入了三级缓存此时三级缓存中有了Student和ClassRoom但是都没有完成对ClassRoom和Student的自动注入工作。 3、ClassRoom的初始化又执行自动注入Student的逻辑 此时我们来到ClassRoom的populateBean属性初始化方法仍然调用AutowiredAnnotationBeanPostProcessor的postProcessProperties方法来完成对Student的自动注入。 省略我们分析Student的自动注入步骤我们继续分析自动注入的过程仍然会调用resolveDependency方法然后调用doResolveDependency方法然后调用resolveCandidate方法又通过beanFactory.getBean来获取Student。 还记得我们上面分析的doGetBean方法中调用的getSingleton方法的逻辑此时从三级缓存中已经能够获取到Student了但是该Student的ClassRoom仍然是null的但是能够获取到Studen实例并不影响我们ClassRoom对Student的注入 // org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean protected T T doGetBean(final String name, Nullable final ClassT requiredType,Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {final String beanName transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.// 关键方法Object sharedInstance getSingleton(beanName);if (sharedInstance ! null args null) {if (logger.isTraceEnabled()) {if (isSingletonCurrentlyInCreation(beanName)) {logger.trace(Returning eagerly cached instance of singleton bean beanName that is not fully initialized yet - a consequence of a circular reference);}else {logger.trace(Returning cached instance of singleton bean beanName );}}bean getObjectForBeanInstance(sharedInstance, name, beanName, null);}从三级缓存中获取到Student后将Student从三级缓存移出放入二级缓存。 此时在ClassRoom的初始化自动注入Student的过程获取到了我们的Student还未注入CLassRoom在Inject方法中继续执行会发现通过反射将Student写入了ClassRoom的属性。 // org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject Override protected void inject(Object bean, Nullable String beanName, Nullable PropertyValues pvs) throws Throwable {Field field (Field) this.member;Object value;if (this.cached) {value resolvedCachedArgument(beanName, this.cachedFieldValue);}else {DependencyDescriptor desc new DependencyDescriptor(field, this.required);desc.setContainingClass(bean.getClass());SetString autowiredBeanNames new LinkedHashSet(1);Assert.state(beanFactory ! null, No BeanFactory available);TypeConverter typeConverter beanFactory.getTypeConverter();try {value beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);}catch (BeansException ex) {throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);}synchronized (this) {if (!this.cached) {if (value ! null || this.required) {this.cachedFieldValue desc;registerDependentBeans(beanName, autowiredBeanNames);if (autowiredBeanNames.size() 1) {String autowiredBeanName autowiredBeanNames.iterator().next();if (beanFactory.containsBean(autowiredBeanName) beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {this.cachedFieldValue new ShortcutDependencyDescriptor(desc, autowiredBeanName, field.getType());}}}else {this.cachedFieldValue null;}this.cached true;}}}if (value ! null) {ReflectionUtils.makeAccessible(field);field.set(bean, value); // 通过反射写入属性} } 此时完成了ClassRoom的初始化。 4、Student注入ClassRoom 此时ClassRoom在Student初始化过程完成了初始化并注入Student实例此时的Student还没有完成对ClassRoom的注入呢 我们又回到Student的inject方法了此时相当于是一个递归的过程。 对ClassRoom的create的过程会返回创建好的ClassRoom实例初始化完成也注入完成正好将ClassRoom注入到Student中。 此时完成对Student和ClassRoom的初始化过程。 也正式解决了Student和ClassRoom的循环依赖问题。 5、初始化完成的Bean放入一级缓存 我们再次回到doGetBean方法这里调用了getSingleton方法getSingleton方法最后面的finally中会调用addSingleton方法。 // Create bean instance. if (mbd.isSingleton()) {sharedInstance getSingleton(beanName, () - {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});bean getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }addSingleton方法会将Bean放入一级缓存同时删除二级缓存和三级缓存中的Bean此时Bean初始化完成同时也缓存完成下次获取Bean直接从一级缓存获取即可提高性能。 // org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);} }关于Bean的缓存请移步 Spring中Bean会被缓存吗Spring的Bean是如何被缓存的 三、总结 Spring解决循环依赖正式靠着这三级缓存完成的相当于一个递归初始化的过程 在 Spring 底层 IoC 容器 BeanFactory 中处理循环依赖的方法主要借助于以下 3 个 Map 集合 singletonObjects一级 Map里面保存了所有已经初始化好的单例 BeanearlySingletonObjects二级 Map里面会保存从 三级 Map 获取到的正在初始化的 Bean保存的同时会移除 三级 Map 中对应的 ObjectFactory 实现类在完全初始化好某个 Bean 时会移除 二级 Map中对应的早期对象singletonFactories三级 Map里面保存了正在初始化的 Bean 对应的 ObjectFactory 实现类调用其 getObject() 方法返回正在初始化的 Bean 对象仅实例化还没完全初始化好 而这三个缓存其实也就是人们称的三级缓存其实严格意义上并不能称为“缓存”这三个缓存其实都是Map 1、二级缓存的用处 此处解决循环依赖似乎并没有用到二级缓存那么二级缓存是哪里用到的呢 因为通过 三级 Map获取 Bean 会有相关 SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference 的处理避免重复处理。 例如在循环依赖中一个 Bean 可能被多个 Bean 依赖 A - B也依赖 A - C - A当你获取 A 这个 Bean 时后续 B 和 C 都要注入 A没有上面的 二级 Map的话三级 Map 保存的 ObjectFactory 实现类会被调用两次会重复处理可能出现问题。这就是为什么需要 3 个 Map另外这样做在性能上也有所提升 。 也是为了处理AOP动态代理的问题也是一个对象被多个对象重复依赖导致重复创建的问题 假如 A 需要进行 AOP因为代理对象每次都是生成不同的对象如果干掉第二级缓存只有第一、三级缓存 B 找到 A 时直接通过三级缓存的工厂的代理对象生成对象 A1。 C 找到 A 时直接通过三级缓存的工厂的代理对象生成对象 A2。 看到问题没你通过 A 的工厂的代理对象生成了两个不同的对象 A1 和 A2所以为了避免这种问题的出现我们搞个二级缓存把 A1 存下来下次再获取时直接从二级缓存获取无需再生成新的代理对象。 2、汇总流程图 参考资料 spring如何解决循环依赖 源码深度解析Spring 如何解决循环依赖 极客时间《小马哥讲 Spring 核心编程思想》
http://www.hkea.cn/news/14432554/

相关文章:

  • 湘阴网站建设安装钢结构网架公司
  • 开发一个企业网站需要多少钱欧美做暧网站
  • 红色礼品网站模板外链生成
  • 响应式网站建设服务手机商店下载安装
  • 如此查询网站名字是否注册钻石网站建设
  • 西宁网站建设加q479185700违规网站备案
  • 中国建设银行安徽省 招聘信息网站phpwind8.7和wordpress
  • 海丰网站制作可以免费发广告的网站有哪些
  • 中国建设银行网站2017两学一做网站
  • h5能做网站开发吗现在都用什么软件做网站
  • 模板式自助建站wordpress动态主题
  • 网站没有做伪静态是什么样子十大美妆电商平台
  • 电子商务网站需要做那些准备工作wordpress 电子书模板
  • 沈阳网站推广公司排名著名的国外设计网站
  • 网站注册的账号怎么注销seo专业术语
  • 做一静态网站 多少钱百度seo排名主要看啥
  • 免费的产品展示小程序seo网站诊断
  • 公司网站建设的基本流程四川建设人才官方网站
  • 可以做设计的网站有哪些上海市中心
  • 福建示范校建设专题网站中国交通建设集团属于什么企业
  • 武安网站建设价格江门网站制作
  • 西安交易网站建设门户网站的大数据应用
  • 怎么仿网站链接网站栏目页面
  • 快速建网站软件响应式网站是做列表
  • pc网站如何做移动适配热点事件舆情分析报告
  • 网站用心邯郸市民网
  • phpcms v9网站建设入门湛江城乡建设网站
  • 中铁四局建筑公司网站佛山哪里做网站
  • 怎么注册网站挣流量扫二维码进入个人的购物网站如何做
  • 网站推广营销的步骤如何查询一个网站是那家公司做的