首页 文章 精选 留言 我的

精选列表

搜索[ API集成],共10010篇文章
优秀的个人博客,低调大师

Spring Boot项目集成 UidGenerator

前言 UidGenerator 基于snowflake算法实现 UidGenerator 由百度开发,基于SnowFlake算法的唯一ID生成器。UidGenerator 已组件的形式工作在应用项目中,支持自定义workeid位数和初始化策略,从而适用docker等虚拟化环境下实例自动重启等场景。 准备一个maven项目,构建两个模块。分别作为使用方和提供方。(建两个模块主要是为了“造轮子”,其他模块或项目可以直接引用,无需关心uid配置,如果没有分模块,可以忽略构建两个模块) 下载uid源码,放在项目中,开源地址https://github.com/baidu/uid-generator 数据库建表 DROP TABLE IF EXISTS WORKER_NODE;CREATE TABLE WORKER_NODE ( ID BIGINT NOT NULL AUTO_INCREMENT COMMENT 'auto increment id', HOST_NAME VARCHAR(64) NOT NULL COMMENT 'host name', PORT VARCHAR(64) NOT NULL COMMENT 'port',TYPE INT NOT NULL COMMENT 'node type: ACTUAL or CONTAINER', LAUNCH_DATE DATE NOT NULL COMMENT 'launch date', MODIFIED TIMESTAMP NOT NULL COMMENT 'modified time', CREATED TIMESTAMP NOT NULL COMMENT 'created time',PRIMARY KEY(ID)) COMMENT='DB WorkerID Assigner for UID Generator',ENGINE = INNODB; Spring 配置 CachedUidGennerator: UidGenerator 有两个具体的实现类,分别是 DefaultUidGenerator 和 CachedUidGenerator, 官方推荐使用性能较强的 CachedUidGenerator。 我们直接引用 UdiGenerator源码中的 cached-uid-spring.xml文件,使用默认配置 <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"> <!-- UID generator --> <bean id="disposableWorkerIdAssigner" class="com.baidu.fsg.uid.worker.DisposableWorkerIdAssigner" /> <bean id="cachedUidGenerator" class="com.baidu.fsg.uid.impl.CachedUidGenerator"> <property name="workerIdAssigner" ref="disposableWorkerIdAssigner" /> <!-- 以下为可选配置, 如未指定将采用默认值 --> <!-- RingBuffer size扩容参数, 可提高UID生成的吞吐量. --> <!-- 默认:3, 原bufferSize=8192, 扩容后bufferSize= 8192 << 3 = 65536 --> <!--<property name="boostPower" value="3"></property>--> <!-- 指定何时向RingBuffer中填充UID, 取值为百分比(0, 100), 默认为50 --> <!-- 举例: bufferSize=1024, paddingFactor=50 -> threshold=1024 * 50 / 100 = 512. --> <!-- 当环上可用UID数量 < 512时, 将自动对RingBuffer进行填充补全 --> <!--<property name="paddingFactor" value="50"></property>--> <!-- 另外一种RingBuffer填充时机, 在Schedule线程中, 周期性检查填充 --> <!-- 默认:不配置此项, 即不实用Schedule线程. 如需使用, 请指定Schedule线程时间间隔, 单位:秒 --> <!--<property name="scheduleInterval" value="60"></property>--> <!-- 拒绝策略: 当环已满, 无法继续填充时 --> <!-- 默认无需指定, 将丢弃Put操作, 仅日志记录. 如有特殊需求, 请实现RejectedPutBufferHandler接口(支持Lambda表达式) --> <!--<property name="rejectedPutBufferHandler" ref="XxxxYourPutRejectPolicy"></property>--> <!-- 拒绝策略: 当环已空, 无法继续获取时 --> <!-- 默认无需指定, 将记录日志, 并抛出UidGenerateException异常. 如有特殊需求, 请实现RejectedTakeBufferHandler接口(支持Lambda表达式) --> <!--<property name="rejectedPutBufferHandler" ref="XxxxYourPutRejectPolicy"></property>--> </bean> </beans> 引入cached-uid-spring.xml配置文件,在我们自己新建的 UidConfig中 package com.xxx.uid.config; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; /** * @author lishuzhen * @date 2020/8/11 16:10 */ @Configuration @ImportResource(locations = {"classpath:/uid/cached-uid-spring.xml"}) public class UidConfig { } 在另一个模块中maven引入,创建一个UidGenUtils工具类,方便使用 package com.xxxx.utils; import com.xxx.uid.UidGenerator; import org.springframework.stereotype.Component; import javax.annotation.Resource; /** * @author lishuzhen * @date 2020/8/11 16:13 */ @Component public class UidGenUtils { @Resource private UidGenerator uidGenerator; public long getUid() { return uidGenerator.getUID(); } public String getUidStr() { return String.valueOf(uidGenerator.getUID()); } }

