随记

......

AOP

PointCut

切入点

用于匹配符合某些特征的方法.

JoinPoint

连接点

程序执行过程中的一个点,如方法的执行或异常的处理。在Spring AOP中,连接点总是表示方法执行。

advice

before

beofore

目标JoinPoint执行之前执行

afterReturing

目标JoinPoint正常执行返回.

afterThrowing

目标JoinPoint 执行时抛出异常

after(finnaly)

目标JoinPoint方法执行结束

around

需要手动的调用目标JoinPoint执行.

该通知的第一个参数是ProceedingJoinPoint类型.

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;

@Aspect
public class AroundExample {

@Around("com.xyz.myapp.CommonPointcuts.businessService()")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
// start stopwatch
Object retVal = pjp.proceed();
// stop stopwatch
return retVal;
}

}

访问当前JoinPoint

任何通知可以定义该方法的第一个参数类型为(org.aspectj.lang.JoinPoint)类型,除@around通知外

  • getArgs() 返回方法参数

  • getThis() 返回代理对象

  • getTarget 返回目标对象

  • getSignature() 返回被通知的方法的描述

  • toString() 打印被通知的方法的有用描述

传递参数给Advice


@Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation() && args(account,..)")
public void validateAccount(Account account) {
// ...
}

Advice的顺序

从高到底

@Around, @Before, @After, @AfterReturning, @AfterThrowing

Method.invoke

调用链

method.invoke()
->
MethodAccessor.invoke()
-> ReflectionFactory.newMethodAccessor() -> DelegatingMethodAccessorImpl
-> invoke
-> DelegatingMethodAccessorImpl.invoke
-- delegate = NativeMethodAccessorImpl
-> invoke
if(numInvocations > ReflectionFactory.inflationThreshold())
-> acc = MethodAccessorGenerator.generateMethod
-> parent.setDelegate(acc)
invoke0()//native invoke
-- deletegate = sun.reflect.GeneratedMethodAccessor1@101df177

