验证码: 看不清楚,换一张 查询 注册会员,免验证
  • {{ basic.site_slogan }}
  • 打开微信扫一扫,
    您还可以在这里找到我们哟

    关注我们

JavaAgent如何实现http接口发布

阅读:467 来源:乙速云 作者:代码code

JavaAgent如何实现http接口发布

      需求

      公司运维系统想要监控服务是否正常启动,这些服务是k8s部署的,运维人员的要求业务服务提供一个http接口用于监控服务健康监测,要求所有的接口请求的URL,参数等都是相同的,这么做的目的是不需要通过规范来约束开发人员去开一个服务健康监测的接口。

      使用服务接口来检测服务我觉得相比较监控进程启动,端口监听等方式更准确一些。所以,为了满足运维同学的要求,起初想到的方案是提供一个jar,专门集成到项目中用于发布监控接口,但是想了一下,这么做需要涉及到服务的改造,我理想的方式是对应用无侵入的方式实现。

      初步方案

      说到对应用无入侵,首先想到的就是javaagent技术,此前使用该技术实现了无入侵增强程序日志的工具,所以对使用javaagent已经没有问题,此时需要考虑的是如何发布接口了。

      基础技术 JavaAgent

      支持的技术 SpringBoot和DubboX发布的rest服务

      公司服务大致分为两类,一个是使用springboot发布的Spring MVC rest接口,另一种是基于DubboX发布的rest接口,因为公司在向服务网格转,所以按要求是去dubbo化的,没办法还是有其他小组由于一些其他原因没有或者说短期内不想进行服务改造的项目,这些项目比较老,不是springboot的,是使用spring+DubboX发布的rest服务。所以这个agent要至少能支持这两种技术。

      支持SpringBoot

      想要支持SpringBoot很简单,因为SpringBoot支持自动装配,所以,我要写一个spring.factories来进行自动装配。

      支持DubboX

      业务系统是传统spring+DubboX实现的,并不支持自动装配,这是个问题点,还有个问题点就是如何也发布一个DubboX的rest接口,这两个问题实际上就需要对SpringBean生命周期和Dubbo接口发布的流程有一定的了解了,这个一会儿再说。

      技术实现

      pom文件依赖

          
              
                  org.springframework.boot
                  spring-boot-starter-web
                  2.3.6.RELEASE
                  true
              
              
                  org.springframework.boot
                  spring-boot-autoconfigure
                  2.3.6.RELEASE
                  true
              
              
                  org.springframework.boot
                  spring-boot-configuration-processor
                  2.3.6.RELEASE
                  true
              
              
                  com.alibaba
                  fastjson
                  1.2.70
              
              
                  org.apache.zookeeper
                  zookeeper
                  3.4.6
                  
                      
                          log4j
                          log4j
                      
                  
              
              
                  com.101tec
                  zkclient
                  0.7
              
              
                  com.alibaba
                  dubbo
                  2.8.4
                  
                      
                          org.springframework
                          spring
                      
                  
              
              
                  javax.ws.rs
                  javax.ws.rs-api
                  2.0.1
              
          

      实现一个JavaAgent

      实现一个JavaAgent很容易,以下三步就可以了,这里不细说了。

      定义JavaAgent入口

      public class PreAgent {
          public static void premain(String args, Instrumentation inst) {
              System.out.println("输入参数:" + args);
              // 通过参数控制,发布的接口是DubboX还是SpringMVC
              Args.EXPORT_DUBBOX = args;
          }
      }

      Maven打包配置

              
                  
                      maven-deploy-plugin
                      
                          true
                      
                  
                  
                      org.apache.maven.plugins
                      maven-shade-plugin
                      1.4
                      
                          
                              package
                              
                                  shade
                              
                              
                                  true
                                  false
                                  true
                                  false
                                  true
                                  
                                      
                                          
                                              com.ruubypay.agent.PreAgent
                                          
                                      
                                  
                              
                          
                      
                  
              

      MANIFEST.MF编写

      注:该文件在resource/META-INF/目录下

      Manifest-Version: 1.0
      Can-Redefine-Classes: true
      Can-Retransform-Classes: true
      Premain-Class: com.ruubypay.agent.PreAgent

      支持SpringBoot发布的Http接口

      编写Controller

      接口很简单就发布一个get接口,响应pong即可。

      @RestController
      public class PingServiceController {
          @GetMapping(value = "/agentServer/ping")
          public String ping() {
              return "pong";
          }
      }

      创建spring.factories

      通过这个配置文件可以实现SpringBoot自动装配,这里不细说SpringBoot自动装配的原理了,该文件的配置内容就是要自动装配的Bean的全路径,代码如下:

      org.springframework.boot.autoconfigure.EnableAutoConfiguration=
        com.ruubypay.config.WebConfiguration

      WebConfiguration配置类

      这个配置配置类很简单,@Configuration声明这是个配置类,@ComponentScan扫描包。

      @Configuration
      @ComponentScan(value = "com.ruubypay")
      public class WebConfiguration {
      }

      支持DubboX发布的rest接口

      定义API

      使用的是DubboX发布rest接口需要javax.ws.rs包的注解,@Produces({ContentType.APPLICATION_JSON_UTF_8})声明序列化方式,@Pathrest接口的路径,@GET声明为get接口。

      @Produces({ContentType.APPLICATION_JSON_UTF_8})
      @Path("/agentServer")
      public interface IPingService {
          /**
           * ping接口
           * @return
           */
          @GET
          @Path("/ping")
          String ping();
      }

      编写API实现类

      @Component("IPingService")
      public class IPingServiceImpl implements IPingService {
          @Override
          public String ping() {
              return "pong";
          }
      }

      实现发布Dubbo接口

      如何实现发布接口是实现的难点;首先程序并不支持自动装配了,我们就要考虑如何获取到Spring上下文,如果能够注册BeanSpring容器中,如何触发发布Dubbo接口等问题。

      Spring上下文获取及注册Bean到Spring容器中

      触发Bean注册,获取Spring上下文我们通过Spring的Aware接口可以实现,我这里使用的是ApplicationContextAware;注册BeanSpring容器中可以使用BeanDefinition先创建Bean然后使用DefaultListableBeanFactoryregisterBeanDefinitionBeanDefinition注册到Spring上下文中。

      @Component
      public class AgentAware implements ApplicationContextAware {
          private static final String DUBBOX = "1";
          private ApplicationContext applicationContext;
          @Override
          public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
              this.applicationContext = applicationContext;
              // 如果不是DubboX,不用发布接口
              if (DUBBOX.equals(Args.EXPORT_DUBBOX)) {
                  // 注册配置Bean WebConfiguration
                  webConfiguration();
                  // 发布DubboX接口
                  exportDubboxService();
              }
          }
          public void webConfiguration() {
              System.out.println("创建WebConfiguration的bean");
              ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext;
              DefaultListableBeanFactory listableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getAutowireCapableBeanFactory();
              // 创建WebConfiguration的bean
              BeanDefinition webConfigurationBeanDefinition = new RootBeanDefinition(WebConfiguration.class);
              // 注册到集合beanFactory中
              System.out.println("注册到集合beanFactory中");
              listableBeanFactory.registerBeanDefinition(WebConfiguration.class.getName(), webConfigurationBeanDefinition);
          }
      }

      发布Dubbo接口

      通过ApplicationContextAware我们已经能够获取Spring上下文了,也就是说应用程序的Dubbo注册中心,发布接口协议,Dubbo Application等配置都已经存在Spring容器中了,我们只要拿过来使用即可,拿过来使用没问题,我们接下来就需要考虑,如何发布接口,这需要对Dubbo服务发布的流程有一定的了解,这里我不细说了,感兴趣的可以自己了解下,或者看我以前发布的文章;

      首先Dubbo接口的Provider端的核心Bean是com.alibaba.dubbo.config.spring.ServiceBean,使用Spring配置文件中的标签标签生成的Bean就是ServiceBean,所以,这里我们只需要创建ServiceBean对象并且初始化对象中的必要数据,然后调用ServiceBean#export()方法就可以发布Dubbo服务了。

      这里需要的对象直接通过依赖查找的方式从Spring容器获取就可以了 ApplicationConfig,ProtocolConfig,RegistryConfig,IPingService

          public void exportDubboxService() {
              try {
                  System.out.println("开始发布dubbo接口");
                  // 获取ApplicationConfig
                  ApplicationConfig applicationConfig = applicationContext.getBean(ApplicationConfig.class);
                  // 获取ProtocolConfig
                  ProtocolConfig protocolConfig = applicationContext.getBean(ProtocolConfig.class);
                  // 获取RegistryConfig
                  RegistryConfig registryConfig = applicationContext.getBean(RegistryConfig.class);
                  // 获取IPingService接口
                  IPingService iPingService = applicationContext.getBean(IPingService.class);
                  // 创建ServiceBean
                  ServiceBean serviceBean = new ServiceBean<>();
                  serviceBean.setApplicationContext(applicationContext);
                  serviceBean.setInterface("com.ruubypay.api.IPingService");
                  serviceBean.setApplication(applicationConfig);
                  serviceBean.setProtocol(protocolConfig);
                  serviceBean.setRegistry(registryConfig);
                  serviceBean.setRef(iPingService);
                  serviceBean.setTimeout(12000);
                  serviceBean.setVersion("1.0.0");
                  serviceBean.setOwner("rubby");
                  // 发布dubbo接口
                  serviceBean.export();
                  System.out.println("dubbo接口发布完毕");
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }

      使用方式

      • DubboX: java -javaagent:ruubypay-ping-agent.jar=1 -jar 服务jar包

      • springboot的http接口:java -javaagent:ruubypay-ping-agent.jar -jar 服务jar包

    分享到:
    *特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: hlamps#outlook.com (#换成@)。
    相关文章
    {{ v.title }}
    {{ v.description||(cleanHtml(v.content)).substr(0,100)+'···' }}
    你可能感兴趣
    推荐阅读 更多>

    {{ basic.bottom_text }}