SOFABoot源码解析之JVM服务

SOFA RPC源码解析之RPC服务发布、引用、调用和响应流程 1. SOFA RPC源码解析 1.1 SOFA RPC服务发布、引用、调用和响应流程 1.1.1 服务发布流程    对于不同类型的SOFABoot服务,如Jvm服务、Rest服务、Bolt服务或Dubbo服务,服务发布的主流程如下:    1. 定义SOFABoot服务: 在SpringXML文件中使用标签sofa-service定义服务; 在Java类中使用注解@SofaSe... 阅读详情

1.SOFABoot源码解析

1.1  JVM服务

1.1.1 服务发布

        以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,详细描述SOFABoot JVM服务发布过程。

        在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。

        RPC案例的SpringXML配置文件内容如下:

1.  <?xml version="1.0"encoding="UTF-8"?>
2.  <beansxmlns="http://www.springframework.org/schema/beans"
3.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4.         xmlns:sofa="http://sofastack.io/schema/sofaboot"
5.         xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
6.              http://sofastack.io/schema/sofaboot  http://sofastack.io/schema/sofaboot.xsd"
7.         default-autowire="byName">
8.   
9.      <bean id="personServiceImpl"class="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonServiceImpl"/>
10.     
11.     <sofa:serviceref="personServiceImpl"interface="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService">       
12.         <sofa:binding.jvm/>
13.     </sofa:service>   
14.  
15.  <sofa:referenceid="personReferenceRest"interface="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService">
16.         <sofa:binding.jvm/>
17.     </sofa:reference>
18.  
19.     <bean id="personFilter"class="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonServiceFilter"/>
20.  
21. </beans>

        在SpringXML配置文件中:

        1.   通过XML元素bean定义PersonService接口实现类PersonServiceImpl;

        2.   通过XML元素sofa:service以jvm格式发布PersonService接口服务;

        启动本应用,启动流程在《启动原理》中已经详细描述,在此不再详述,直接从SpringXML配置文件加载Bean定义开始分析。

        一、   注册ServiceFactoryBean类对应的Bean定义

        调用AnnotationConfigEmbeddedWebApplicationContext(AbstractApplicationContext).refresh())方法刷新Spring应用上下文过程,通过invokeBeanFactoryPostProcessors(beanFactory)方法调用beanFactory中所有实现了BeanFactoryPostProcessor接口的类。当调用到ConfigurationClassPostProcessor类processConfigBeanDefinitions方法时,在循环处理@Configuration配置类过程中,调用ConfigurationClassBeanDefinitionReader类loadBeanDefinitions(configClasses)方法,处理解析完成的@Configuration配置类。此时,其中有一步是调用ConfigurationClassBeanDefinitionReader类loadBeanDefinitionsFromImportedResources(configClass.getImportedResources())方法,加载@ImportResource注解里面配置的SpringXML配置文件中定义的Bean。在这个方法中,使用XMLBeanDefinitionReader加载SpringXML配置文件中定义的Bean。

        接下来就是SpringXML配置文件中各种标签的解析过程。

        对于XML标签bean,由于是最基本的SpringXML标签,大家都比较熟悉了,在此不再详述。

        对于XML标签sofa:service,其处理过程如下:

        XMLBeanDefinitionReader类调用DefaultBeanDefinitionDocumentReader类registerBeanDefinitions方法注册Bean定义。

        DefaultBeanDefinitionDocumentReader类调用BeanDefinitionParserDelegate类parseCustomElement方法解析自定义的XML元素。

        在此,对于XML标签sofa:service,根据命名空间sofa对应的值http://sofastack.io/schema/sofaboot,在spring.handlers(此文件位于infra-sofa-boot-starter.jar)文件中,查找到XML标签的处理类SofaBootNamespaceHandler:

1.  http\://sofastack.io/schema/sofaboot=com.alipay.sofa.infra.config.spring.namespace.handler.SofaBootNamespaceHandler

        在SofaBootNamespaceHandler类中,调用findParserForElement方法,查找指定XML元素的解析类,此处service对应的BeanDefinitionParser解析类为com.alipay.sofa.runtime.spring.parser.ServiceDefinitionParser。

        使用ServiceDefinitionParser类把SpringXML配置文件中sofa:service标签定义的服务转换为ServiceFactoryBean,并注册到Spring应用上下文中。

        二、  创建ServiceFactoryBean类的实例

        调用AnnotationConfigEmbeddedWebApplicationContext(AbstractApplicationContext).refresh())方法刷新Spring应用上下文过程,通过finishBeanFactoryInitialization(beanFactory)方法实例化beanFactory中所有剩余的非延迟初始化的单例对象。

        当实例化ServiceFactoryBean时,由于ServiceFactoryBean实现了Initializing接口,所以在调用ServiceFactoryBean类的初始化方法时,会调用ServiceFactoryBean类的afterPropertiesSet方法,进行实例的初始化操作。

        到现在为止,开始JVM服务发布流程:

        1.   根据XML标签sofa:service所包含的子标签sofa:binding.*(一个或多个,此处是sofa:binding.jvm),解析出服务发布的类型,此处是jvm服务。

        2.   创建DefaultImplementation实例implementation,并设置其属性ref为SpringXML文件中sofa-service元素的ref属性中指定的接口实现,此处为SpringXML文件中id为personServiceImpl的com.alipay.sofa.boot.examples.demo.rpc.bean.PersonServiceImpl类的实例。

        3.   创建Service接口的实现ServiceImpl,其中,服务接口类型为com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService,接口模式为spring(表明此引用服务来自于SpringXML配置文件),target为ref(即id为personServiceImpl的PersonServiceImpl实例)。

        4.   如果解析出的bindings为空,则把JvmBinding增加到bindings列表中。此处,由于在SpringXML文件中只配置了binding.jvm,在第一步parseBindings方法中,由于jvm没有对应的BindingConverter实现,所以导致bindings为空。

        5.   把解析出的binding(此处为JvmBinding)增加到service实例的属性bindings列表中。

        6.   创建ServiceComponent实例componentInfo。

        7.   从sofaRuntimeContext实例中获取组件管理器实例componentManager,并调用其register方法注册刚才创建的服务组件componentInfo,具体注册操作在doRegister方法完成:

1.  private ComponentInfo doRegister(ComponentInfo ci) {
2.          ComponentName name = ci.getName();
3.          if (isRegistered(name)) {
4.              SofaLogger.error("Component was alreadyregistered: {0}", name);
5.              return getComponentInfo(name);
6.          }
7.   
8.          try {
9.              ci.register();
10.         } catch (Throwable e) {
11.             SofaLogger.error(e, "Failed toregister component: {0}", ci.getName());
12.             return null;
13.         }
14.  
15.         SofaLogger.info("Registeringcomponent: {0}", ci.getName());
16.  
17.         try {
18.             ComponentInfo old = registry.putIfAbsent(ci.getName(), ci);
19.             if (old != null) {
20.                 SofaLogger.error("Component wasalready registered: {0}", name);
21.                 return old;
22.             }
23.             if (ci.resolve()) {
24.                 typeRegistry(ci);
25.                 ci.activate();
26.             }
27.         } catch (Throwable e) {
28.             ci.exception(new Exception(e));
29.             SofaLogger.error(e, "Failed tocreate the component {0}", ci.getName());
30.         }
31.  
32.         return ci;
33.     }

  在组件管理器中注册组件的主要处理逻辑如下:

  • 获取组件名称,此处为service:com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService。
  • 判断组件管理器componentManager中是否存在指定名字的组件。如果有,则直接从组件管理器获取组件,并返回。如果没有,则继续注册流程。
  • 调用组件ServiceComponent类的register方法,更新组件状态为registered。
  • 把组件置入组件管理器的registry中(ConcurrentMap<ComponentName, ComponentInfo>)。
  • 调用组件ServiceComponent类的resolve方法,更新组件状态为resolved。
  • 把组件置入组件管理器的resolvedRegistry中(ConcurrentMap<ComponentType, Map<ComponentName,ComponentInfo>>)。
  • 调用组件ServiceComponent的activate方法,激活组件,并更新组件状态为activated。
1.      public void activate() throwsServiceRuntimeException {
2.   
3.          activateBinding();
4.          super.activate();
5.      }

    调用activateBinding方法,激活服务组件的所有Binding。

1.  private void activateBinding() {
2.   
3.          Object target = service.getTarget();
4.          ……略
5.          if (service.hasBinding()) {
6.              boolean allPassed = true;
7.              Set<Binding> bindings =service.getBindings();
8.              for(Binding binding : bindings) {
9.                  BindingAdapter<Binding>bindingAdapter = this.bindingAdapterFactory
10.                     .getBindingAdapter(binding.getBindingType());
11.  
12.                 if (bindingAdapter == null) {
13.                     throw newServiceRuntimeException(……略);
14.                 }
15.  
16.                 Object outBindingResult;
17.                 ……略
18.                 try {
19.                     outBindingResult =bindingAdapter.outBinding(service, binding, target,
20.                         getContext());
21.                 } catch (Throwable t) {
22.                     allPassed = false;
23.                    ……略
24.                     continue;
25.                 }
26.                 if(!Boolean.FALSE.equals(outBindingResult)) {
27.                     ……略
28.                 } else {
29.                     binding.setHealthy(false);
30.                     SofaLogger.info("<<Out Binding [{0}] Fails, Don't publish service - {1}.",
31.                         binding.getBindingType(),service);
32.                 }
33.             }
34.  
35.             if (!allPassed) {
36.                 throw new ServiceRuntimeException(……略);
37.             }
38.         }
39.  
40.         SofaLogger.info("Register Service- {0}", service);
41.     }

    activateBinding方法主要处理逻辑如下:

  • 获取服务的目标类target;
  • 依次遍历服务所有Binding,分别为每种Binding发布服务,具体过程如下:根据Binding类型(此处为jvm),获取BindingAdapter接口的实现,此处为:com.alipay.sofa.runtime.service.binding.JvmBindingAdapter。调用JvmBindingAdapter类outBinding方法,对外发布服务:
1.      public Object outBinding(Object contract,JvmBinding binding, Object target,
2.                               SofaRuntimeContextsofaRuntimeContext) {
3.          return null;
4.      }

        由于是JVM服务,即只在同一个JVM中同一个应用的不同模块之间可以访问,同一个JVM中不同应用及JVM外部应用无法访问,所以此处outBinding方法为空方法,不对外提供任何服务。

        由此可以看出,发布JVM服务只是把服务组件置入组件管理器的registry中(ConcurrentMap<ComponentName,ComponentInfo>),然后把服务组件的状态设置为activated,表示服务发布成功。

1.1.2 服务引用

        以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,详细描述SOFABoot JVM服务引用过程。

        在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。

        RPC案例的SpringXML配置文件内容如下:

1.  <?xml version="1.0"encoding="UTF-8"?>
2.  <beansxmlns="http://www.springframework.org/schema/beans"
3.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4.         xmlns:sofa="http://sofastack.io/schema/sofaboot"
5.         xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd
6.              http://sofastack.io/schema/sofaboot   http://sofastack.io/schema/sofaboot.xsd"
7.         default-autowire="byName">
8.   
9.      <beanid="personServiceImpl"class="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonServiceImpl"/>
10.     
11.     <sofa:serviceref="personServiceImpl"interface="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService">       
12.         <sofa:binding.jvm/>
13.     </sofa:service>   
14.  
15.  <sofa:referenceid="personReferenceRest"interface="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService">
16.         <sofa:binding.jvm/>
17.     </sofa:reference>
18.  
19.     <bean id="personFilter"class="com.alipay.sofa.boot.examples.demo.rpc.bean.PersonServiceFilter"/>
20.  
21. </beans>

        在SpringXML配置文件中:

        1.   通过XML元素bean定义PersonService接口实现类PersonServiceImpl;

        2.   通过XML元素sofa:reference引用jvm格式的PersonService接口服务;

        启动本应用,启动流程在《启动原理》中已经详细描述,在此不再详述,直接到从SpringXML配置文件加载Bean定义开始分析。

        一、   注册ReferenceFactoryBean类对应的Bean定义

        调用AnnotationConfigEmbeddedWebApplicationContext(AbstractApplicationContext).refresh())方法刷新Spring应用上下文过程,通过invokeBeanFactoryPostProcessors(beanFactory)方法调用beanFactory中所有实现了BeanFactoryPostProcessor接口的类。

        当调用到ConfigurationClassPostProcessor类processConfigBeanDefinitions方法时,在循环处理@Configuration配置类过程中,调用ConfigurationClassBeanDefinitionReader类loadBeanDefinitions(configClasses)方法,处理解析完成的@Configuration配置类。此时,其中有一步是调用ConfigurationClassBeanDefinitionReader类loadBeanDefinitionsFromImportedResources(configClass.getImportedResources())方法,加载@ImportResource注解里面配置的SpringXML配置文件中定义的Bean。在这个方法中,使用XMLBeanDefinitionReader加载SpringXML配置文件中定义的Bean。

        接下来就是SpringXML配置文件中各种标签的解析过程。

        对于XML标签bean,由于是最基本的SpringXML标签,大家都应用比较熟悉了,在此不再详述。

        对于XML标签sofa:reference,其处理过程如下:

        XMLBeanDefinitionReader类调用DefaultBeanDefinitionDocumentReader类registerBeanDefinitions方法注册Bean定义;

        DefaultBeanDefinitionDocumentReader类调用BeanDefinitionParserDelegate类parseCustomElement方法解析自定义的XML元素。

        在此,对于XML标签sofa:reference,根据命名空间sofa对应的值http://sofastack.io/schema/sofaboot,在spring.handlers(此文件位于infra-sofa-boot-starter.jar)文件中,查找到XML标签的处理类SofaBootNamespaceHandler:

1.  http\://sofastack.io/schema/sofaboot=com.alipay.sofa.infra.config.spring.namespace.handler.SofaBootNamespaceHandler

在SofaBootNamespaceHandler类中,调用findParserForElement方法,查找指定XML元素的解析类,此处service对应的BeanDefinitionParser解析类为com.alipay.sofa.runtime.spring.parser.ReferenceDefinitionParser。

使用ReferenceDefinitionParser类把SpringXML配置文件中sofa:reference标签定义的服务转换为ReferenceFactoryBean,并注册到Spring应用上下文中。

        二、   创建ReferenceFactoryBean类的实例

        调用AnnotationConfigEmbeddedWebApplicationContext(AbstractApplicationContext).refresh())方法刷新Spring应用上下文。

        当通过onRefresh() 方法调用createEmbeddedServletContainer方法,在调用DefaultListableBeanFactory类doGetBeanNamesForType(ResolvableType type, booleanincludeNonSingletons, boolean allowEagerInit)方法,获取类型为org.springframework.boot.context.embedded.EmbeddedServletContainerFactory的Bean名字时,会遍历beanFactory中所有beanDefinitionNames,判断每个beanName所代表的Bean定义RootBeanDefinition中beanClass是否与EmbeddedServletContainerFactory类型相匹配。当调用org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch方法判断名为personReferenceRest的BeanDefinition对应的实例与EmbeddedServletContainerFactory是否类型匹配。由于XML标签sofa:reference被解析为ReferenceFactoryBean类,该类实现了FactoryBean接口,表明其为工厂Bean,所以为了查看此工厂Bean创建的实例的具体类型,必须实例化此工厂Bean,即ReferenceFactoryBean。至此,又会调用AbstractBeanFactory的getObject方法,获取此ReferenceFactoryBean创建的具体实例。

        当实例化ReferenceFactoryBean时,由于ReferenceFactoryBean实现了Initializing接口,所以在调用ReferenceFactoryBean类的初始化方法时,会调用ReferenceFactoryBean类的afterPropertiesSet方法,进行实例的初始化操作。

        到现在为止,开始JVM服务引用流程:

        1.  根据XML标签sofa:reference所包含的子标签sofa:binding.*(一个或多个,此处是sofa:binding.jvm),解析出服务引用的类型,此处是jvm服务。

        2.  设置ReferenceFactoryBean的bindings属性。由于在SpringXML文件中只配置了binding.jvm,并且jvm没有对应的BindingConverter实现,所以bindings为空。

        3.  创建Reference接口的实现ReferenceImpl,其中,引用的服务接口类型为com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService,接口模式为spring(表明此引用服务来自于SpringXML配置文件),jvmFirst为true(表示优先使用JVM服务,即在同一个JVM内部同一个应用不同模块之间服务调用方式)。

        4.  如果bindings为空,则把JvmBinding增加到bindings;

        5.  把bindings中第一个Binding(此处为JvmBinding)增加到reference实例的属性bindings集合中。

        6.  调用ReferenceRegisterHelper类registerReference方法:

1.  public static ObjectregisterReference(Reference reference,
2.                                             BindingAdapterFactorybindingAdapterFactory,
3.                                             SofaRuntimePropertiessofaRuntimeProperties,
4.                                             SofaRuntimeContextsofaRuntimeContext) {
5.          Binding binding = (Binding)reference.getBindings().toArray()[0];
6.   
7.          if(!binding.getBindingType().equals(JvmBinding.JVM_BINDING_TYPE)
8.              &&!sofaRuntimeProperties.isDisableJvmFirst() && reference.isJvmFirst()) {
9.              reference.addBinding(new JvmBinding());
10.         }
11.  
12.         ComponentManager componentManager =sofaRuntimeContext.getComponentManager();
13.         ReferenceComponent referenceComponent =new ReferenceComponent(reference,
14.             new DefaultImplementation(),bindingAdapterFactory, sofaRuntimeProperties,
15.             sofaRuntimeContext);
16.  
17.         if(componentManager.isRegistered(referenceComponent.getName())) {
18.             returncomponentManager.getComponentInfo(referenceComponent.getName())
19.                 .getImplementation().getTarget();
20.         }
21.  
22.         ComponentInfo componentInfo =componentManager.registerAndGet(referenceComponent);
23.         return componentInfo.getImplementation().getTarget();
24.  
25.     }

    注册Reference组件的主要步骤:

  • 获取reference实例包含的binding,此处为JvmBinding类型;
  • 如果binding不是JvmBinding类型,disableJvmFirst属性为false(表明全局开启jvmFirst),jvmFirst为true,则增加JvmBinding到reference实例的属性bindings集合中。此处binding为JvmBinding,所以直接跳过,继续后续流程;
  • 从sofaRuntimeContext实例中获取组件管理器实例componentManager;
  • 创建ReferenceComponent实例;
  • 判断组件管理器componentManager中是否存在指定名字的组件,例如:名称为reference:com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService:#342780926,如果有,则直接从组件管理器获取组件,并返回组件的实现的代理。如果没有,则在组件管理器中注册刚才创建的ReferenceComponent实例。具体的组件注册在doRegister方法中实现:
1.  private ComponentInfodoRegister(ComponentInfo ci) {
2.          ComponentName name = ci.getName();
3.          if (isRegistered(name)) {
4.              SofaLogger.error("Componentwas already registered: {0}", name);
5.              return getComponentInfo(name);
6.          }
7.   
8.          try {
9.              ci.register();
10.         } catch (Throwable e) {
11.             SofaLogger.error(e, "Failed toregister component: {0}", ci.getName());
12.             return null;
13.         }
14.  
15.         SofaLogger.info("Registeringcomponent: {0}", ci.getName());
16.  
17.         try {
18.             ComponentInfo old = registry.putIfAbsent(ci.getName(), ci);
19.             if (old != null) {
20.                 return old;
21.             }
22.             if (ci.resolve()) {
23.                 typeRegistry(ci);
24.                 ci.activate();
25.             }
26.         } catch (Throwable e) {
27.              ……略
28.         }
29.  
30.         return ci;
31.     }

    在组件管理器中注册组件的主要过程如下:

  • 调用组件ComponentInfo类的register方法,更新组件状态为registered。
  • 把组件置入组件管理器的registry中(ConcurrentMap<ComponentName, ComponentInfo>)。
  • 调用组件ComponentInfo类的resolve方法,更新组件状态为resolved。
  • 把组件置入组件管理器的resolvedRegistry中(ConcurrentMap<ComponentType, Map<ComponentName,ComponentInfo>>)。
  • 调用组件ComponentInfo类的activate方法,激活组件,并更新组件状态为activated。
1.  public void activate() throwsServiceRuntimeException {
2.          if (reference.hasBinding()) {
3.              Binding candidate = null;
4.              Set<Binding> bindings =reference.getBindings();
5.              if (bindings.size() == 1) {
6.                  candidate =bindings.iterator().next();
7.              } else if (bindings.size() > 1){
8.                  Object backupProxy = null;
9.                  for (Binding binding :bindings) {
10.                     if(JvmBinding.JVM_BINDING_TYPE.getType().equals(binding.getName())) {
11.                         candidate = binding;
12.                     } else {
13.                         backupProxy = createProxy(reference, binding);
14.                     }
15.                 }
16.                 if (candidate != null) {
17.                     ((JvmBinding)candidate).setBackupProxy(backupProxy);
18.                 }
19.             }
20.  
21.             Object proxy = null;
22.             if (candidate != null) {
23.                 proxy = createProxy(reference, candidate);
24.             }
25.  
26.             this.implementation = newDefaultImplementation();
27.             implementation.setTarget(proxy);
28.         }
29.  
30.         super.activate();
31.         latch.countDown();
32.     }

    在ComponentInfo类activate方法中,主要处理逻辑如下:

  • 获取ReferenceImpl中所有Binding。

        此处需要注意的是,在rpc.xsd文件中,规定XML标签sofa-reference只能有0个或1个Binding子元素。其可选子元素:binding.jvm、binding.bolt、binding.rest、binding.dubbo。

        如果设置多个Binding子元素,则在实例化时抛异常。

        如果不设置Binding子元素,则默认为JvmBinding。

        这个隐含的规则从这部分代码中无法体现,但影响其下面的处理逻辑。

        由此可知,Binding的个数只能为1或2。

        当Binding的个数当为1时,则只能是JvmBinding或其他类型Binding之一。

        当Binding的个数当为2时,则只能是JvmBinding和其他类型Binding之一。

        在下述三种情况下,ReferenceImpl中所有Binding的个数为1:

        ★ 当未设置Binding子元素,而采用默认的JvmBinding;

        ★ 设置Binding子元素为JvmBinding;

        ★ 设置一个其他类型的Binding,但disableJvmFirst为false,并且jvmFirst为true。

        在下述情况下,ReferenceImpl中所有Binding的个数为2:

        ★ 设置一个其他类型的Binding,但disableJvmFirst为true,或jvmFirst为false。

  • 如果Binding个数为1,其处理逻辑为:

        ★ 设置candidate(候选Binding)为当前Binding;

  • 如果Binding个数为2,其处理逻辑为:

        ★ 如果Binding类型为jvm,则设置candidate为JvmBinding。

        ★ 如果Binding类型为其它类型的Binding,如RestBinding,则调用createProxy(reference,binding)方法,根据Binding类型创建代理对象。

        ★ 设置JvmBinding的备选代理对象(backupProxy)为刚才创建的其它类型Binding的代理对象。

  • 如果candidate不为null,则调用createProxy(reference,candidate)方法,为候选Binding(candidate)创建代理对象proxy。否则,proxy为null。
  • 创建DefaultImplementation实例,并设置ReferenceComponent实例target属性为刚才为candidate创建的代理对象proxy。

    上述逻辑稍微有点复杂,简单来说就是:

  • 在优先使用JVM服务的前提下,如果配置了一个其它类型的服务,如Rest服务,则把它作为JVM服务的备选服务。当JVM服务不可用时,使用备选服务。如果没有配置其它类型服务,则JVM服务没有备选服务,当JVM服务不可用时,则服务不可用,调用失败。
  • 在不优先使用JVM服务的前提下,则只能使用配置的其它类型的服务,如Rest服务。

    在此案例中,设置candidate为JvmBinding。由于只设置了JvmBinding,没有设置其它类型的Binding,所以JvmBinding的备选代理对象为null。这样当JvmBinding不可用时,无备选方案可用。

    在此,我们主要关注一下通过createProxy方法为JvmBinding创建代理对象的过程:

1.  private Object createProxy(Referencereference, Binding binding) {
2.          BindingAdapter<Binding>bindingAdapter = bindingAdapterFactory.getBindingAdapter(binding
3.              .getBindingType());
4.          ……略
5.          Object proxy;
6.          try {
7.              proxy = bindingAdapter.inBinding(reference,binding, sofaRuntimeContext);
8.          } finally {
9.              ……略
10.         return proxy;
11.     }

        根据Binding类型,通过BindingAdapterFactoryImpl类getBindingAdapter方法,获取指定Binding类型的Binding适配器,此处是JvmBindingAdapter。

        调用JvmBindingAdapter类inBinding方法创建代理对象:

1.      public Object inBinding(Object contract,JvmBinding binding,
2.                              SofaRuntimeContextsofaRuntimeContext) {
3.          return createServiceProxy((Contract)contract, binding, sofaRuntimeContext);
4.      }

        调用createServiceProxy方法:

1.  private Object createServiceProxy(Contractcontract, JvmBinding binding,
2.                                        SofaRuntimeContextsofaRuntimeContext) {
3.          ClassLoader newClassLoader;
4.          ClassLoader appClassLoader =sofaRuntimeContext.getAppClassLoader();
5.          Class<?> javaClass =contract.getInterfaceType();
6.   
7.          try {
8.              Class appLoadedClass =appClassLoader.loadClass(javaClass.getName());
9.   
10.             if (appLoadedClass == javaClass) {
11.                 newClassLoader =appClassLoader;
12.             } else {
13.                 newClassLoader =javaClass.getClassLoader();
14.             }
15.         } catch (ClassNotFoundException e) {
16.             newClassLoader =javaClass.getClassLoader();
17.         }
18.  
19.         ClassLoader oldClassLoader =Thread.currentThread().getContextClassLoader();
20.  
21.         try {
22.             Thread.currentThread().setContextClassLoader(newClassLoader);
23.             ServiceProxy handler = newJvmServiceInvoker(contract, binding, sofaRuntimeContext);
24.             ProxyFactory factory = newProxyFactory();
25.             if (javaClass.isInterface()) {
26.                 factory.addInterface(javaClass);
27.             } else {
28.                 factory.setTargetClass(javaClass);
29.                 factory.setProxyTargetClass(true);
30.             }
31.             factory.addAdvice(handler);
32.             return factory.getProxy();
33.         } finally {
34.             Thread.currentThread().setContextClassLoader(oldClassLoader);
35.         }
36.     }

    在createServiceProxy方法中,创建服务代理的主要步骤如下:

  • 从sofaRuntimeContext获取应用类加载器appClassLoader,此处为:sun.misc.Launcher$AppClassLoader实例;
  • 设置javaClass为入参contract的getInterfaceType方法返回的接口类型,此处为com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService;
  • 使用应用类加载器appClassLoader加载服务接口PersonService;
  • 设置newClassLoader为javaClass对应的Class对象的类加载器;
  • 设置oldClassLoader为当前线程的上下文类加载器;
  • 设置当前线程的上下文类加载器为newClassLoader;
  • 设置handler,此处为ServiceProxy抽象类的子类JvmServiceInvoker的实例。该类继了ServiceProxy,而ServiceProxy实现了org.aopalliance.intercept.MethodInterceptor接口,表示此处创建AOP代理的方法拦截器。该AOP代理拦截器拦截对proxyClass指定的接口(例如:com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService)的方法调用,具体流程在后面详述;
  • 创建AOP代理工厂类org.springframework.aop.framework.ProxyFactory的实例factory;
  • 配置factory:如果javaClass为接口,则factory的interfaces列表中增加javaClass。否则,设置factory的targetClass为javaClass,proxyTarget为true;
  • 把指定的AOP advice实例handler增加到advice链尾部;
  • 调用factory的getProxy方法,为指定服务创建AOP代理对象。由于目标类是接口,则使用JDK动态代理技术。Spring使用JDK来生成代理对象,具体的生成代码放在org.springframework.aop.framework.JdkDynamicAopProxy这个类中。JdkDynamicAopProxy 同时实现了AopProxy和InvocationHandler接口,InvocationHandler是JDK动态代理的核心,生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。invoke主流程可以简述为:获取可以应用到此方法上的通知链(InterceptorChain),如果有,则应用通知,并执行joinpoint;如果通知链为空,则直接反射执行joinpoint。

    关于AOP代理对象的更多细节,在此不详细描述,有兴趣的同学自己在网上查资料看看。

    至此,JvmBinding的AOP代理对象创建完毕,此代理对象的handler为JdkDynamicAopProxy,实现了PersonService接口。

    接下来,创建DefaultImplementation实例,并设置ReferenceComponent实例target属性为刚才创建的candidate代理对象。

    设置ReferenceFactoryBean的proxy为刚才创建的AOP代理对象。这样,当其它类引用某个服务的ReferenceFactoryBean类时,由于此类为工厂Bean,所以通过getObject方法获取的实际对象为AOP代理对象。这样对生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。

    至此,JvmBinding类型的服务的代理对象创建完成。

1.1.3  客户端调用

        当我们在SpringXML文件中使用sofa:reference引用服务以后,就可以在其它类中引用创建的指定接口的代理对象,并像调用本地Java类那样,调用接口的某个方法。

        以下通过在Spring应用上下文中按照名字personReferenceJvm查找com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService接口的代理对象,然后调用其sayName方法,描述客户端调用Jvm服务的流程:

1.  public static void main(String[] args)throws InterruptedException {
2.       
3.        ConfigurableApplicationContext ac =SpringApplication.run(SofaBootRpcDemoApplication.class, args);
4.       
5.        PersonService personService = (PersonService)ac.getBean("personReferenceJvm");
6.       
7.        personService.sayName("Mike");
8.   
9.      }

        通过ConfigurableApplicationContext类getBean方法,获取名字为personReferenceJvm的实例,此时返回PersonService接口的AOP代理对象。此代理对象的handler为JdkDynamicAopProxy,实现了PersonService接口。

1.  public Object invoke(Object proxy, Methodmethod, Object[] args) throws Throwable {
2.       MethodInvocationinvocation;
3.       ObjectoldProxy = null;
4.       booleansetProxyContext = false;
5.   
6.       TargetSourcetargetSource = this.advised.targetSource;
7.       Class<?>targetClass = null;
8.       Objecttarget = null;
9.   
10.      try{
11.          if(!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
12.              //The target does not implement the equals(Object) method itself.
13.              returnequals(args[0]);
14.          }
15.          elseif (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
16.              //The target does not implement the hashCode() method itself.
17.              returnhashCode();
18.          }
19.          elseif (method.getDeclaringClass() == DecoratingProxy.class) {
20.              //There is only getDecoratedClass() declared -> dispatch to proxy config.
21.              returnAopProxyUtils.ultimateTargetClass(this.advised);
22.          }
23.          elseif (!this.advised.opaque && method.getDeclaringClass().isInterface()&&
24.                  method.getDeclaringClass().isAssignableFrom(Advised.class)){
25.              //Service invocations on ProxyConfig with the proxy config...
26.              returnAopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
27.          }
28.  
29.          ObjectretVal;
30.  
31.          if(this.advised.exposeProxy) {
32.              //Make invocation available if necessary.
33.              oldProxy= AopContext.setCurrentProxy(proxy);
34.              setProxyContext= true;
35.          }
36.  
37.          //May be null. Get as late as possible to minimize the time we "own"the target,
38.          //in case it comes from a pool.
39.          target= targetSource.getTarget();
40.          if(target != null) {
41.              targetClass= target.getClass();
42.          }
43.  
44.          //Get the interception chain for this method.
45.          List<Object> chain =this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
46.  
47.          //Check whether we have any advice. If we don't, we can fallback on direct
48.          //reflective invocation of the target, and avoid creating a MethodInvocation.
49.          if(chain.isEmpty()) {
50.              //We can skip creating a MethodInvocation: just invoke the target directly
51.              //Note that the final invoker must be an InvokerInterceptor so we know it does
52.              //nothing but a reflective operation on the target, and no hot swapping or fancyproxying.
53.              Object[]argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
54.              retVal= AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
55.          }
56.          else{
57.              //We need to create a method invocation...
58.              invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
59.              //Proceed to the joinpoint through the interceptor chain.
60.              retVal = invocation.proceed();
61.          }
62.  
63.          //Massage return value if necessary.
64.          Class<?>returnType = method.getReturnType();
65.          if(retVal != null && retVal == target &&returnType.isInstance(proxy) &&
66.                  !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())){
67.              //Special case: it returned "this" and the return type of the method
68.              //is type-compatible. Note that we can't help if the target sets
69.              //a reference to itself in another returned object.
70.              retVal= proxy;
71.          }
72.          elseif (retVal == null && returnType != Void.TYPE &&returnType.isPrimitive()) {
73.              thrownew AopInvocationException(
74.                      "Nullreturn value from advice does not match primitive return type for: " +method);
75.          }
76.          returnretVal;
77.      }
78.      finally{
79.          if(target != null && !targetSource.isStatic()) {
80.              //Must have come from TargetSource.
81.              targetSource.releaseTarget(target);
82.          }
83.          if(setProxyContext) {
84.              //Restore old proxy.
85.              AopContext.setCurrentProxy(oldProxy);
86.          }
87.      }
88. }

        获取PersonService接口sayName方法拦截器链,此处只有一个,即[com.alipay.sofa.runtime.service.binding.JvmBindingAdapter$JvmServiceInvoker@4d45094f]。

        为sayName方法创建一个ReflectiveMethodInvocation实例invocation,表示一个方法调用。

        调用ReflectiveMethodInvocation的proceed方法,执行拦截器链:

1.  public Object proceed() throws Throwable {
2.       //  We start with an index of -1 and incrementearly.
3.       if(this.currentInterceptorIndex ==this.interceptorsAndDynamicMethodMatchers.size() - 1) {
4.           returninvokeJoinpoint();
5.       }
6.       ObjectinterceptorOrInterceptionAdvice =            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
7.       if(interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher){
8.           ……略
9.       }
10.      else{
11.          //It's an interceptor, so we just invoke it: The pointcut will have
12.          //been evaluated statically before this object was constructed.
13.          return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
14.      }
15. }

        从interceptorsAndDynamicMethodMatchers中获取指定位置的拦截器,此处为com.alipay.sofa.runtime.service.binding.JvmBindingAdapter$JvmServiceInvoker的一个实例。

        调用JvmBindingAdapter$JvmServiceInvoker的invoke方法:

1.  public Object doInvoke(MethodInvocationinvocation) throws Throwable {
2.              if (binding.isDestroyed()) {
3.                  throw newIllegalStateException(……略);
4.              }
5.              ……略
6.              Object retVal;
7.              Object targetObj = this.getTarget();
8.   
9.              if ((targetObj == null ||((targetObj instanceof Proxy) && binding.hasBackupProxy()))) {
10.                 targetObj =binding.getBackupProxy();
11.                 ……略
12.             }
13.  
14.             if (targetObj == null) {
15.                 throw newIllegalStateException(……略);
16.             }
17.  
18.             ClassLoader tcl = Thread.currentThread().getContextClassLoader();
19.             try {
20.                 pushThreadContextClassLoader(sofaRuntimeContext.getAppClassLoader());
21.                 retVal = invocation.getMethod().invoke(targetObj,invocation.getArguments());
22.             } catch (InvocationTargetExceptionex) {
23.                 throw ex.getTargetException();
24.             } finally {
25.                ……略
26.                 popThreadContextClassLoader(tcl);
27.             }
28.  
29.             return retVal;
30.         }

        调用JvmBindingAdapter$JvmServiceInvoker的getTarget方法,获取目标类:

1.  protected Object getTarget() {
2.              if (this.target == null) {
3.                  ComponentName componentName =ComponentNameFactory.createComponentName(
4.                      ServiceComponent.SERVICE_COMPONENT_TYPE,getInterfaceName(),
5.                      contract.getUniqueId());
6.                  ComponentInfo componentInfo =sofaRuntimeContext.getComponentManager()
7.                      .getComponentInfo(componentName);
8.   
9.                  if (componentInfo != null) {
10.                     this.target =componentInfo.getImplementation().getTarget();
11.                 }
12.             }
13.  
14.             return target;
15.         }

        根据服务接口类型为服务组件创建ComponentName实例componentName,此处组件名的字符串值为service:com.alipay.sofa.boot.examples.demo.rpc.bean.PersonService;

        从sofaRuntimeContext实例获取组件管理器,然后调用组件管理器getComponentInfo方法,获取名为componentName的服务组件,即ServiceComponent实例;

        调用ServiceComponent类getImplementation方法,获取服务组件的属性implementation的值,即DefaultImplementation实例;

        最后,调用DefaultImplementation的getTarget方法,获取服务具体实现类实例,此处为PersonServiceImpl的实例。此值是在ServiceFactoryBean初始化时设置的。

        获取到target以后,判断target是否为null。如果为null,则设置target为候选代理对象(在一个接口发布多种类型的服务时,如Jvm、Rest等,则会为Jvm类型的服务设置一个候选,以便在Jvm服务不可用时,使用备选服务)。此处不为null,则继续服务调用。

        最后,通过Java反射机制,调用目标对象的某个方法,此处为PersonServiceImpl类sayName方法。到此为止,Jvm服务调用完成,返回结果。