优秀的个人博客,低调大师

EFK实战二 - 日志集成

前言 在EFK基础架构中,我们需要在客户端部署Filebeat,通过Filebeat将日志收集并传到LogStash中。在LogStash中对日志进行解析后再将日志传输到ElasticSearch中,最后通过Kibana查看日志。 上文已经搭建好了EFK的基础环境,本文我们通过真实案例打通三者之间的数据传输以及解决EFK在使用过程中的一些常见问题。 首先看一下实际的业务日志 2020-01-0910:03:26,719INFO========GetCostCenterStart=============== 2020-01-09 10:03:44,267 WARN 成本中心编码少于10位!{"deptId":"D000004345","companyCode":"01"} 2020-01-0910:22:37,193ERRORjava.lang.IllegalStateException:SessionImpl[abcpI7fK-WYnW4nzXrv7w,]:can'tcallgetAttribute()whensessionisnolongervalid. atcom.caucho.server.session.SessionImpl.getAttribute(SessionImpl.java:283) atweaver.filter.PFixFilter.doFilter(PFixFilter.java:73) atcom.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:87) atweaver.filter.MonitorXFixIPFilter.doFilter(MonitorXFixIPFilter.java:30) atweaver.filter.MonitorForbiddenUrlFilter.doFilter(MonitorForbiddenUrlFilter.java:133) 「日志组成格式为:」 时间 日志级别 日志详情 那么我们的主要任务就是将这段日志正常写入EFK中。 filebeat安装配置 下载filebeat7.5.1 将下载后的文件上传至服务器并解压tar -zxvf filebeat-7.5.1-linux-x86_64.tar.gz 修改filebeat.yml, filebeat.inputs: -type:log enabled:true paths: -/app/weaver/Resin/log/xxx.log 此段配置日志输入,指定日志存储路径 output.logstash: #TheLogstashhosts hosts:["172.31.0.207:5044"] 此段配置日志输出,指定Logstash存储路径 启动filebeat ./filebeat -e -c filebeat.yml 如果需要静默启动,则使用 nohup ./filebeat -e -c filebeat.yml & 命令启动即可。 logstash配置 logstash的配置主要分为三段 input,filter,output。input用于指定输入,主要是开放端口给Filebeat用于接收日志filter用于指定过滤,对日志内容进行解析过滤。output用于指定输出,直接配置ES的地址即可 input{ beats{ port=>5044 } } output{ elasticsearch{ hosts=>["http://172.31.0.127:9200"] index=>"myindex-%{+YYYY.MM.dd}" user=>"elastic" password=>"xxxxxx" } } 我们配置好logstash后通过命令重启logstash docker-compose -f elk.yml restart logstash 经过上述两步配置后应用程序往日志文件写入日志,filebeat会将日志写入logstash。在kibana查看写入的日志结果如下: 日志显示有2个问题: 由于错误日志堆栈信息有多行,在kibana中展示成了多行,数据查看很乱。需要将堆栈异常整理成一行显示。 需要对日志进行解析,拆成“时间 日志级别 日志详情”的显示格式。 优化升级 在filebeat中设置合并行 filebeat默认是行传输的,但是我们的日志肯定是多行一个日志,我们要把多行合并到一起就要找到日志的规律。比如我们的日志格式全都是以时间格式开头,所以我们在filebeat中 filebeat.inputs区域添加如下几行配置 #以日期作为前缀 multiline.pattern:^\d{4}-\d{1,2}-\d{1,2} #开启多行合并 multiline.negate:true #合并到上一行之后 multiline.match:after 在logstash中设置对日志的解析 将日志解析成“时间 日志级别 日志详情”的展示格式,所以我们需要在logstash配置文件中添加filter段 filter { grok{ match => { "message" => "(?<date>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}),\d{3} %{LOGLEVEL:loglevel} (?<des>.*)" } } } 这里主要是使用grok语法对日志进行解析,通过正则表达式对日志进行过滤。大家可以通过kibana里的grok调试工具进行调试 配置完成后我们重新打开kibana Discover界面查看日志,符合预期,完美! 常见问题 kibana 乱码 这个主要原因还是客户端日志文件格式有问题,大家可以通过 file xxx.log查看日志文件的编码格式,如果是ISO8859的编码基本都会乱码,我们可以在filebeat配置文件中通过encoding指定日志编码进行传输。 filebeat.inputs: -type:log enabled:true paths: -/app/weaver/Resin/log/xxx.log encoding:GB2312 kibana 提取字段出错 如上所示,打开kibana Discover面板时出现此异常,大家只要删除ES中的 .kibana_1索引然后重新访问Kibana即可。 查看周围文件 我们在终端查看日志某关键字时一般会查上下文信息便于排查问题,如经常用到的指令 cat xxx.log | grep -C50 keyword,那么在Kibana中如何实现这功能呢。 在Kibana中搜索关键字,然后找到具体日志记录,点击左边向下箭头,然后再点击“查看周围文档”即可实现。 动态索引 我们日志平台可能需要对接多个业务系统,需要根据业务系统建立不同的索引。 在filebeat中给日志打上标记 -type:log ...... fields: logType:oabusiness 在logstash中根据标记生成索引 input { beats { port => 5044 } } filter { if [fields][logType] == "oabusiness" { grok{ match => { "message" => "(?<date>\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}),\d{3} %{LOGLEVEL:loglevel} (?<des>.*)" } } } } output { elasticsearch { hosts => ["http://172.31.0.207:9200"] index => "%{[fields][logType]}-%{+YYYY.MM.dd}" user => "elastic" password => "elastic" } } 如果本文对你有帮助, 别忘记来个三连: 点赞,转发,评论 本文分享自微信公众号 - JAVA日知录(javadaily)。 如有侵权,请联系 support@oschina.cn 删除。 本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

