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

阳江网站建设 公司汝城网站建设

阳江网站建设 公司,汝城网站建设,管理咨询公司一般是做什么的,可以做公众号背景图的网站1.什么是循环依赖#xff1a; 这里给大家举个简单的例子#xff0c;相信看了上一篇文章大家都知道了解了spring的生命周期创建流程。那么在Spring在生命周期的哪一步会出现循环依赖呢#xff1f; 第一阶段#xff1a;实例化阶段 Instantiation 第二阶段#xff1a;属性赋…1.什么是循环依赖 这里给大家举个简单的例子相信看了上一篇文章大家都知道了解了spring的生命周期创建流程。那么在Spring在生命周期的哪一步会出现循环依赖呢 第一阶段实例化阶段 Instantiation 第二阶段属性赋值 Populate 第三阶段初始化阶段 Initialization 第四阶段销毁阶段 Destruction 首先在第一阶段实例化阶段会出现循环依赖。 Component public class TestService {private OrderService orderService;public void TestService(OrderService orderService){this.orderServiceorderService;} }----------------------------------- Component public class OrderService {private TestService testService;public void OrderService (TestService testService){this.testServicetestService;} }Spring在实例化阶段创建我们对象的时候是通过反射调用我们的构造方法进行创建。如果你没有写无参构造方法写了有参构造方法。那么spring就会调用你的有参构造方法进行创建对象。那么这个时候问题就来了 1.首先TestService 它的有参对象是OrderService这个时候spring就会对我的有参对象进行属性注入它就会去创建我们的OrderService 。 2.在创建OrderService 的时候发现orderService的构造方法有参是TestService 它又会去创建我们的TestService 。这个时候就会出现循环依赖TestService 依赖OrderService OrderService 依赖TestService 。 其次在第二阶属性赋值阶段也会出现循环依赖。 Component public class TestService {Autowiredprivate OrderService orderService;} -----------------------------------Component public class OrderService {Autowiredprivate TestService testService; } Spring在调用我们构造方法进行创建对象后就会进行属性赋值。 当我们注入TestService 时发现OrderService属性不在单例池中就会去创建OrderService。创建OrderService时发现OrderService也有属性需要注入就会去注入TestService 。这个时候也会出现魂环依赖问题。那么对于Spring来说它是怎么去解决这些循环依赖问题的呢 2.解决思路 下路就是循环依赖我画的简单流程图如果要解决循环依赖。我们怎么去解决呢 思路一 既然每次都要查看单例池存不存在那我实例化的时候就放入单例池中吗。这样不就可以解决循环依赖了吗。 假如你现在有两个线程在实例化阶段完成后你就把TestService放入单例池中这个时候线程二去单例池中获取TestService对象。线程二获取的是完整的spring对象吗并不是这个时候我们的TestService他没有走完我们的生命周期线程二它获取的会是TestService的普通对象如果在后面阶段TestService需要AOP呢Spring给它生成了代理对象。这个时候线程二就拿不到TestService的代理对象了。 思路二不能直接放入单例池中那么我就搞一个Set 集合每次实例化对象的时候就把BeanName存入集合当中表示这个对象正在创建中。为了解决代理对象问题我在生成一个map我们叫他earlySingletonObjects 。它用来存储我们的代理对象。 其实这样就可以解决循环依赖的问题了但是Spring在这方面没有这样实现。而是采用了另一种方法。因为这样违背了Spring设计原则。 Spring结合AOP跟Bean的生命周期是在Bean创建完全之后通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来完成的在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。如果出现了循环依赖那没有办法只有给Bean先创建代理但是没有出现循环依赖的情况下设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。 思路三在实例化后我在加入一个MapString, ObjectFactory? singletonFactories 的map每次实例化之后就把当前类存入map中等后面产生循环依赖时我先从earlySingletonObjects 中去找没有找到的话。我在去singletonFactories 中去找。 3.源码分析 首先在我们spring中有三级缓存 // 从上至下 分表代表这“三级缓存”//一级缓存 用于存放完全初始化好的 bean从该缓存中取出的 bean 可以直接使用private final MapString, Object singletonObjects new ConcurrentHashMap(256); //二级缓存 提前曝光的单例对象的cache存放原始的 bean 对象尚未填充属性用于解决循环依赖private final MapString, Object earlySingletonObjects new HashMap(16); // 三级缓存 单例对象工厂的cache存放 bean 工厂对象用于解决循环依赖private final MapString, ObjectFactory? singletonFactories new HashMap(16); 1. 在构造Bean对象之后将对象提前曝光到三级缓存中这时候曝光的对象仅仅是构造完成还没注入属性和初始化。 public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactoryimplements AutowireCapableBeanFactory {protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Nullable Object[] args)throws BeanCreationException { // 这里就是调用你的构造方法进行创建对象if (instanceWrapper null) {instanceWrapper createBeanInstance(beanName, mbd, args);}Object bean instanceWrapper.getWrappedInstance();// mbd.isSingleton() 判断对象是否是单例的// 当前对象是否允许循环依赖 this.allowCircularReferences 默认是true// isSingletonCurrentlyInCreation(beanName) 当前对象是否在创建中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);}// 循环依赖-添加到三级缓存中。value是lambda表达式这个时候并未执行addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean));}……} } 2. 提前曝光的对象被放入MapString, ObjectFactory? singletonFactories缓存中这里并不是直接将Bean放入缓存而是包装成ObjectFactory对象再放入。 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);// 从二级缓存中移除因为在spring中bean是单例的防止后面出现bug导致不是单例this.earlySingletonObjects.remove(beanName);// 将当前bean加入到set当中this.registeredSingletons.add(beanName);}}}3. 为什么要包装一层ObjectFactory对象 这里也就是Spring为什么采用第三级缓存的主要原因。 如果创建的Bean有对应的代理那其他对象注入时注入的应该是对应的代理对象但是Spring无法提前知道这个对象是不是有循环依赖的情况而正常情况下没有循环依赖情况Spring都是在创建好完成品Bean之后才创建对应的代理。这时候Spring有两个选择 1.不管有没有循环依赖都提前创建好代理对象并将代理对象放入缓存出现循环依赖时其他对象直接就可以取到代理对象并注入。 2.不提前创建好代理对象在出现循环依赖被其他对象注入时才实时生成代理对象。这样在没有循环依赖的情况下Bean就可以按着Spring设计原则的步骤来创建。 Spring选择了第二种方式那怎么做到提前曝光对象而又不生成代理呢 Spring就是在对象外面包一层ObjectFactory提前曝光的是ObjectFactory对象在被注入时才在ObjectFactory.getObject方式内实时生成代理对象并将生成好的代理对象放入到第二级缓存MapString, Object earlySingletonObjects。 protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject bean;if (!mbd.isSynthetic() hasInstantiationAwareBeanPostProcessors()) {for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {exposedObject bp.getEarlyBeanReference(exposedObject, beanName);}}return exposedObject;}为了防止对象在后面的初始化init时重复代理在创建代理时earlyProxyReferences缓存会记录已代理的对象。 Overridepublic Object getEarlyBeanReference(Object bean, String beanName) {Object cacheKey getCacheKey(bean.getClass(), beanName);this.earlyProxyReferences.put(cacheKey, bean);return wrapIfNecessary(bean, beanName, cacheKey);} 在这里spring会创建对象判断你是否需要代理是否创建代理对象。 protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// Create proxy if we have advice.Object[] specificInterceptors getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors ! DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);Object proxy createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}也可以理解为三级缓存的ObjectFactory其实在做的是一种缓存机制当我们后面初始化需要代理时Spring就会先从这个缓存中去拿代理对象拿得到就不创建代理对象而是使用这个代理对象。 4. 注入属性和初始化 Spring会调用populateBean进行属性注入然后该对象在单例池中就直接从单例池拿不在就进行对象的创建并注入。 public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactoryimplements AutowireCapableBeanFactory {protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Nullable Object[] args)throws BeanCreationException {……// Initialize the bean instance.Object exposedObject bean;try {// 注入属性populateBean(beanName, mbd, instanceWrapper);exposedObject initializeBean(beanName, exposedObject, mbd);}catch (Throwable ex) {if (ex instanceof BeanCreationException beanName.equals(((BeanCreationException) ex).getBeanName())) {throw (BeanCreationException) ex;}else {throw new BeanCreationException(mbd.getResourceDescription(), beanName, Initialization of bean failed, ex);}}……} } 在进行对象创建过程中会调用getSingleton方法从缓存中获取注入对象 // 获取要注入的对象protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 先从单例池一级缓存中拿看能不能获取beanObject singletonObject this.singletonObjects.get(beanName);// 如果单例池拿的是空并且正在创建中if (singletonObject null isSingletonCurrentlyInCreation(beanName)) {// 那么就在从二级缓存中去拿singletonObject this.earlySingletonObjects.get(beanName);// 如果二级缓存中没有就加锁在进行判断if (singletonObject null allowEarlyReference) {synchronized (this.singletonObjects) {// 如果一级缓存还是没有singletonObject this.singletonObjects.get(beanName);if (singletonObject null) {// 就找二级缓存 singletonObject this.earlySingletonObjects.get(beanName);if (singletonObject null) {// 二级缓存还是没有就找三级缓存ObjectFactory? singletonFactory this.singletonFactories.get(beanName);if (singletonFactory ! null) {// 三级缓存获取到了这时三级缓存会执行lambad表达式并创建普通对象或者代理对象singletonObject singletonFactory.getObject();// 把获取到的对象放入二级缓存中this.earlySingletonObjects.put(beanName, singletonObject);// 从三级缓存删除该对象防止lambad表达式重复执行防止出现bug让spring不能保证单例this.singletonFactories.remove(beanName);}}}}}}return singletonObject;}5.放入已完成创建的单例缓存中 最终Spring会通过addSingleton方法将最终生成的可用的Bean放入到单例缓存里。 /*** Add the given singleton object to the singleton cache of this factory.* pTo be called for eager registration of singletons.* param beanName the name of the bean* param singletonObject the singleton object*/protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {// 将创建好的bean放入一级缓存单例池中this.singletonObjects.put(beanName, singletonObject);// 删除三级缓存this.singletonFactories.remove(beanName);// 删除二级缓存this.earlySingletonObjects.remove(beanName);// 放入已注册实例的Set集合当中this.registeredSingletons.add(beanName);}}总结 1.Spring有哪三级缓存 // 从上至下 分表代表这“三级缓存”//一级缓存 用于存放完全初始化好的 bean从该缓存中取出的 bean 可以直接使用private final MapString, Object singletonObjects new ConcurrentHashMap(256); //二级缓存 提前曝光的单例对象的cache存放原始的 bean 对象尚未填充属性用于解决循环依赖private final MapString, Object earlySingletonObjects new HashMap(16); // 三级缓存 单例对象工厂的cache存放 bean 工厂对象用于解决循环依赖private final MapString, ObjectFactory? singletonFactories new HashMap(16); 2.只要二级缓存不要三级缓存可不可以。 其实我试验过用二级缓存也可以达到和三级缓存同样的效果。只不过为了不违背Spring设计原则Spring采用了三级缓存。 Spring结合AOP跟Bean的生命周期是在Bean创建完全之后通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来完成的在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。如果出现了循环依赖那没有办法只有给Bean先创建代理但是没有出现循环依赖的情况下设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。 3. Spring三级缓存完整流程思路 实例化普通对象UserService 对象U将普通对象U加入Set集合判断是不是在创建中将对象U加入三级缓存 U注入属性OrderService对象O发现O不在创建中实例化普通对象OrderService 对象O将对象O加入Set集合用于判断是不是在创建中将对象O加入三级缓存。 O注入属性U发现对象U在创建中循环依赖在一级缓存中找没找到在二级缓存中找没找到在三级缓存中找到了创建对象U的代理对象。将代理对象加入二级缓存并在三级缓存中进行remove将U的代理对象注入给O 注入完属性后就进行初始化等操作完成对象的创建。将O注入到一级缓存中从二级三级缓存删除O对象。 O对象创建完成后U对象就注入属性O的代理对象U在完成初始化等操作最后将U注入到一级缓存中从二级三级缓存删除O对象。
http://www.sczhlp.com/news/162984/