1.1.4 服务端响应

        由于JVM服务调用是同一个JVM内Java本地方法调用,所以直接执行目标方法,并返回处理结果。

华为OD机试真题 新系统 9月20号 【字符串分组求和】 华为OD新系统机试真题【字符串分组求和】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【字符串分组求和】解析。 阅读详情

相关推荐

超速U盘选购避坑指南:如何通过Rx Detect机制识别真伪USB3.0设备

本文深入解析了USB 3.0超速U盘的选购避坑要点,重点介绍了通过Rx Detect机制识别真伪设备的核心原理。文章提供了从软件检测到实际性能测试的完整方案,帮助消费者和技术人员有效辨别虚假的USB3.0设备,确保获得真正的超速传输体验。

weixin_29189373的博客 446

SOFA原理学习--sofa boot入门学习

        目前Spring boot可以说是Spring web最为流行的开发框架了,目前很多框架都支持Spring boot注册扫描的模式,这篇博客我们用一个示例来展示一下sofa-boot简单的开发工程。 1、创建API中相关接口及实现类 接口: public interface IHelloService { public String sayHello(String...

井底之蛙 1万+

保姆级教程:从Salmon输出到DESeq2,搞定RNA-seq表达矩阵标准化与下游分析准备

本文提供从Salmon输出到DESeq2标准化的RNA-seq数据分析全流程指南,详细解析表达矩阵构建、标准化方法选择及下游分析准备。重点介绍如何将Salmon定量结果转换为DESeq2兼容格式,包括TPM与原始计数的处理技巧,以及常见问题排查方法,帮助研究人员高效完成RNA-seq数据分析。

weixin_42699679的博客 304

SOFA使用记录

SOFA,即可扩展开放式金融服务架构,相较于其他服务架构,SOFA由于其spring上下文的模块隔离模式,使得SOFA架构的各个模块都拥有独立的spring配置,在应用拆分时,可以将模块的spring配置一同拆分出去,只需将本地服务改为远程服务即可。 一、安装插件 在idea的 Manage repositories 中添加自定义地址 : http://ide.alipay.net/plugin/list,添加完毕后搜索sofa,安装插件。 重启后即可看到SOFA工程创建按钮,如下: ...

yangchenbeiluo的博客 3797

《华为项目管理之道》第1章笔记

performance indicator,KPI)纳入个人绩效承诺书,贯彻结果导向的理念,以向员工。客户需求是华为发展的原动力,为客户服务是华为存在的唯一理由。目经理‘用兵’,依靠市场机制‘调兵’”,打破了人员在功能部门的板结,实现了听得。为管理者选拔的必要条件,项目经理成为人人向往的岗位。《华为项目管理之道》,是新出的华为官方的项目管理书,整个书不错。伴随着项目型组织的建立,华为逐步形成了完备的项目管理流程和制度,从而将业务运。为此,通过改革,重新明确了项目经理承担的经营责任,并开始以项。

jackyrongvip的专栏 2127

富斯遥控器-ros机器人控制

富斯遥控器-ros机器人手柄控制

zkh7758的博客 1702

SOFABoot源码解析之JVM服务代理机制

1.SOFABoot源码解析1.1  JVM服务代理机制        在SOFABoot中,采用AOP代理方式为JVM服务引用创建本地代理对象。对于AOP代理,主要有两种实现方式:        1.   针对实现接口的类,采用JDK动态代理机制;        2.   针对没有实现接口的类,采用CGLIB动态代理机制;        在SOFABoot中,对于JVM服务类型的服务引用,即可以...

闲来无事 980

脉冲变压器电感选型参数,结构原理,工艺与注意问题总结

脉冲变压器电感简称脉冲变压器,是一种特殊类型的变压器,主要用于处理脉冲信号。它的主要特性是能够在短时间内承受高电压和大电流。脉冲变压器主要用于开关电源、脉冲功率放大、雷达脉冲调制等领域。本文对脉冲变压器的工作原理,结构特点,工艺流程,选型参数及设计注意事项进行总结。

fydar的博客 1347

最近超火的SOFABoot是个什么东西?带你快速入门SOFABoot

最近发现了一个新的开源项目:SOFABoot,再加上公司用的框架也是SOFABoot,所以给将这个框架分享给大家,希望能扩展大家的视野。 首先我们需要知道什么是SOFABoot? SOFABoot 是蚂蚁集团开源的基于 Spring Boot 的研发框架,它在 Spring Boot 的基础上,提供了诸如 Readiness Check,类隔离,日志空间隔离等等能力。 下面是他的项目地址: https://gitee.com/sofastack/sofa-boot 为什么要选择SOFABoot?他能.

编码人生 1万+

3. 动手运行第一个 SAP Fiori Elements 应用(ListReport 类型)

这个代理服务器能够自动监听我们 Fiori Elements 应用里向 ES5 Demo 系统发送的 OData 请求,拦截这个请求,并通过 Node.js 代码向 ES5 服务器转发,拿到响应数据后再交还给 Fiori Elements 应用。后者对自己发出的请求被代理这件事情一无所知。本文的任务是,大家按照我的介绍,在本地成功运行笔者准备的这个 Fiori Elements 应用。的错误消息, 说明大家安装的 Node.js 版本没有达到本地运行 Fiori Elements 的最低要求。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1671

C#上位机开发实战全流程:从需求到落地,避坑指南+完整代码

作为一名做了5年工业自动化上位机开发的程序员,我踩过的坑比写过的代码还多——从最初串口通信粘包导致数据错乱,到可视化图表卡顿卡死,再到现场异常崩溃无日志可查,每一次踩坑都是一次血泪教训。今天这篇文章,我会把C#上位机开发的全流程拆解开,从需求分析到通信模块、数据可视化,再到异常处理,每个环节都结合工业实际场景,分享真实项目中能用的方案、完整代码和避坑技巧。不管你是刚入门的新手,还是想优化现有项目的老司机,相信都能有所收获。很多新手做上位机开发,一上来就闷头写代码,最后发现做出来的东西不符合现场需求——比如客

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 996

SOFABoot源码解析之模块化开发

1.SOFABoot源码解析1.1  模块化开发1.1.1 简述        关于SOFABoot模块化开发的文档来自于Alipay开源社区Wiki,链接地址为:        https://github.com/alipay/sofa-boot/wiki/Modular-Development        此处直接引用该文档内容,主要是便于大家理解源码解析部分。1.1.1.1  模块化开发...

闲来无事 3558

PCL 中实现平面模型分割【2026最新版】

RANSAC分割平面。博客长期更新,最近一次更新时间为:2026年5月4日。

点云侠的博客 38万+

SOFA RPC源码解析之Rest服务(1)-服务发布

1.SOFA RPC源码解析1.1  Rest服务1.1.1 服务发布        以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,详细描述SOFABoot Rest服务发布原理。        在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。        RPC案例的SpringXML配...

闲来无事 3607

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

SOFA RPC源码解析之Rest服务(2)-服务引用

1.SOFA RPC源码解析1.1Rest服务1.1.1 服务引用        以SOFABoot自带的RPC案例sofaboot-sample-with-rpc为例,详细描述SOFABoot服务发布原理。        在此提前说明,源码分析主要分析主流程,以及本人认为比较重要的一些内容,对于其它部分,大家可以基于本文档,自行研读。        RPC案例的SpringXML配置文件内容如下...

闲来无事 1442

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

【剖析|SOFARPC 框架】系列之 SOFARPC 注解支持剖析

1、前言 在 SOFABoot 环境下,SOFARPC 提供三种方式给开发人员发布和引用 RPC 服务: XML 方式(配置) Annotation 方式(注解) 编程 API 方式(动态) 编程 API 方式与Spring 的 ApplicationContextAware 类似。XML的方式依赖于在xml中引入 SOFA 命名空间,利用 Bean...

weixin_34186950的博客 879

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

最新阿里巴巴关于Java重要开源项目汇总,程序员真的是吃青春饭吗

这份面试题几乎包含了他在一年内遇到的所有面试题以及答案,甚至包括面试中的细节对话以及语录,可谓是细节到极致,甚至简历优化和怎么投简历更容易得到面试机会也包括在内!也包括教你怎么去获得一些大厂,比如阿里,腾讯的内推名额!某位名人说过成功是靠99%的汗水和1%的机遇得到的,而你想获得那1%的机遇你首先就得付出99%的汗水!你只有朝着你的目标一步一步坚持不懈的走下去你才能有机会获得成功!成功只会留给那些有准备的人!

2401_84585372的博客 682

阿里巴巴开源的 26 种项目介绍及源码分享,强烈推荐!

1.分布式应用服务开发的一站式解决方案 Spring Cloud AlibabaSpring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解决方案。此项目包含开发分布...

Java精选 2304

蚂蚁金服开源增强版 Spring Boot 的研发框架!

针对 Spring Boot 缺少 Readiness Check 能力的情况,SOFABoot 增加了 Spring Boot 现有的健康检查的能力,提供了 Readiness Check 的能力。利用 Readiness Check 的能力,SOFA 中间件中的各个组件只有在 Readiness Check 通过之后,才将流量引入到应用的实例中,比如 RPC,只有在 Readiness Check 通过之后,才会向服务注册中心注册,后面来自上游应用的流量才会进入。提供类隔离的能力========

2401_84046677的博客 640

java jxl包_阿里26款Java开源项目(附源码),看完收藏!

1.分布式应用服务开发的一站式解决方案 Spring Cloud AlibabaSpring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring ...

weixin_39688035的博客 121

阿里巴巴的26款超神Java开源项目!

1.分布式应用服务开发的一站式解决方案 Spring Cloud Alibaba Spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。 依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用接入阿里分布式应用解决方案,通过阿里中间件来迅速搭建分布式应用系统。 地址:https

435

蚂蚁课堂-第四期-基于springcloud构建微服务电商项目_阿里巴巴29个屌炸天的开源项目,你用过几个?附编程资料!!!...

1. 分布式应用服务开发的一站式解决方案 Spring Cloud AlibabaSpring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring...

weixin_39733812的博客 127

2024年Java最全阿里巴巴的26款超神Java开源项目,2024Java大厂面试经验

面试前一定少不了刷题,为了方便大家复习,我分享一波个人整理的面试大全宝典Java核心知识整理Java核心知识Spring全家桶(实战系列)其他电子书资料Step3:刷题既然是要面试,那么就少不了刷题,实际上春节回家后,哪儿也去不了,我自己是刷了不少面试题的,所以在面试过程中才能够做到心中有数,基本上会清楚面试过程中会问到哪些知识点,高频题又有哪些,所以刷题是面试前期准备过程中非常重要的一点。以下是我私藏的面试题库:本文已被。

2301_82257317的博客 2161

阿里有趣的Java开源项目

今天分享一篇阿里云社区的文章,把阿里开源的 Java 项目进行了整理,一篇值得收藏的文章,这些开源项目值得各位花时间去好好研究,一定要挑几个感兴趣的项目,读读源码。   原文如下。     1、Spring Cloud Alibaba   Spring Cloud Alibaba 致力于提供分布式应用服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件,方便开发者通过 S...

KHOST的博客 1355

26 款阿里超神 Java 开源项目,看看你用过几个?

点击上方“芋道源码”,选择“设为星标”做积极的人,而不是积极废人!源码精品专栏中文详细注释的开源项目RPC 框架 Dubbo 源码解析网络应用框架 Netty 源码解析消息中间件 Ro...

芋艿V 314

阿里巴巴的26款超神Java开源项目

目录 1.分布式应用服务开发的一站式解决方案 Spring Cloud Alibaba 2. JDBC 连接池、监控组件 Druid 3. Java 的 JSON 处理器 fastjson 4. 服务框架 Dubbo 5. 企业级流式计算引擎 JStorm 6. a...

weixin_30258901的博客 227
上一篇: SOFABoot源码解析之模块化开发
下一篇: SOFA RPC源码解析之RPC配置
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

任性之闲来无事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值