阿里云AMQP Springboot集成

概述 本文主要介绍如何通过 Spring boot 连接阿里云AMQP服务。 操作步骤 1、示例程序下载,下载地址。 2、参数配置,AMQP管理控制台获取。 resources -> application.properties spring.application.name=rabbitmq-demo spring.rabbitmq.host=18********617278.mq-amqp.cn-hangzhou-a.aliyuncs.com spring.rabbitmq.port=5672 spring.rabbitmq.username=****** spring.rabbitmq.password=****** spring.rabbitmq.virtual-host=****** spring.rabbitmq.temp

优秀的个人博客,低调大师

SpringBoot之集成Spring AOP

在开始之前,我们先把需要的jar包添加到工程里。新增Maven依赖如下: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> 接下来,我们进入正题。这里的涉及的通知类型有:前置通知、后置最终通知、后置返回通知、后置异常通知、环绕通知,下面我们就具体的来看一下怎么在SpringBoot中添加这些通知。 首先我们先创建一个Aspect切面类: @Component @Aspect publicclassWebControllerAop{ } 指定切点: //匹配com.zkn.learnspringboot.web.controller包及其子包下的所有类的所有方法 @Pointcut("execution(*com.zkn.learnspringboot.web.controller..*.*(..))") publicvoidexecuteService(){ } 接着我们再创建一个Controller请求处理类: packagecom.zkn.learnspringboot.web.controller; importorg.springframework.web.bind.annotation.RequestMapping; importorg.springframework.web.bind.annotation.RestController; /** *Createdbyzknon2016/11/19. */ @RestController @RequestMapping("/aop") publicclassAopTestController{ } 前置通知 配置前置通知: /** *前置通知,方法调用前被调用 *@paramjoinPoint */ @Before("executeService()") publicvoiddoBeforeAdvice(JoinPointjoinPoint){ System.out.println("我是前置通知!!!"); //获取目标方法的参数信息 Object[]obj=joinPoint.getArgs(); //AOP代理类的信息 joinPoint.getThis(); //代理的目标对象 joinPoint.getTarget(); //用的最多通知的签名 Signaturesignature=joinPoint.getSignature(); //代理的是哪一个方法 System.out.println(signature.getName()); //AOP代理类的名字 System.out.println(signature.getDeclaringTypeName()); //AOP代理类的类(class)信息 signature.getDeclaringType(); //获取RequestAttributes RequestAttributesrequestAttributes=RequestContextHolder.getRequestAttributes(); //从获取RequestAttributes中获取HttpServletRequest的信息 HttpServletRequestrequest=(HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST); //如果要获取Session信息的话,可以这样写: //HttpSessionsession=(HttpSession)requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION); Enumeration<String>enumeration=request.getParameterNames(); Map<String,String>parameterMap=Maps.newHashMap(); while(enumeration.hasMoreElements()){ Stringparameter=enumeration.nextElement(); parameterMap.put(parameter,request.getParameter(parameter)); } Stringstr=JSON.toJSONString(parameterMap); if(obj.length>0){ System.out.println("请求的参数信息为:"+str); } } 注意:这里用到了JoinPoint和RequestContextHolder。通过JoinPoint可以获得通知的签名信息,如目标方法名、目标方法参数信息等。通过RequestContextHolder来获取请求信息,Session信息。 接下来我们在Controller类里添加一个请求处理方法来测试一下前置通知: @RequestMapping("/testBeforeService.do") publicStringtestBeforeService(Stringkey,Stringvalue){ return"key="+key+"value="+value; } 前置通知拦截结果如下所示: 后置返回通知 配置后置返回通知的代码如下: /** *后置返回通知 *这里需要注意的是: *如果参数中的第一个参数为JoinPoint,则第二个参数为返回值的信息 *如果参数中的第一个参数不为JoinPoint,则第一个参数为returning中对应的参数 *returning限定了只有目标方法返回值与通知方法相应参数类型时才能执行后置返回通知,否则不执行,对于returning对应的通知方法参数为Object类型将匹配任何目标返回值 *@paramjoinPoint *@paramkeys */ @AfterReturning(value="execution(*com.zkn.learnspringboot.web.controller..*.*(..))",returning="keys") publicvoiddoAfterReturningAdvice1(JoinPointjoinPoint,Objectkeys){ System.out.println("第一个后置返回通知的返回值:"+keys); } @AfterReturning(value="execution(*com.zkn.learnspringboot.web.controller..*.*(..))",returning="keys",argNames="keys") publicvoiddoAfterReturningAdvice2(Stringkeys){ System.out.println("第二个后置返回通知的返回值:"+keys); } Controller里添加响应的请求处理信息来测试后置返回通知: @RequestMapping("/testAfterReturning.do") publicStringtestAfterReturning(Stringkey){ return"key=:"+key; } @RequestMapping("/testAfterReturning01.do") publicIntegertestAfterReturning01(Integerkey){ returnkey; } 当发送请求为:http://localhost:8001/aop/testAfterReturning.do?key=testsss&value=855sss时,处理结果如图所示: 当发送请求为:http://localhost:8001/aop/testAfterReturning01.do?key=55553&value=855sss时,处理结果如图所示: 后置异常通知 后置异常通知的配置方式如下: /** *后置异常通知 *定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法; *throwing限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行, *对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。 *@paramjoinPoint *@paramexception */ @AfterThrowing(value="executeService()",throwing="exception") publicvoiddoAfterThrowingAdvice(JoinPointjoinPoint,Throwableexception){ //目标方法名: System.out.println(joinPoint.getSignature().getName()); if(exceptioninstanceofNullPointerException){ System.out.println("发生了空指针异常!!!!!"); } } Controller里配置响应的请求处理类: @RequestMapping("/testAfterThrowing.do") publicStringtestAfterThrowing(Stringkey){ thrownewNullPointerException(); } 后置异常通知方法的处理结果如下所示: 后置最终通知 后置最终通知的配置方式如下: /** *后置最终通知(目标方法只要执行完了就会执行后置通知方法) *@paramjoinPoint */ @After("executeService()") publicvoiddoAfterAdvice(JoinPointjoinPoint){ System.out.println("后置通知执行了!!!!"); } Controller类配置相应的请求处理类: @RequestMapping("/testAfter.do") publicStringtestAfter(Stringkey){ thrownewNullPointerException(); } @RequestMapping("/testAfter02.do") publicStringtestAfter02(Stringkey){ returnkey; } 当发送请求为:http://localhost:8001/aop/testAfter.do?key=55553&value=855sss 当发送请求为:http://localhost:8001/aop/testAfter02.do?key=55553&value=855sss 环绕通知 环绕通知的配置方式如下: /** *环绕通知: *环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。 *环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型 */ @Around("execution(*com.zkn.learnspringboot.web.controller..*.testAround*(..))") publicObjectdoAroundAdvice(ProceedingJoinPointproceedingJoinPoint){ System.out.println("环绕通知的目标方法名:"+proceedingJoinPoint.getSignature().getName()); try{ Objectobj=proceedingJoinPoint.proceed(); returnobj; }catch(Throwablethrowable){ throwable.printStackTrace(); } returnnull; } Controller对应的请求处理类如下: @RequestMapping("/testAroundService.do") publicStringtestAroundService(Stringkey){ return"环绕通知:"+key; } 当发送请求为:http://localhost:8001/aop/testAroundService.do?key=55553 当发送请求为:http://localhost:8001/aop/testAfter02.do?key=55553&value=855sss时,不符合环绕通知的切入规则,所以环绕通知不会 执行。 完整的AOP配置代码如下: packagecom.zkn.learnspringboot.aop; importcom.alibaba.fastjson.JSON; importcom.google.common.collect.Maps; importorg.aspectj.lang.JoinPoint; importorg.aspectj.lang.ProceedingJoinPoint; importorg.aspectj.lang.Signature; importorg.aspectj.lang.annotation.*; importorg.springframework.stereotype.Component; importorg.springframework.web.context.request.RequestAttributes; importorg.springframework.web.context.request.RequestContextHolder; importjavax.servlet.http.HttpServletRequest; importjavax.servlet.http.HttpSession; importjava.util.Enumeration; importjava.util.Map; /** *Createdbyzknon2016/11/18. */ @Component @Aspect publicclassWebControllerAop{ //匹配com.zkn.learnspringboot.web.controller包及其子包下的所有类的所有方法 @Pointcut("execution(*com.zkn.learnspringboot.web.controller..*.*(..))") publicvoidexecuteService(){ } /** *前置通知,方法调用前被调用 *@paramjoinPoint */ @Before("executeService()") publicvoiddoBeforeAdvice(JoinPointjoinPoint){ System.out.println("我是前置通知!!!"); //获取目标方法的参数信息 Object[]obj=joinPoint.getArgs(); //AOP代理类的信息 joinPoint.getThis(); //代理的目标对象 joinPoint.getTarget(); //用的最多通知的签名 Signaturesignature=joinPoint.getSignature(); //代理的是哪一个方法 System.out.println(signature.getName()); //AOP代理类的名字 System.out.println(signature.getDeclaringTypeName()); //AOP代理类的类(class)信息 signature.getDeclaringType(); //获取RequestAttributes RequestAttributesrequestAttributes=RequestContextHolder.getRequestAttributes(); //从获取RequestAttributes中获取HttpServletRequest的信息 HttpServletRequestrequest=(HttpServletRequest)requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST); //如果要获取Session信息的话,可以这样写: //HttpSessionsession=(HttpSession)requestAttributes.resolveReference(RequestAttributes.REFERENCE_SESSION); Enumeration<String>enumeration=request.getParameterNames(); Map<String,String>parameterMap=Maps.newHashMap(); while(enumeration.hasMoreElements()){ Stringparameter=enumeration.nextElement(); parameterMap.put(parameter,request.getParameter(parameter)); } Stringstr=JSON.toJSONString(parameterMap); if(obj.length>0){ System.out.println("请求的参数信息为:"+str); } } /** *后置返回通知 *这里需要注意的是: *如果参数中的第一个参数为JoinPoint,则第二个参数为返回值的信息 *如果参数中的第一个参数不为JoinPoint,则第一个参数为returning中对应的参数 *returning限定了只有目标方法返回值与通知方法相应参数类型时才能执行后置返回通知,否则不执行,对于returning对应的通知方法参数为Object类型将匹配任何目标返回值 *@paramjoinPoint *@paramkeys */ @AfterReturning(value="execution(*com.zkn.learnspringboot.web.controller..*.*(..))",returning="keys") publicvoiddoAfterReturningAdvice1(JoinPointjoinPoint,Objectkeys){ System.out.println("第一个后置返回通知的返回值:"+keys); } @AfterReturning(value="execution(*com.zkn.learnspringboot.web.controller..*.*(..))",returning="keys",argNames="keys") publicvoiddoAfterReturningAdvice2(Stringkeys){ System.out.println("第二个后置返回通知的返回值:"+keys); } /** *后置异常通知 *定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法; *throwing限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行, *对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。 *@paramjoinPoint *@paramexception */ @AfterThrowing(value="executeService()",throwing="exception") publicvoiddoAfterThrowingAdvice(JoinPointjoinPoint,Throwableexception){ //目标方法名: System.out.println(joinPoint.getSignature().getName()); if(exceptioninstanceofNullPointerException){ System.out.println("发生了空指针异常!!!!!"); } } /** *后置最终通知(目标方法只要执行完了就会执行后置通知方法) *@paramjoinPoint */ @After("executeService()") publicvoiddoAfterAdvice(JoinPointjoinPoint){ System.out.println("后置通知执行了!!!!"); } /** *环绕通知: *环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。 *环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型 */ @Around("execution(*com.zkn.learnspringboot.web.controller..*.testAround*(..))") publicObjectdoAroundAdvice(ProceedingJoinPointproceedingJoinPoint){ System.out.println("环绕通知的目标方法名:"+proceedingJoinPoint.getSignature().getName()); try{//obj之前可以写目标方法执行前的逻辑 Objectobj=proceedingJoinPoint.proceed();//调用执行目标方法 returnobj; }catch(Throwablethrowable){ throwable.printStackTrace(); } returnnull; } } 完整的Controller类代码如下: packagecom.zkn.learnspringboot.web.controller; importorg.springframework.web.bind.annotation.RequestMapping; importorg.springframework.web.bind.annotation.RestController; /** *Createdbyzknon2016/11/19. */ @RestController @RequestMapping("/aop") publicclassAopTestController{ @RequestMapping("/testBeforeService.do") publicStringtestBeforeService(Stringkey,Stringvalue){ return"key="+key+"value="+value; } @RequestMapping("/testAfterReturning.do") publicStringtestAfterReturning(Stringkey){ return"key=:"+key; } @RequestMapping("/testAfterReturning01.do") publicIntegertestAfterReturning01(Integerkey){ returnkey; } @RequestMapping("/testAfterThrowing.do") publicStringtestAfterThrowing(Stringkey){ thrownewNullPointerException(); } @RequestMapping("/testAfter.do") publicStringtestAfter(Stringkey){ thrownewNullPointerException(); } @RequestMapping("/testAfter02.do") publicStringtestAfter02(Stringkey){ returnkey; } @RequestMapping("/testAroundService.do") publicStringtestAroundService(Stringkey){ return"环绕通知:"+key; } } 本文转自:http://lib.csdn.net/article/microservice/60453?knId=1899