补充说明

  • 下文中代理类皆为MethodAccessor的子类

  • ReflectionFactory.noInflation = true 会直接生成代理类

  • 反射调用方法执行次数大于ReflectionFactory.inflationThreshold(默认15)时,会生成代理类,用于提高反射执行效率,代理类反编译后源码大致如下(以String#toCharArray为例)

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package sun.reflect;

import java.lang.reflect.InvocationTargetException;

public class GeneratedMethodAccessor1 extends MethodAccessorImpl {
public GeneratedMethodAccessor1() {
}

//var1 为原object对象,var为方法参数数组
public Object invoke(Object var1, Object[] var2) throws InvocationTargetException {
if (var1 == null) {
throw new NullPointerException();
} else {
//生成字节码时已经自动处理了对象类型
String var10000;
try {
var10000 = (String)var1;
if (var2 != null && var2.length != 0) {
throw new IllegalArgumentException();
}
} catch (NullPointerException | ClassCastException var4) {
throw new IllegalArgumentException(var4.toString());
}

try {
//实际调用 等价于 strObj.toCharArray();所以开销很小
return var10000.toCharArray();
} catch (Throwable var3) {
throw new InvocationTargetException(var3);
}
}
}
}

  • 当系统中反射调用过多时会导致metaspace溢出,因为生成了过多的代理类

  • noInflation可通过sun.reflect.noInflation配置

  • inflationThreshold可通过sun.reflect.inflationThreshold配置

Constructor.newInstance

调用链

和上文大致类似

补充说明

  • 生成代理类的代理类反编译后源码大致如下(以new String(String)为例)
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package sun.reflect;

import java.lang.reflect.InvocationTargetException;

public class GeneratedConstructorAccessor2 extends ConstructorAccessorImpl {
public GeneratedConstructorAccessor2() {
}

public Object newInstance(Object[] var1) throws InvocationTargetException {
String var10000;
String var10001;
String var10002;
try {
var10000 = new String;
var10001 = var10000;
if (var1.length != 1) {
throw new IllegalArgumentException();
}

var10002 = (String)var1[0];
} catch (NullPointerException | ClassCastException var3) {
throw new IllegalArgumentException(var3.toString());
}

try {
var10001.<init>(var10002);
return var10000;
} catch (Throwable var2) {
throw new InvocationTargetException(var2);
}
}
}

<profiles>
<profile>
<id>docker-build-local</id>
<properties>
<docker-maven-plugin.host>http://192.168.2.210:2374</docker-maven-plugin.host>
<docker-maven-plugin.registry.url>registry.cn-hangzhou.aliyuncs.com</docker-maven-plugin.registry.url>
<docker-maven-plugin.image.tag>snapshot</docker-maven-plugin.image.tag>
<docker-maven-plugin.skip.build>false</docker-maven-plugin.skip.build>
<docker-maven-plugin.skip.docker>false</docker-maven-plugin.skip.docker>
</properties>
<activation>
<property>
<name>dockerBuild</name>
<value>local</value>
</property>
</activation>
</profile>
</profiles>
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<env>
<LANG>zh_CH.UTF-8</LANG>
</env>
<runs>
<run>
echo "test something"
</run>
</runs>
</configuration>
</plugin>
</plugins>
</build>

InternetProtocol

数据包结构图

IP_DATAPACKET

各字段说明

字段命 位数 说明
version 4bit 版本号
headerLength 4bit 表示首部长度占多少个32bit数量,所以,最大首部长度为15*4byte(32bit) = 60 byte;
typeOfService(TOS) 8bit 服务类型
totalLength 16bit 整个ip数据报的长度,子节为单位,所以ip数据报最大长度为0xFF(65536)byte
identification 16bit 16位标识
fragmentOffset 16bit 片偏移 3bit标识 + 13bit片偏移
TTL 8bit 生存时间,数据包最多可以经过最多的路由数,TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃,并发送ICMP报文通知源主机
protocol 8bit 协议
checksum 16bit 首部校验和
source 32bit 源地址
destination 32bit 目的地址

头部长度合计: headerLength*4 byte


  • version: 4bit

  • headerLength: 4bit(15),表示首部长度占多少个32bit数量,所以,最大首部长度为15*4byte(32bit) = 60 byte;

  • typeOfService(TOS):8bit, 服务类型

  • totalLength:16bit,整个ip数据报的长度,子节为单位,所以ip数据报最大长度为0xFF(65536)byte

  • identification:16bit,16位标识,

  • fragmentOffset:16bit,片偏移 3bit标识 + 13bit片偏移

  • TTL :8bit,生存时间,数据包最多可以经过最多的路由数,TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃,并发送ICMP报文通知源主机

  • protocol:8bit,协议

  • checksum: 16bit,首部校验和

  • source:32bit,源地址

  • destination:32bit,目的地址

    ----
    

InternetProtocol

数据包结构图

IP_DATAPACKET

各字段说明

字段命 位数 说明
version 4bit 版本号
headerLength 4bit 表示首部长度占多少个32bit数量,所以,最大首部长度为15*4byte(32bit) = 60 byte;
typeOfService(TOS) 8bit 服务类型
totalLength 16bit 整个ip数据报的长度,子节为单位,所以ip数据报最大长度为0xFF(65536)byte
identification 16bit 16位标识
fragmentOffset 16bit 片偏移 3bit标识 + 13bit片偏移
TTL 8bit 生存时间,数据包最多可以经过最多的路由数,TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃,并发送ICMP报文通知源主机
protocol 8bit 协议
checksum 16bit 首部校验和
source 32bit 源地址
destination 32bit 目的地址

头部长度合计: headerLength*4 byte


  • version: 4bit

  • headerLength: 4bit(15),表示首部长度占多少个32bit数量,所以,最大首部长度为15*4byte(32bit) = 60 byte;

  • typeOfService(TOS):8bit, 服务类型

  • totalLength:16bit,整个ip数据报的长度,子节为单位,所以ip数据报最大长度为0xFF(65536)byte

  • identification:16bit,16位标识,

  • fragmentOffset:16bit,片偏移 3bit标识 + 13bit片偏移

  • TTL :8bit,生存时间,数据包最多可以经过最多的路由数,TTL的初始值由源主机设置(通常为32或64),一旦经过一个处理它的路由器,它的值就减去1。当该字段的值为0时,数据报就被丢弃,并发送ICMP报文通知源主机

  • protocol:8bit,协议

  • checksum: 16bit,首部校验和

  • source:32bit,源地址

  • destination:32bit,目的地址

    ----
    

主动关闭的一方会进入TIME_WAIT,此时处于TIME_WAIT状态下的端口是不能用来LISTEN
SO_REUSEADDR 开启这个选项后,即使处于TIME_WAIT状态的peer(ip:port),也可以重新使用

TCP_NO_DELAY: 默认关闭
Nagle算法(拥塞控制算法)
发送方发送的数据大于等于MSS(Maximum segement size) = MTU - IP_HDR - TCP_HDR(tcp双端建立连接后协商的每次传输可接收最大字节数)

当已debug方式启动项目时,JVM进程直接就退出了 exit code 1

项目是spring-boot 2.3.6
spring-cloud Hxon-SR7
开始以为是spring 版本原因,因为启动之前的项目(spring-boot/cloud 1.x)完全正常。

最终通过控制变量,排除法,找到了问题

IDEA自2019.3后增加了Reactor Stream debug

开启这个后,项目就无法以Jrebel -debug方式启动。真坑啊。

最后找到了Reactor stream debugger.这个插件位置:jb-idea install dir /plugins/reactivestreams-core

有时间了反编译下这个插件,看看啥原因

https://www.jetbrains.com/help/idea/reactor.html#reactor-inspections

https://blog.jetbrains.com/idea/2019/10/whats-new-in-intellij-idea-2019-3-eap6-improved-reactor-support-and-a-huge-pack-of-fixes/

MediaCodec

inputBuffer (用于解码)

outputBuffer(用于获取编码后的数据)

录屏暂停

VideoEncoderCore

WSLiveDemo

编码相关

Libyuv

https://github.com/RyanRQ/ScreenRecoder

https://github.com/HelloHuDi/ScreenCapture

https://www.twblogs.net/a/5b8dd29b2b7177188340d7da?lang=zh-cn

https://github.com/chienpm304/Zecorder

https://zhuanlan.zhihu.com/p/268441151

https://github.com/TakuSemba/RtmpPublisher

https://www.coder.work/article/3500335

https://cloud.tencent.com/developer/article/1580199


var encoder = MediaCodec.createEncoderByType("video/aac")
while(true){
var index = encoder.dequeueOutputBuffer(info,10000);
if(index == "INFO_TRY_AGAIN_LATER"){
//TODO
}else if(index == "INFO_OUTPUT_FORMAT_CHANGED"){
//TODO
}else if(index =="INFO_OUTPUT_BUFFERS_CHANGED"){
//TODO
}
}

yuv -> h.264

微信公众号h5页面

关键知识

  • uin : 微信公众号/账户 唯一id

  • username : 微信公众号/账户的用户名 微信后端自动生成?

  • username 的获取可以通过找到公众号页面,然后点击“举报”,这时候可以通过抓包的方式,或者chrome-remote-debug查看“举报”页面的url中的username参数.

公众号资料页

//微信公众号的唯一数字码?
var uni = '123545';
var uniBase64 = b64(uni);
var mpPforileUrl = `https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=${uniBase64}#wechat_redirect`;

https://mp.weixin.qq.com/mp/profile_ext?action=report&uin=777&key=777&pass_ticket=fPx54kmr6jcYdnK8qI81wat4YVhJG3imtE6y2boI0KMfM+cLv5bZD7MdmM5YrSrI&username=&useraction=[object Object]&t=0.8240767701548524&scene=&__biz=MzU0MzExMzIwOA==&is_ok=1&fromplatform=3

静默自动关注

页面引入wx-js-sdk后

执行如下代码

var username= '';
//config
// 这里获取js签名参数.
var meta = {

};
window.wx && wx.config({
debug:true,
beta: true,
appId: meta.appid,
timestamp: meta.timestamp,
nonceStr: meta.noncestr,
signature: meta.signature,
jsApiList: ["quicklyAddBrandContact"]
});

(wx.ready(function () {
wx.invoke("quicklyAddBrandContact", {
username: username,
scene: ""
}, function (e) {
//{"err_msg":"quickly_add_contact:ok"}
//备注如果 e.err_msg 中包含ok则表示关注成功
console.log(e)//这时候可能会失败,然后需要执行
});
}),
wx.error(function (e) {
console.log(e);
}));

插件开发相关资源

IDEA平台版本号

IntelliJ Platform Based Products of Recent IDE Versions

API变更说明

Api changes

使用Gradle构建

Building Plugins with Gradle

插件的扩展点 && 组件说明

ApplicationComponent

initComponent只会回调一次,无论打开多个Project窗口

ToolWindowFactory

只实例化一次

AnAction

action被点击后,可以通过回调获取当前Project

public void actionPerformed(AnActionEvent e){
Project project = e.getDataContext().getData(PlatformDataKeys.PROJECT);
}


查询API使用方式

https://www.programcreek.com/java-api-examples/?api=com.intellij.execution.filters.TextConsoleBuilderFactory

其他

JRebel插件

  1. jrebel-config-client.jar 包含jrebel扩展参数。

RebelArgs

JrebelConfiguration

LunchingArgs

RouteDefination : 路由定义,配置文件中的
|
| convert
|
Route : 实际使用的路由信息

RouteDefinationLocator

RouteLocator

Request links

ReactorNetty
|
HttpServerHandle
|
ReactorHttpHandlerAdapter
|
WebServerManager
|
HttpWebHandlerAdapter
|
ExceptionhandlingWebHandler
|
FilteringWebHandler
|
DefaultWebFilterChain
|
DispatcherHandler
|
RoutePredicateHandlerMapping
|
SimpleHandlerAdapter
|
FilteringWebHandler
|
ReactiveLoadBalancerClientFilter
|
ReactorLoadBalancer

0%