Lock

https://tool.4xseo.com/a/24067.html

锁分类:

对数据操作的粒度分

  1. 表锁:操作时,会锁定整个表
  2. 行锁:操作时,会锁定当前行
  3. 间隙锁:操作时,锁定范围条件内的记录

对数据的操作类型分

  1. 读锁(共享锁):针对同一份数据,多个读操作可以同时进行不会互相影响

  2. 写锁(排他锁,也叫独占锁):当前操作没有完成之前,会阻塞其他写锁或读锁

在开启事务的且自动提交为关闭的状态下`

select for updateupdate 会创建 排他锁,
如果带有索引查询,则会加行锁,如果查询整个表,则会加间隙锁

lock table

session 1

lock table my_table read;

select * from my_table;
unlock tables;

sessoin 2

select * from my_table;

update my_table set id = 1; -- will blocked until session 1 unlock tables

lock record

session 1

-- session  a
set autocommit = 0;
begin;
select TRX_ID from information_schema.INNODB_TRX where trx_mysql_thread_id = CONNECTION_ID();
select * from stu_teacher where teacher_id = 1 for update;
select TRX_ID from information_schema.INNODB_TRX where trx_mysql_thread_id = CONNECTION_ID();
COMMIT;

session 2

set @@autocommit=0; 
SHOW VARIABLES LIKE 'autocommit';
BEGIN;
select * from stu_teacher where teacher_id = 1 for update;
update stu_teacher set teacher_name = 'test112' where teacher_id = 1;
COMMIT;

session 1 先执行的话 session 2的查询for update 更新会被锁住

Tx

steps


set autocommit = 0;

start transaction -- or begin;

update something set id = 1;

commit;

ISOLATION

READ_UNCOMMITED

READ_COMMITED

REPEATABLE-READ 可重复读,但会幻读(读取到新加入的行)

READ_PHANTOM

serialization

LOCK

EntryPoint


HttpRequestHandler
|
/----------\
/ \
/ \
WebSocketHttpRequestHandler SockJsHttpRequestHandler(So,text message need json format,strictly is json array)
| |
SubProtocolWebSocketHandler SockJsWebSocketHandler
| |
| WebSocketServerSockJsSession -> handleMessage -> Jackson2SockJsMessageCodec -> decode
| |
StompSubProtocolHandler StompSubProtocolHandler

AliyunVodEncryption加密分析

阿里云点播API文档地址

GetVideoPlayAuth

GetPlayInfo

预定义伪代码

covert


/**
* @param hexStr 16进制字符串,长度为16
* 把16进制字符串利用base64编码,再解码,得到长度为16的字节数组
*
*/
function convert(hexStr){
return Base64.decode(Base64.encode(str));
}

AES

//AES加密,模式为CBC,填充方式:PKCS5Padding
function AES(){
this.encrypt(content,KEY,IV){
aes.encrypt(content,KEY,IV)
}
}

返回参数说明

PlayInfoList.PlayInfo[0]

{
"Status": "Normal",
"StreamType": "video",
"Rand": "NYspn8Qc220551gz62GCFGeOOU6WxF9nr9e8c64wDbE=", //存储第一段AES key
"Size": 1368828,
"Definition": "LD",
"Fps": "25",
"Duration": "10.0254",
"ModificationTime": "2021-05-11T08:04:11Z",
"Specification": "H264.SD",
"Bitrate": "1092.283",
"Encrypt": 1,//是否加密
"PreprocessStatus": "UnPreprocess",
"Format": "m3u8",
"EncryptType": "AliyunVoDEncryption",//阿里云的私有加密
"PlayURL": "https://vod.domain.com/play.m3u8",
"NarrowBandType": "0",
"Plaintext": "4pccpVV9LIjk9s0gZCFj4t6n85PPlwZuhrL2D4fbJJU=",//存储第二段AES key
"CreationTime": "2021-05-11T08:04:05Z",
"Height": 540,
"Width": 960,
"JobId": "a7a32209e6e3429f99128b25b34a8e40"
}

逻辑分析

假设视频文件的AES keyrealKey

浏览器生成一个随机串 r1 利用RSA公钥加密,结果为randStr

服务器接受到randStr,利用私钥解密出随机串 r1

r1利用MD5生成数字摘要,再截取(8,24)位的字符串 记为rs1

convert(rs1)得到第一段加密的IVKEY,记为KEY1,IV1

再生成一段随机字符串记为r2,利用AES.encrypt(r2,KEY1,IV1) 得到上面返回结果中的 Rand

拼接r1 + r2,利用MD5生成数字摘要,再截取(8,24)为的字符串,记为rs2

convert(rs2)得到第二段加密的KEY,记为KEY2

利用AES.encrypt(realKey,KEY2,IV1) 得到上面返回的结果Plaintext

至此,整个加密逻辑分析完毕

解密TS文件

MPEG-TS文件结构

用到的工具EasyICE,DVB Inspector,tsduck

ts-header(32byte)

字段名 位数 说明
sync_byte 4bit TS package 标识,固定值0x47
transport_error_indicator 1bit 传输错误标识
payload_unit_start_indicator 1bit PES包开始标识,可以用掩码0x40 判断
transport_priority 1bit 传输优先级
PID 13bit TS package identity 0x100:视频数据,0x101:音频数据, -1:id3Track,应该从PMT表中查找
transport_scrambling_control 2bit 是否有干扰码
adaptation_field_control 2bit 是否有扩展字段,0x01:payload only,0x02:adaptation field only,0x03:adaptation field follow payload
continuity_counter 4bit pack seq

var data = []
//当遇到`PUSI(Payload unit start indicator )`标识时,获取每个ts包的payload
data.push(payload)
//遇到下一个`pusi`标识时,
//合并data中的payload,作为一个PES单元
//解密PES数据段,再把解密后的payload回写到TSPacket

reference

AES五种加密模式

aliplayer-vod.js

aes-js

jsencrypt

https://gist.github.com/manyuanrong/39f151181a193b454c3b11dac1b60e15#file-jsencrypt-js

https://g.alicdn.com/de/prismplayer/2.9.0/hls/aliplayer-hls-min.js

https://stackoverflow.com/questions/28562894/how-to-loop-an-mpeg-ts-stream

https://github.com/fy-create/TSParser

只构建parent pom

cd your-project
mvn install -N

note:

-N,--non-recursive Do not recurse into sub-projects

构建多模块

     p
|
|
-----------
| |
a -----> b

````

mvn install -pl a -am -amd


note:

-pl, –projects
构建指定的模块,模块间用逗号分隔;适合无依赖的项目
-am, –also-make (常用)
同时构建所列模块的依赖模块,比如A依赖B,B依赖C,构建B,同时构建C
-amd, –also-make-dependents
同时构建依赖于所列模块的模块,比如A依赖B,B依赖C,构建B,同时构建A

```

reference

Maven 单独构建多模块项目中的子模块

Install parent POM without building Child modules

how it works

// create worker
new SharedWorkder("https://socialclub.rockstargames.com/Home/SocketWorker") //
// self.importScripts('https://s.rsg.sc/sc/js/20201212bfdb/build/socketWorker.js');

how to debug

  1. Type chrome://inspect/#workers in chrome location bar;

  2. You can find https://socialclub.rockstargames.com/Home/SocketWorker in the Shared workers

  3. Click inpect as you can debug like debug normal session;

conclusion

//https://www.right.com.cn/forum/thread-4052504-1-1.html
//https://www.jianshu.com/p/01262e314eab
//http://alisdk-api-doc.oss-cn-hangzhou.aliyuncs.com/player/5.1.6/android/index.html?com/aliyun/player/VidPlayerConfigGen.EncryptType.html

  1. hidden the network request detail;

  2. increase debugging difficulty;

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>
0%