相关文章:

  • 男女做污的事情网站php网站开发工程师找工作
  • 铁岭网站开发华为商城官网手机版app
  • 营销型网站建设策划书怎么写腾讯企点app
  • 建设网站需要支付什么插件费用吗行政单位建设网站方案
  • 网站集约化建设工作打算网页设计目的怎么写
  • 济阳做网站多少钱最爱网
  • 会展网站建设阿里云邮箱企业版登录
  • 自己建设网站平台步骤开源商城app源码
  • 公司网站首页设计模板佛山网络公司 乐云seo
  • 观山湖网站建设dw网站指向邮箱超链接怎么做
  • 简单的个人主页网站制作网络营销策划的定义
  • 公司创建网站多少钱服装商城的网站建设
  • 电子政务网站建设方案品牌营销策划是什么意思
  • 如何查询网站二级页面流量html做企业门户网站
  • 江苏省 建设 注册中心网站首页营销型网站建设合同模板
  • 厦门市建设执业资格注册管理中心网站青岛网页制作设计营销
  • 企业级建站郑州发布
  • 网站的原型图网络营销服务公司
  • 建设在线购物网站ftp 修改网站
  • 网站建设表格的属性建设网站多少钱 郑州
  • 东昌府企业做网站推广网站域名后缀代表什么意思
  • 顺德网站建设公司信息python怎么学
  • 电子商务网站建设大作业无锡电子商城网站设计
  • 网站建设是什么部门宝宝个人网站模板
  • 民宿网站建设怎么自己做购物网站
  • 网站开发选择题网站的基础知识
  • linux jenkins服务启动异常等,排查是否日志磁盘空间满 du df命令
  • 详细介绍:LeetCode 391 完美矩形
  • [NOI2025] 集合 题解
  • 重庆网站建设平台网站建设中怎么解决