优秀的个人博客,低调大师

MyEclipse离线集成Maven插件

MyEclipse自带有Maven4MyEclipse插件,如果没有可以在线和离线安装的方式,在线安装由于网络问题或者插件下载地址的问题导致安装失败,现在给大家介绍离线安装的方式。 1、Maven插件下载地址:http://pan.baidu.com/s/1mi94Efe 2、在MyEclipse 安装目录下新建maven文件夹,比如我的安装目录为:C:\MyEclipseSpr10.6\MyEclipse for Spring 10\dropins\目录下新建maven文件夹,然后解压下载到Maven插件,把目录下的features文件夹和plugins文件夹拷贝到新建的maven目录下。 3、在MyEclipse安装目录下的dropins目录新建txt文本,并重命名为maven.link。 4、编辑maven.link文件,输入path=C:\MyEclipseSpr10.6\MyEclipse for Spring 10\dropins\maven。 5、重启MyEclipse,查看MyEclipse工具栏Window/Preferences下就会出现Maven的选项,到此为止你已成功安装maven插件。

优秀的个人博客,低调大师

C#接口,类,集成

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks; namespace Demo{ public abstract class MyBase { } internal class MyClass : MyBase { } public interface IMyBaseInterface { } internal interface IMyBaseInterface2 { } internal interface IMyInterface : IMyBaseInterface,IMyBaseInterface2 { } internal sealed class MyComplexClass : MyClass,IMyInterface { } class Program { static void Main(string[] args) { MyComplexClass myObj = new MyComplexClass(); Console.WriteLine(myObj.ToString()); Console.ReadKey(); } } }一个namespace可以定义多种类与接口,有意思。本文转自TBHacker博客园博客,原文链接:http://www.cnblogs.com/jiqing9006/p/6758409.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

iOS Sonar集成流程详解

所有文章目录:http://my.oschina.net/ChenTF/blog/677112 本篇文章地址:http://my.oschina.net/ChenTF/blog/708646 对您有帮助的话, 还请"赞" 一下哦, 有问题可留言或加QQ群:323276186 关于XCode8的兼容方案, 请看我的这篇文章:https://my.oschina.net/ChenTF/blog/80656 1. Sonar介绍 行业内提到"代码质量管理, 自动化质量管理", 一般指的都是通过Sonar来实现。本文的目标是实现在Sonar上显示出iOS项目, 先看张最终的效果图: 用Sonar能够实现什么? 技术债务(sonar根据"规则"扫描出不符合规则的代码) 覆盖率(单元测试覆盖率) 重复(重复的代码, 有利于提醒封装) 结构 问题1: "规则"指的是什么? 在Sonar工具中配置检测工具(规则), 然后sonar根据规则检测"质量报告文件", 得出问题数目。 比如本文配置的规则是OCLint 问题2: 技术债务的天数怎么得出? 每个规则都有对应的处理时间, 最后:问题类型1数目 * 对应时间 + 问题类型2数目 * 对应时间 +... 得到时间。 2. 概述 Sonar原生并不支持iOS, 所以就需要我们自己按照Sonar原理来安装各个工具, 并将各个工具连接起来, 生成质量结果, 并由Jenkins来实现自动化执行。 但由于涉及到的知识范围很广, 不仅需要iOS开发技术, 还需要运维知识和各个命令工具的使用方法。 而且国内外的资料少的相当可怜, 没有最佳实践, 没有专门的第三方平台, 造成很多东西都是一步步试错出来的, 一步一坎, 所以用了很长时间。 不过最后都将每个工具, 每个步骤打通, 将各个工具连接起来, 整理成.sh脚本和 .properties配置文件, 这样在后续新添项目时会很轻松。 3. 宏观介绍 3.1 配置关系图 3.2 涉及到的知识点 XCTool工具 OClint工具 Gcovr工具 Git, SVN命令 Linux命令 Jenkins工具 Sonar工具 Shell语法 Sonar-runner工具 3.3 关系逻辑讲解 每个项目添加一个配置文件(.properties), 为了在Jenkins上调用命令时能自动填充项目设置; 在Jenkins上安装各个工具(XCTool, OCLint, gcovr, sonar-runner) 与 .sh脚本, Jenkins服务器可以从代码仓库clone下代码, 然后通过.sh脚本与.properties配置文件来调用各个“工具”, 然后每个项目生成对应的“文件”; 在 .sh脚本 最后会通过sonar-runner将生成的 ”文件” 传给Sonar服务器, Sonar服务器以图形化的形式显示出对应的结果。 具体传递给哪个sonar服务器与项目名, 都是在.properties中进行配置 4.环境配置 4.1 基础知识 其实Sonar的展示是将一系列的报告文件转换得到的, 文件又是通过各个工具生成的, 所以需要先安装工具。 涉及到的工具包括(1.xctool 2.oclint, 3.gcovr, 4.sonar-runner), 虽然涉及的工具比较多, 每个用法都可详细的单独讲, 但不建议在开始时就深入了解这些, 本文会将用到的地方进行讲解, 后续深入了解请看给出的推荐资料。 在接下来的步骤中, 需要具备基础的Linuxl知识与Shell知识, 建议有空的话先学学。 Linux教程:http://c.biancheng.net/cpp/html/2726.html Shell教程:http://c.biancheng.net/cpp/view/6994.html 4.2 工具-HomeBrew “gem管理器”, 通过该工具可以安装别的gem工具, 类似cocoapods。 安装方法:http://brew.sh/index_zh-cn.html 详细介绍:https://github.com/Homebrew/brew/blob/master/share/doc/homebrew/README.md#readme 有了此工具后, 以下的工具都可通过该工具来安装, 正确的使用方式是先search 工具, 再install工具 4.3 工具-XCTool 此工具是用来代替XCode在服务器上执行Build, Test等命令, 类似xcodebuild。 安装方法:$brew install xctool 详细介绍:https://github.com/facebook/xctool 4.4 工具-OCLint OCLint是一个静态分析工具, 可以检测OC代码, 发现语法漏洞。用该工具来生成代码质量报告(技术债务)。 安装方式: $brew install Caskroom/cask/oclint 或 $brew tap oclint/formulae $ brew install oclint (不走上面的命令直接install oclint的话, 下载的版本不是最新版, 文档将不能正常生成) 4.5 工具-Gcovr 该工具是用来生成单元测试覆盖率的文档的 安装方式: $brew install gcovr 4.6 环境-JDK 教程:http://jingyan.baidu.com/article/ce09321b7c111f2bff858fea.html 5.Jenkins Jenkins一般被称为"构建器", 说简单点就是 "定时触发 + 配置任务"。Jenkins可以通过协同很多别的工具工作, 本文就是通过.sh(脚本)来协同SVN/Git 与 各个工具, 来生成文件并传给Sonar服务器。 更多Jenkins的知识具体看这两篇教程。 http://www.cnblogs.com/zz0412/p/jenkins02.html http://www.cnblogs.com/horizonli/p/5330073.html 5.1新建一个工程 5.2 代码仓库设置 5.2.1 SVN 关于credential: Jenkins检测到当前服务器访问不了代码仓库时, 会提示你设置权限, 进入Credential, 设置账号密码就可以了。 5.2.2Git方式 git的Credentials设置: 设置好username与private key(能访问git电脑的私钥)就可以了, Passphrase会自动生成。 关于公钥私钥的介绍: 一般的SSH方式是在git服务器的SSH设置里面添加自己当前电脑的公钥(id_rsa.pub)。然后当前电脑访问Git服务器时就能直接访问了。 但Jenkins需要在Git上设置好当前电脑的私钥后, 还需要将当前电脑的私钥(id_rsa)保存在Jenkins配置中。猜测是访问git时是以别的电脑来访问的。 附: Git教程:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 5.3 构建设置 Jenkins支持通过脚本构建, 一般再次设置一些环境与变量, 然后执行脚本。一般此处的设置要结合具体的脚本调用方式来决定, 所以再第六节再详细介绍。 我当前的设置是这样的: 先设置环境变量 跳转到工程根目录下 把脚本copy到当前目录下 执行脚本 5.4 定时构建 可以指定每天几点执行一次, 或每周五执行一次, 当然也可以点击左上角的"立即构建"立即执行。 例: 设置为周一到周五的9点30~9点45之间进行 6.更多说明 6.1 Sonar配置 本项目的配置指导来源于"https://github.com/octo-technology/sonar-objective-c", 后发现教程中的配置不好用, 最后找到这篇Fork的文章"https://github.com/mjdetullio/sonar-objective-c", 最后是按照第二篇的设置进行的。sonar的配置具体看第二篇文章 其实我对Sonar的配置不是很清楚, 先留个坑吧。 只知道最后通过runner-sonar工具将生成的文件传给了Sonar服务器, 至于Sonar的配置参数, 则是从.sonar-project.properties文件里面获取的。 附: Sonar官网:http://www.javatips.net/blog/sonarqube-tutorial Sonar安装:http://www.uml.org.cn/jchgj/201307251.asp 6.2 工程配置 按照教程的指导, 将run-sonar.sh和sonar-project.properties放到根目录下, 修改.properties文件的内容, 然后执行run-sonar.sh就可以了。 我是将.properties随项目走, 因为每个项目的配置不一样, 而run-sonar.sh是固定不变的, 所以放在了Jenkins服务器上, 再执行构建时将其拷贝到当前目录下。 介绍些配置过程中用到的命令, 方便大家: $ ssh 用户名@服务器地址 // 通过bash访问远程服务器 $scp /Users/xxx/Documents/svn/run-sonar.sh pmo-mini@111.222.2.444:~/opt/iosShell/run-sonar.sh // 将本地的sh文件copy到远程服务器对应的位置 $ chmod u=rxw run-sonar.sh // 修改文件权限, 使其为可读可写可执行 6.3 脚本执行流程与生成物介绍 clear ↓ build ↓ test : TEST-report.xml ↓ gcovr : coverage-xxx.xml ↓ oclint : oclint.xml TEST-report.xml 是通过xctool的test命令生成的, 如果生成失败会有2, 3行的默认文本, 这时就可以证明是执行到test时失败了, 建议先用xcode执行测试, 把环境调通了, 更多单元测试文章, 请看我的 "iOS单元测试入门与配置"篇; coverage-XiangMu.xml 是单测覆盖率报告, 如果你的单测覆盖率有误, 看这个文档。走完test后, 在XCode的路径文件下, 会生成项目的覆盖率报告, 然后gcovr命令根据这些报告生成覆盖率报告。 一般覆盖率报告有问题都是test环节有问题 oclint.xml 是技术债务报告, 一般build环节没有问题, 这个报告就没问题。 6.4 脚本分享 因为github上的脚本执行时到test命令就错误了, 所以将我修改后的分享出来。 没有找到能上次文件的地方, 把脚本所以内容全贴出来太浪费地方了, 就分享修改的地方吧, 大家从github上下载, 然后修改吧.. elseecho-n'Running tests using xctool'# runCommand sonar-reports/TEST-report.xml $xctoolCmdPrefix -scheme "$testScheme" -reporter junit GCC_GENERATE_TEST_COVERAGE_FILES=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES test # ctf:这个命令出错, 用下面的命令代替 $xctoolCmdPrefix-scheme"$testScheme"-reporter junit:TEST-report.xml GCC_GENERATE_TEST_COVERAGE_FILES=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES testecho-n'Computing coverage report' # We do it for every xcodeproject (in case of workspaces) 7.成果 7.1 技术债务 不仅可以显示出有多少不符合”规则”的代码片段,还能根据代码仓库的提交历史对应到时谁的问题 7.2 覆盖率 可以检测到单元测试的覆盖范围,监督单元测试覆盖范围。 7.3 重复 检测到相似的代码片段,提醒将常用的功能封装起来,提高重用性。 7.4 结构 项目的文件结构 7.5 代码 7.6 问题 8.未来接入方式与成本 项目中添加.properties配置文件, 修改配置项; 在Jenkins添加对应的项目; 然后? 没有然后了。 本文转自ljianbing51CTO博客,原文链接:http://blog.51cto.com/ljianbing/1930273 ,如需转载请自行联系原作者

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册