LOADING

加载过慢请开启缓存 浏览器默认开启

峰言峰语

数学技巧

数学 2025/9/30

余数性质

\[ \begin{align} (a+b) \bmod n &= (a \bmod n + b \bmod n) \bmod n \\ (a \times b) \bmod n &= (a \bmod n \times b \bmod n) \bmod n \\ a^{b} \bmod n &= (a \bmod n)^b \bmod n \end{align} \]

同余
\[ \begin{cases} \begin{align} (a - c) &\equiv (b - d) \pmod{n} \\ (a + c) &\equiv (b + d) \pmod{n} \\ (a \times c) &\equiv (b \times d) \pmod{n} \end{align}, a \equiv b \pmod{n} \; and \; c \equiv d \pmod{n} \end{cases} \]


乘法逆元

\(a \times b \equiv 1 \pmod{p}\),且\(a,\;p\)互质,则\(b\)就是\(a\)的乘法逆元,记作\(a^{-1}\),也可以叫做\(a\)\(\bmod p\)下的倒数

有了乘法逆元就可以补充性质
\[ \frac{a}{b} \bmod p = (a \times b^{-1}) \bmod p = (a \bmod p \times b^{-1} \bmod p) \bmod p \]


求逆元

  1. 扩展欧几里得算法

    欧几里得算法:有公式\(\gcd(a,b)=\gcd(b,a \bmod b)\),其中\(\gcd\)是最大公约数,通过辗转相除
    \[ \begin{align} \gcd(a, b) &= \gcd(b, a \bmod b) \\ \gcd(b, a \bmod b) &= \gcd(a \bmod b, b \bmod (a \bmod b)) \\ &\cdots \\ \gcd(x, d) &= \gcd(d, 0) = d \end{align} \]
    当得到形如\(\gcd(d, 0)\)的式子时,说明上一步中有\(x \bmod d = 0\),最大公约数为\(d\)

    扩展欧几里得算法:有公式\(ax + by = \gcd(a, b)\)\(x, \; y\)均为整数,有如下推论
    \[ \begin{align} \because &\gcd(a, b) = \gcd(b, a \bmod b) = ax + by \\ &a \bmod b = a - \lfloor\frac{a}{b}\rfloor b \\ \therefore &\gcd(b, a \bmod b) = bx^{\prime} + (a \bmod b)y^{\prime} = ax + by \\ &bx^{\prime} + (a - \lfloor\frac{a}{b}\rfloor b)y^{\prime} = ay^{\prime} + b(x^{\prime} - \lfloor\frac{a}{b}\rfloor y^{\prime}) = ax + by \\ &x = y^{\prime} \\ &y = x^{\prime} - \lfloor\frac{a}{b}\rfloor y^{\prime} \end{align} \]
    通过辗转相除
    \[ \begin{align} ax + by &= \gcd(a, b) \\ bx^{\prime} + (a \bmod b)y^{\prime} &= \gcd(b, a \bmod b) \\ &\cdots \\ dx^{\prime \prime} + 0 \times y^{\prime \prime} &= \gcd(d, 0) = d \end{align} \qquad \therefore x^{\prime \prime} = 1 \quad y^{\prime \prime} \in \mathbb{Z} \]
    根据推论往上递推最终可以求得\(ax + by = \gcd(a, b)\)中的\(x, \; y\)
    \[ \begin{align} &\because a \cdot a^{-1} \equiv 1 \pmod{p} \\ &\therefore a \cdot a^{-1} + kp = 1, \; k \in \mathbb{Z} \end{align} \]
    所以当\(\gcd(a, b) = 1\),求出的\(x\)即是\(a\)在模\(b\)下的逆元

  2. 费马小定理

    费马小定理:若\(p\)质数,对应任意整数\(a\),有\(a^{p} \equiv a \pmod{p}\)

    欧拉定理:若正整数\(a, \; n\)互质,则\(a^{\varphi(n)} \equiv 1 \pmod{n}\),其中\(\varphi(n)\)为欧拉函数,表示在小于等于\(n\)的正整数中,与\(n\)互质的数的个数

    费马小定理是欧拉定理的特殊情况,用费马小定理求逆元
    \[ a^{p-2} \equiv a^{-1} \pmod{p} \]
    用欧拉定理求逆元
    \[ a^{\varphi(n)-1} \equiv a^{-1} \pmod{n} \]


快速幂

快速幂的核心在于利用二进制位运算

计算\(a^{b}\),首先将\(b\)用二进制展开得\(b = x_{0} + 2^{1}x_{1} + 2^{2}x_{2} \dots, \; x_{n} \in \{0, 1\}\),由此\(a^{b} = a^{x_{0}} \cdot a^{2^{1}x_{1}} \cdot a^{2^{2}x_{2}} \dots\)

\(b\)中每有一个1,代表此位置要乘\(a^{2^{i}}\),否则乘1(不变),另外,有\(a^{2^{i}} \cdot a^{2^{i}} = a^{2^{i + 1}}\)

def quick_pow(base, power):
    res = 1
    while power > 0:
        if power & 1 == 1:
            res *= base
        base *= base
        power >>= 1
    return res

位运算技巧

  1. 消去最后一个1:x & (x - 1)
  2. 获取最后一个1:x & -x
  3. 找出序列中唯一出现奇数次的数:x1 ^ x2 ^ x3 ...
阅读全文

DL常用函数

深度学习 2025/9/29

1. 激活函数 (Activation)

Sigmoid

\[ \sigma(x)=\frac{1}{1+e^{-x}} \]
说明:输出在 \((0,1)\);适合二分类输出(配合 BCE),但隐藏层容易发生梯度消失。
导数
\[ \sigma'(x)=\sigma(x)(1-\sigma(x)) \]


Tanh

\[ \tanh(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}} \]
说明:输出在 \((-1,1)\),比 sigmoid 居中(均值为 0)常用于 RNN/隐藏层。仍有梯度消失问题。
导数
\[ \frac{d}{dx}\tanh(x)=1-\tanh^2(x) \]


ReLU(Rectified Linear Unit)

\[ \mathrm{ReLU}(x)=\max(0,x) \]
说明:计算简单,稀疏激活,缓解梯度消失。但负区间梯度为 0,可能出现“死神经元”。


Leaky ReLU

\[ \mathrm{LeakyReLU}(x)= \begin{cases} x,& x\ge 0\\ \alpha x,& x<0 \end{cases} \]
通常 \(\alpha=0.01\)说明:负区间保有小梯度,缓解 ReLU 死区问题。


PReLU(Parametric ReLU)

\[ \mathrm{PReLU}(x)=\begin{cases} x,& x\ge 0\\ a x,& x<0 \end{cases} \]
其中 \(a\) 为可学习参数。说明:比 Leaky 更灵活,但会增加参数。


ELU(Exponential Linear Unit)

\[ \mathrm{ELU}(x)=\begin{cases} x,& x\ge0\\ \alpha (e^x-1),& x<0 \end{cases} \]
说明:负区间趋近于 \(-\alpha\),能加速学习并部分居中激活。


SELU(Scaled ELU)

\[ \mathrm{SELU}(x)=\lambda\begin{cases} x,& x>0\\ \alpha(e^x-1),& x\le0 \end{cases} \]
配套特殊初始化和网络结构可实现“自归一化”。


GELU(Gaussian Error Linear Unit)

常用近似形式:
\[ \mathrm{GELU}(x)=x\cdot \Phi(x) \quad(\Phi \text{ 为标准正态 CDF}) \]
近似实现用:
\[ \mathrm{GELU}(x)\approx \tfrac{x}{2}\left(1+\tanh\left[\sqrt{\tfrac{2}{\pi}}\left(x+0.044715x^3\right)\right]\right) \]
说明:Transformer(BERT、GPT 系列)常用,表现优于 ReLU 的平滑替代。


Swish

\[ \mathrm{Swish}(x)=x\cdot\sigma(x) \]
说明:平滑,有时比 ReLU/GELU 更好,特别在大模型里表现不错。


Mish

\[ \mathrm{Mish}(x)=x\tanh(\ln(1+e^x)) \]
说明:平滑、无界正区间,部分任务比 Swish/ELU 更优(但计算稍贵)。


Softplus(平滑 ReLU)

\[ \mathrm{Softplus}(x)=\ln(1+e^x) \]
说明:可微分的 ReLU 近似;导数为 sigmoid。


Softmax(多类输出)

对于向量 \(z\in\mathbb{R}^K\)
\[ \mathrm{Softmax}(z)_{i}=\frac{e^{z_i}}{\sum_{j=1}^{K} e^{z_j}} \]
说明:把 logits 转为概率分布。数值稳定实现用 \(z-\max_j z_j\)(避免 exp 溢出)。
常用变体:Log-Softmax(用于 NLLLoss 的稳定实现)。


2. 损失函数 (Loss)

MSE(Mean Squared Error)

\[ L_{\mathrm{MSE}}=\frac{1}{n}\sum_{i=1}^n (y_i-\hat y_i)^2 \]
说明:回归常用;对离群点敏感(平方放大误差)。


MAE(Mean Absolute Error)

\[ L_{\mathrm{MAE}}=\frac{1}{n}\sum_{i=1}^n |y_i-\hat y_i| \]
说明:对离群点更稳健,但导数在 0 点不可导(可用 subgradient)。


Huber Loss

\[ L_\delta(a)= \begin{cases} \frac{1}{2}a^2,& |a|\le\delta\\ \delta(|a|-\tfrac{1}{2}\delta),& |a|>\delta \end{cases},\quad a=y-\hat y \]
说明:MSE 与 MAE 的折中,常用于含异常点的回归。


Cross-Entropy(多类)

如果 \(y\) 为 one-hot,\(\hat p\) 为概率分布:
\[ L=-\sum_{i} y_i \log \hat p_i \]
说明:分类任务最常用;通常与 softmax 一起使用。实现上常用 log-softmax + nll 以提高稳定性。


Binary Cross-Entropy / BCEWithLogits

对二分类,若用 logits \(z\)
\[ \mathrm{BCEWithLogits}(z,y) = -\big[y\log \sigma(z) + (1-y)\log(1-\sigma(z))\big] \]
实现提醒:用 BCEWithLogits(直接用 logits 而不是先 sigmoid)避免数值不稳定。


KL Divergence(Kullback–Leibler)

连续形式或离散形式,例如离散分布 \(P,Q\)
\[ D_{KL}(P|Q)=\sum_i P(i)\log\frac{P(i)}{Q(i)} \]
说明:VAE、知识蒸馏中常见(作为正则/约束)。非对称。


NLL(Negative Log Likelihood)

分类时给定目标类别 \(y\) 与 log-prob \(\log p(y)\)
\[ L_{\mathrm{NLL}}=-\log p(y) \]
常与 LogSoftmax 联用。


Hinge Loss(SVM)

\[ L_{\mathrm{hinge}}=\max(0, 1-y\cdot f(x)) \]
说明:二分类与 margin 的损失,常用于传统 SVM。


Focal Loss(处理类别不平衡)

\[ L_{\mathrm{focal}}=- (1-p_t)^\gamma \log(p_t) \]
其中 \(p_t\) 是预测概率,\(\gamma>0\) 控制对困难样本的聚焦。常用于目标检测(如 RetinaNet)。


Contrastive / Triplet / InfoNCE(表示学习)

  • Triplet Loss(三元组):
    \[ L=\max\big(0,\; d(a,p)-d(a,n)+\alpha\big) \]
    其中 \(a\) 为 anchor,\(p\) positive,\(n\) negative,\(d(\cdot,\cdot)\) 距离,\(\alpha\) margin。
  • InfoNCE(对比学习常见)(简化):
    \[ L=-\log\frac{\exp(\mathrm{sim}(z,z^+)/\tau)}{\sum_{i}\exp(\mathrm{sim}(z,z_i)/\tau)} \]
    \(\mathrm{sim}\) 常为余弦相似度,\(\tau\) 温度参数。

CTC Loss(连接时序分类)

用于对齐未知对齐标签(如语音识别):数学形式复杂,通常使用动态规划实现(不可直接给出单行公式)。常用框架 API(如 ctc_loss)。


3. 正则化 / 其它防过拟合手段 (Regularization)

L2 正则化(权重衰减)

\[ \Omega_{L2}(w)=\lambda \sum_i w_i^2 \]
说明:促使参数变小,常与优化器一起实现(注意:PyTorch 的 weight_decay 与直接在 loss 加 L2 有细微实现差异)。


L1 正则化

\[ \Omega_{L1}(w)=\lambda \sum_i |w_i| \]
说明:倾向稀疏权重(特征选择效果)。


Dropout

训练时对每个神经元使用 Bernoulli 随机掩码:
\[ \tilde h_i = \frac{h_i \cdot r_i}{1-p},\quad r_i\sim\mathrm{Bernoulli}(1-p) \]
说明:训练时随机丢弃,推理时按比例缩放或使用训练时的 scale。如上式为 inverted dropout(常用实现),训练-推理一致性更好。


Label Smoothing

将 one-hot 软化:
\[ y^{LS}_k=(1-\epsilon)\cdot \mathbf{1}_{k=y} + \frac{\epsilon}{K} \]
说明:防止模型过度自信,常用于分类(Transformer 中常用)。


Spectral Normalization

对层权重做谱范数规范化(常用于 GAN 的判别器),控制 Lipschitz 常数,提升稳定性。


4. 归一化 / 标准化 函数 (Normalization)

Batch Normalization(BatchNorm)

对 mini-batch 的每个特征维度 \(k\)
\[ \hat x_k=\frac{x_k-\mu_k}{\sqrt{\sigma_k^2+\epsilon}},\quad y_k=\gamma_k \hat x_k + \beta_k \]
其中 \(\mu_k,\sigma_k^2\) 为 batch 均值与方差,\(\gamma,\beta\) 可学习。说明:加速训练,允许较大学习率;小 batch 时效果变差。


Layer Normalization(LayerNorm)

对单个样本的特征维度归一:
\[ \hat x=\frac{x-\mu_{\text{layer}}}{\sqrt{\sigma_{\text{layer}}^2+\epsilon}},\quad y=\gamma\hat x+\beta \]
说明:对 RNN 和 Transformer 更稳定(与 batch size 无关)。


InstanceNorm / GroupNorm

  • InstanceNorm:对每个样本每个通道独立归一(常用于风格迁移)。
  • GroupNorm:把通道分组后做归一,适合小 batch。

Weight Normalization / RMSNorm

  • WeightNorm:对权重向量做 reparam,提高训练稳定性。
  • RMSNorm:只用 RMS 信息做归一(无需均值),计算更简单。

5. 初始化(权重初始分布)

Xavier / Glorot 初始化(均匀或正态)

针对激活函数对称(tanh):
方差设定(正态):
\[ \mathrm{Var}(w)=\frac{2}{n_\text{in}+n_\text{out}} \]
说明:保持前向/反向传播方差平稳。


He / Kaiming 初始化

针对 ReLU:
\[ \mathrm{Var}(w)=\frac{2}{n_\text{in}} \]
说明:ReLU 系列常用。


Orthogonal 初始化

令权重矩阵为正交矩阵(适用于 RNN、深层网络时稳定训练)。


6. 相似度 / 距离 函数 (Similarity / Distance)

点积(Dot product)

\[ \mathrm{dot}(x,y)=x^\top y \]
用于注意力、向量相似度基础。


余弦相似度(Cosine)

\[ \mathrm{cosine}(x,y)=\frac{x^\top y}{|x||y|} \]
说明:对向量长度不敏感,仅看角度方向。常用于检索/相似度评估。


欧氏距离(L2)

\[ d(x,y)=|x-y|_2=\sqrt{\sum_i (x_i-y_i)^2} \]


曼哈顿距离(L1)

\[ d(x,y)=|x-y|_1=\sum_i |x_i-y_i| \]


Mahalanobis 距离

\[ d_M(x,y)=\sqrt{(x-y)^\top S^{-1}(x-y)} \]
其中 \(S\) 为协方差矩阵。


7. 注意力与位置编码 (Attention & PosEnc)

Scaled Dot-Product Attention

给 query \(Q\)、key \(K\)、value \(V\)
\[ \mathrm{Attention}(Q,K,V)=\mathrm{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V \]
说明\(\sqrt{d_k}\) 用于缩放以缓解点积随维度增长而变大导致 softmax 梯度消失的问题。


Multi-Head Attention(概念公式)

\[ \mathrm{MultiHead}(Q,K,V)=\mathrm{Concat}(\text{head}_1,\dots,\text{head}_h)W^O \]
\[ \text{head}_i=\mathrm{Attention}(QW_i^Q, KW_i^K, VW_i^V) \]


Sinusoidal Positional Encoding(Transformer 原始)

对位置 \(pos\) 和维度 \(i\)
\[ \begin{aligned} PE_{(pos,2i)} &= \sin\left(\frac{pos}{10000^{2i/d}}\right)\\ PE_{(pos,2i+1)} &= \cos\left(\frac{pos}{10000^{2i/d}}\right) \end{aligned} \]
说明:为序列模型提供位置信息;也可用可学习的位置编码。


8. 优化器相关(优化器更新公式与学习率调度)

SGD(带或不带 momentum)

  • SGD
    \[ w_{t+1}=w_t - \eta \nabla_w L(w_t) \]
  • Momentum
    \[ v_{t+1}=\mu v_t + \eta \nabla_w L(w_t),\quad w_{t+1}=w_t - v_{t+1} \]
    其中 \(\mu\) 是 momentum(惯性系数)。

Adam(自适应一阶优化器)

参数:\(\beta_1,\beta_2,\epsilon\)
\[ \begin{aligned} m_t&=\beta_1 m_{t-1} + (1-\beta_1) g_t\\ v_t&=\beta_2 v_{t-1} + (1-\beta_2) g_t^2\\ \hat m_t&=\frac{m_t}{1-\beta_1^t},\quad \hat v_t=\frac{v_t}{1-\beta_2^t}\\ w_{t+1}&=w_t - \eta \frac{\hat m_t}{\sqrt{\hat v_t}+\epsilon} \end{aligned} \]
说明:广泛用于 Transformer / 大模型训练。注意学习率与 weight decay 的配合(AdamW 推荐分离 weight decay)。


RMSProp / Adagrad

  • Adagrad:历史梯度平方和累计,适合稀疏梯度。
  • RMSProp:对平方梯度做指数平均,避免 Adagrad 的学习率过快衰减。

学习率调度(常见)

  • Step decay:每 \(k\) 步降低 lr(乘以 gamma)。
  • Exponential decay\(\eta_t=\eta_0 e^{-kt}\).
  • Cosine annealing(无/有热重启):常见于训练后期退火。
  • Warmup:训练初期线性/指数升高 lr(Transformer 常用线性 warmup + 后续衰减)。
    说明:大模型常用 linear warmup + Adam + cosine decayinverse sqrt 衰减。

9. 其它常见数学工具(数值稳定性等)

LogSumExp(数值稳定的 log-sum-exp)

\[ \log\sum_i e^{x_i} = m + \log\sum_i e^{x_i-m},\quad m=\max_i x_i \]
说明:用于 stable softmax / log-likelihood 计算,避免溢出。


Softmax with Temperature

\[ \mathrm{softmax}_\tau(z)_i=\frac{e^{z_i/\tau}}{\sum_j e^{z_j/\tau}} \]
\(\tau<1\) 使分布更尖锐,\(\tau>1\) 更平滑。常用于知识蒸馏或采样控制。


Gradient Clipping(梯度裁剪)

  • 按值裁剪\(g_i=\mathrm{clip}(g_i,-c,c)\)
  • 按范数裁剪:若 \(|g|_2>c\),则 \(g\leftarrow g\cdot \frac{c}{|g|_2}\)
    说明:RNN / 大学习率下防止梯度爆炸。

小结

  • 激活函数:Transformer/大模型 通常选 GELUSwish;传统 CNN 常用 ReLU/LeakyReLU
  • 损失函数:分类用 Cross-Entropy/NLL;回归用 MSE/Huber;不平衡用 Focal
  • 归一化:Transformer 用 LayerNorm;CNN 多用 BatchNorm(但小 batch 时考虑 GroupNorm)。
  • 优化器:大模型通常用 Adam / AdamW + 线性 Warmup + Cosine Decay。注意 weight decay 的实现方式(AdamW 与旧 Adam + L2 不同)。
  • 数值稳定性:softmax/log-sum-exp、BCEWithLogits、log-softmax 等稳定实现非常重要。
  • 调参实践:学习率、batch size、权重衰减、warmup 步数对大模型影响最大。
阅读全文

线性代数(一)

线性代数 2025/9/27

向量

向量是一个抽象的数学概念,只要满足一个向量经过数值放缩之后仍是一个唯一向量两个向量经过向量加法可以得到一个唯一向量那么就可以视作向量,如此,所有的线性变换对这个定义下的向量都适用,这在建模的时候会很有用,比如将函数视为向量

也就是说只要定义好向量的形式,向量的数乘方法和向量加法就可以对其使用线性代数的工具,需要注意的是,定义的方法需要使下面等式成立
\[ \vec{v}+\vec{v}=2\vec{v} \]

向量空间

向量空间是通过选择的基底向量进行线性组合张成的空间,有几个线性无关的基底向量这个空间就有多少个维度,需要注意的是当使用坐标表示向量时,有几个坐标维度这个空间就有几个维度

矩阵

矩阵有几个视角

  1. 矩阵是一个向量空间

    把矩阵看作是向量列表,那么矩阵就是以这些向量为基底向量张成的向量空间,矩阵的秩就是向量空间的维度
    \[ \mathbf{W}=[\vec{v_{1}},\;\vec{v_{2}}...] \]

  2. 矩阵是一个线性变换

    把矩阵看作是一个关于向量变换,其内容是同在某个空间的向量的采样集合,其输入是维度大小与矩阵中向量数量相等的空间中的向量,输出是输入向量在矩阵所在的向量空间中的投影,变换内容可以理解为将输入空间的单位正交基底变换成矩阵中对应的向量的空间变换

    如:
    \[ \begin{bmatrix} 1 & 1 \\ 0 & 0 \\ 0 & 0 \end{bmatrix} \cdot \begin{bmatrix} 1 & 3 \\ 2 & 4 \end{bmatrix} = \begin{bmatrix} 3 & 7 \\ 0 & 0 \\ 0 & 0 \end{bmatrix} \]
    在这个式子中我们将最左边的矩阵视为一个变换,这个矩阵由3维空间中采样的2个向量组成,输入是2维空间中的2个向量,输出是这2个向量在矩阵所在的3维空间的投影,实际上这个变换的意思就是将一个2维空间压缩映射到3维空间中的一个轴上

矩阵乘法与复合矩阵

以矩阵是一个变换的角度去看矩阵乘法
\[ \mathbf{A}\mathbf{B}\vec{v}=\mathbf{C}\vec{v} \]
如果上式成立,那么意味着对向量进行C变换,应该与先进行B变换再进行A变换的结果一致,则称矩阵C是矩阵A、B的复合矩阵,类似于复合函数
\[ f(g(x))=f\cdot g(x) \]
所以矩阵乘法可以看作是复合矩阵变换的做法,要注意乘法的顺序

行列式

矩阵(仅限方阵)的行列式\(det(A)\)表示的是矩阵所代表的变换,对原空间的缩放比例,符号代表空间的取向与原空间是否相同,利用行列式的绝对值能够快速计算变换后的测度(如面积、体积等)

阅读全文

TencentGR总结

比赛 2025/9/15

数据格式

数据为用户与物品的交互序列,包含两种格式

  1. userprofile:包含用户id,用户特征(均为离散特征)字典,时间戳,其余列为None
  2. interaction:包含用户id,物品id,物品特征(均为离散特征)字典,交互类型(0: 曝光,1: 点击),时间戳,其余列为None

每个用户的交互序列中,有且仅有一个userprofile,其余为interaction;interaction中,曝光类型数量远大于点击类型;预测数据中存在冷启动数据

另外,部分物品有多模态特征(emb形式),维数分别为32,1024,3584,4096,3584,3584

用户序列数据总量在一百万左右,候选物品在五百万左右

数据处理

根据用户序列获取

  1. id序列(user_id开头,交互的倒数第二个item_id结束)
  2. 正样本序列(下一个序列项是物品,则记录其id作为正样本)
  3. 负样本序列(从所有具有物品特征的物品中随机采样,采样不包含序列中的物品)
  4. token类型序列(区分userprofile和interaction)
  5. next_token类型序列
  6. next_action类型序列(下一个token是interaction时的交互类型)
  7. 特征序列(每个token的特征)
  8. 正样本特征序列
  9. 负样本特征序列

所有序列缺失值使用默认值填充,并左填充到统一长度

Baseline Model

组件

  1. 所有候选item的emb词表
  2. 所有user的emb词表
  3. 序列位置编码词表(从-len到len)
  4. dropout层
  5. 离散特征词表字典(ModuleDict)
  6. 多模态特征变换层(ModuleDict)
  7. transformer层
  8. user特征dnn
  9. item特征dnn

流程

  1. 输入序列特征经过user特征dnn和item特征dnn处理进行融合(使用token类型进行区分)
  2. 加入位置编码
  3. 对序列掩码输入transformer得到序列表征
  4. 同样对正样本序列和负样本序列进行编码
  5. 使用next_token类型对损失计算进行掩码,计算bce损失

训练

9:1随机分割进行训练

改进

成绩

  • 128/2800+
  • 历史最高42

可能的改进

阅读全文

RabbitMQ笔记(一)

记录 2025/4/23

MQ(消息队列)

消息指的是两个应用间传递的数据。数据的类型有很多种形式,可能只包含文本字符串,也可能包含嵌入对象。

“消息队列(Message Queue)”是在消息的传输过程中保存消息的容器。在消息队列中,通常有生产者和消费者两个角色。生产者只负责发送数据到消息队列,谁从消息队列中取出数据处理,他不管。消费者只负责从消息队列中取出数据处理,他不管这是谁发送的数据。

消息队列作用

  1. 解耦。将系统间/组件间的通信集中到消息队列,谁需要数据谁就到消息队列里取用
  2. 异步。利用消息队列作为数据中转站,从而可以在提交数据后就响应客户端,实现异步处理
  3. 削峰。将短时间内大量请求积压在消息队列中,后面由消费者慢慢进行处理,达到削峰的目的

RabbitMQ概念

  • Broker:消息队列服务进程,包含Exchange和Queue
  • Exchange:消息队列交换机,按一定的路由规则将消息传递给Queue
  • Queue:存储消息的队列
  • Producer:生产者
  • Consumer:消费者
  • Connection:生产者或消费者与Broker的连接,包含多个Channel
  • Channel:连接内的虚拟连接,一切发布消息或使用消息都是通过它完成

交换机类型

  1. Direct

    直连交换机会将消息发送到绑定键与消息的路由键完全匹配的队列

  2. Fanout

    该交换机会将消息发送到与之绑定的所有队列

  3. Topic

    该交换机可以配置通配符规则,*匹配单个词#匹配多个词,路由键由.分隔,两个.之间记作一个词

  4. Headers

    不使用路由键进行匹配,使用请求头中的信息进行匹配

  5. X-Delayed-Message

    使用RabbitMQ插件添加的交换机,用于延迟收信

阅读全文

Docker笔记(一)

记录 2025/4/21

Docker Swarm网络

bridge网络docker_gwbridge,每个节点拥有一个,用于和外界通信

overlay网络ingress,集群拥有一个,用于集群节点之间通信

内部容器ingress-sbox绑定在这两个网络上,用于转发流量

节点node通过docker_gwbridge与外网连通

阅读全文

python笔记(一)

记录 2025/4/2

Backports

这是一个pip包,用于给早期版本的python编译器(如3.2)提供新版具有的功能

Conda环境

自定义环境路径

conda config --add envs_dirs /path/to/custom/envs/

解包

支持*解包,需要实现__iter__

支持**解包,需要实现__getitem__keys

阅读全文

组建NAS(六)

记录 2025/2/25

Docker日志管理

修改Docker守护进程配置/etc/docker/daemon.json

{
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "512m",
        "max-file": "3"
    }
}

对新建容器生效

Docker IPv6

编辑/etc/sysctl.conf开启IPv6转发

echo "net.ipv6.conf.all.forwarding = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

编辑/etc/docker/daemon.json开启IPv6

{
    "ipv6": true,
    "fixed-cidr-v6": "fd13:a4f3:a0b0::/64",
    "experimental": true,
    "ip6tables": true
}

对新建容器生效

Bind9权威DNS

拉取镜像

docker pull internetsystemsconsortium/bind9:9.20

启动容器

docker run \
        --name=bind9 \
        --restart=always \
        --publish 53:53/udp \
        --publish 53:53/tcp \
        # 远程管理端口
        # --publish 127.0.0.1:953:953/tcp \
        # name.conf
        --volume /etc/bind \
        # 工作目录
        --volume /var/cache/bind \
        # 次级域
        --volume /var/lib/bind \
        # 日志
        --volume /var/log \
        internetsystemsconsortium/bind9:9.20

编辑配置文件/etc/bind/named.conf

options {
    directory "/var/cache/bind";
    listen-on { 127.0.0.1; };
    listen-on-v6 { ::1; };
    allow-recursion {
        none;
    };
    allow-update {
        none;
    };
    allow-transfer {
        none;
    };
}
include "/path/to/zone/conf/definition";

编辑include指向的配置文件

zone "xxx.xxx." {
    type primary;
    file "/path/to/zone/file";
}

编写反向域文件以便提供PTR记录

阅读全文

maven

记录 2025/2/24

Maven

为什么使用Maven

① 一个项目就是一个工程

如果项目非常庞大,就不适合使用package来划分模块,最好是每一个模块对应一个工程,利于分工协作。借助于maven就可以将一个项目拆分成多个工程

② 项目中使用jar包,需要“复制”、“粘贴”项目的lib中

同样的jar包重复的出现在不同的项目工程中,你需要做不停的复制粘贴的重复工作。借助于maven,可以将jar包保存在“仓库”中,不管在哪个项目只要使用引用即可就行。

③ jar包需要的时候每次都要自己准备好或到官网下载

借助于maven我们可以使用统一的规范方式下载jar包,规范

④ jar包版本不一致的风险

不同的项目在使用jar包的时候,有可能会导致各个项目的jar包版本不一致,导致未执行错误。借助于maven,所有的jar包都放在“仓库”中,所有的项目都使用仓库的一份jar包。

⑤ 一个jar包依赖其他的jar包需要自己手动的加入到项目中

FileUpload组件->IO组件,commons-fileupload-1.3.jar依赖于commons-io-2.0.1.jar

极大的浪费了我们导入包的时间成本,也极大的增加了学习成本。借助于maven,它会自动的将依赖的jar包导入进来。

依赖管理工具

Maven是一个项目管理工具,可以对Java项目进行构建、依赖管理、文档生成等工作。Maven的核心概念是POM(Project Object Model),通过POM文件描述项目的基本信息、依赖、构建脚本等。

POM

POM文件是Maven项目的核心文件,它是一个XML文件,描述了项目的基本信息、依赖、构建脚本等。POM文件的位置是项目根目录下的pom.xml文件。

POM文件的基本结构如下:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>1.0.0</version>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
    </dependencies>
</project>

maven通过groupId、artifactId、version来唯一标识一个依赖。

依赖范围

Maven的依赖范围有以下几种:

  • compile:默认范围,编译、测试、运行都有效。
  • provided:编译、测试有效,运行时无效,由JDK或容器提供。
  • runtime:测试、运行有效,编译时无效。
  • test:测试有效,编译、运行时无效。
  • system:类似provided,但需要提供systemPath指定jar包的路径。

依赖版本原则

Maven的依赖版本原则如下:

  • 最短路径优先:如果两个依赖冲突,选择最短路径的依赖。
  • 先声明优先:如果两个依赖冲突,选择先声明的依赖。

构建工具

构建是指将源代码转换为可执行程序的过程,构建工具是用来自动化构建过程的工具。Maven是一个构建工具,可以对Java项目进行构建、依赖管理、文档生成等工作。

Maven的构建过程主要包括以下几个阶段:

  • 清理:删除target目录。
  • 编译:编译源代码。
  • 测试:运行单元测试。
  • 打包:打包成jar或war文件。
  • 安装:将打包文件安装到本地仓库。
  • 部署:将打包文件部署到服务器。

Maven的构建过程是通过插件实现的,每个阶段对应一个插件。Maven的插件是一个Java类,实现了Maven的插件接口,可以在Maven的生命周期中执行特定的任务。

生命周期

Maven的生命周期是指构建过程中的一系列阶段,Maven定义了三套生命周期:

  • clean:清理生命周期,包括pre-clean、clean、post-clean三个阶段。
  • default:默认生命周期,包括compile、test、package、install、deploy五个阶段。
  • site:站点生命周期,包括pre-site、site、post-site、site-deploy四个阶段。

标签

<?xml version="1.0" encoding="utf-8" ?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd">
    <!--父项目的坐标。如果项目中没有规定某个元素的值,那么父项目中的对应值即为项目的默认值。 坐标包括group ID,artifact ID和 version。-->
    <parent>
        <!--被继承的父项目的构件标识符-->
        <artifactId>spring-boot-starter-web</artifactId>
        <!--被继承的父项目的全球唯一标识符-->
        <groupId>org.springframework.boot</groupId>
        <!--被继承的父项目的版本-->
        <version>2.6.6</version>
        <!-- 父项目的pom.xml文件的相对路径。相对路径允许你选择一个不同的路径。默认值是../pom.xml。Maven首先在构建当前项目的地方寻找父项 目的pom,其次在文件系统的这个位置(relativePath位置),然后在本地仓库,最后在远程仓库寻找父项目的pom。-->
        <relativePath/>
    </parent>
    <!--声明项目描述符遵循哪一个POM模型版本。模型本身的版本很少改变,虽然如此,但它仍然是必不可少的,这是为了当Maven引入了新的特性或者其他模型变更的时候,确保稳定性。-->
    <modelVersion>4.0.0</modelVersion>
    <!--项目的全球唯一标识符,通常使用全限定的包名区分该项目和其他项目。并且构建时生成的路径也是由此生成, 如com.mycompany.app生成的相对路径为:/com/mycompany/app-->
    <groupId>asia.banseon</groupId>
    <!-- 构件的标识符,它和group ID一起唯一标识一个构件。换句话说,你不能有两个不同的项目拥有同样的artifact ID和groupID;在某个 特定的group ID下,artifact ID也必须是唯一的。构件是项目产生的或使用的一个东西,Maven为项目产生的构件包括:JARs,源 码,二进制发布和WARs等。-->
    <artifactId>banseon-maven2</artifactId>
    <!--项目产生的构件类型,例如jar、war、ear、pom。插件可以创建他们自己的构件类型,所以前面列的不是全部构件类型-->
    <packaging>jar</packaging>
    <!--项目当前版本,格式为:主版本.次版本.增量版本-限定版本号-->
    <version>1.0-SNAPSHOT</version>
    <!--项目的名称, Maven产生的文档用-->
    <name>banseon-maven</name>
    <!--项目主页的URL, Maven产生的文档用-->
    <url>http://www.baidu.com/banseon</url>
    <!-- 项目的详细描述, Maven 产生的文档用。  当这个元素能够用HTML格式描述时(例如,CDATA中的文本会被解析器忽略,就可以包含HTML标 签), 不鼓励使用纯文本描述。如果你需要修改产生的web站点的索引页面,你应该修改你自己的索引页文件,而不是调整这里的文档。-->
    <description>A maven project to study maven.</description>
    <!--描述了这个项目构建环境中的前提条件。-->
    <prerequisites>
        <!--构建该项目或使用该插件所需要的Maven的最低版本-->
        <maven/>
    </prerequisites>
    <!--项目的问题管理系统(Bugzilla, Jira, Scarab,或任何你喜欢的问题管理系统)的名称和URL,本例为 jira-->
    <issueManagement>
        <!--问题管理系统(例如jira)的名字,-->
        <system>jira</system>
        <!--该项目使用的问题管理系统的URL-->
        <url>http://jira.baidu.com/banseon</url>
    </issueManagement>
    <!--项目持续集成信息-->
    <ciManagement>
        <!--持续集成系统的名字,例如continuum-->
        <system/>
        <!--该项目使用的持续集成系统的URL(如果持续集成系统有web接口的话)。-->
        <url/>
        <!--构建完成时,需要通知的开发者/用户的配置项。包括被通知者信息和通知条件(错误,失败,成功,警告)-->
        <notifiers>
            <!--配置一种方式,当构建中断时,以该方式通知用户/开发者-->
            <notifier>
                <!--传送通知的途径-->
                <type/>
                <!--发生错误时是否通知-->
                <sendOnError>true</sendOnError>
                <!--构建失败时是否通知-->
                <sendOnFailure>false</sendOnFailure>
                <!--构建成功时是否通知-->
                <sendOnSuccess>true</sendOnSuccess>
                <!--发生警告时是否通知-->
                <sendOnWarning>true</sendOnWarning>
                <!--不赞成使用。通知发送到哪里-->
                <address/>
                <!--扩展配置项-->
                <configuration/>
            </notifier>
        </notifiers>
    </ciManagement>
    <!--项目创建年份,4位数字。当产生版权信息时需要使用这个值。-->
    <inceptionYear/>
    <!--项目相关邮件列表信息-->
    <mailingLists>
        <!--该元素描述了项目相关的所有邮件列表。自动产生的网站引用这些信息。-->
        <mailingList>
            <!--邮件的名称-->
            <name>Demo</name>
            <!--发送邮件的地址或链接,如果是邮件地址,创建文档时,mailto: 链接会被自动创建-->
            <post>banseon@126.com</post>
            <!--订阅邮件的地址或链接,如果是邮件地址,创建文档时,mailto: 链接会被自动创建-->
            <subscribe>banseon@126.com</subscribe>
            <!--取消订阅邮件的地址或链接,如果是邮件地址,创建文档时,mailto: 链接会被自动创建-->
            <unsubscribe>banseon@126.com</unsubscribe>
            <!--你可以浏览邮件信息的URL-->
            <archive>http:/hi.baidu.com/banseon/demo/dev/</archive>
        </mailingList>
    </mailingLists>
    <!--项目开发者列表-->
    <developers>
        <!--某个项目开发者的信息-->
        <developer>
            <!--SCM里项目开发者的唯一标识符-->
            <id>HELLO WORLD</id>
            <!--项目开发者的全名-->
            <name>banseon</name>
            <!--项目开发者的email-->
            <email>banseon@126.com</email>
            <!--项目开发者的主页的URL-->
            <url/>
            <!--项目开发者在项目中扮演的角色,角色元素描述了各种角色-->
            <roles>
                <role>Project Manager</role>
                <role>Architect</role>
            </roles>
            <!--项目开发者所属组织-->
            <organization>demo</organization>
            <!--项目开发者所属组织的URL-->
            <organizationUrl>http://hi.baidu.com/banseon</organizationUrl>
            <!--项目开发者属性,如即时消息如何处理等-->
            <properties>
                <dept>No</dept>
            </properties>
            <!--项目开发者所在时区, -11到12范围内的整数。-->
            <timezone>-5</timezone>
        </developer>
    </developers>
    <!--项目的其他贡献者列表-->
    <contributors>
        <!--项目的其他贡献者。参见developers/developer元素-->
        <contributor>
            <name/>
            <email/>
            <url/>
            <organization/>
            <organizationUrl/>
            <roles/>
            <timezone/>
            <properties/>
        </contributor>
    </contributors>
    <!--该元素描述了项目所有License列表。 应该只列出该项目的license列表,不要列出依赖项目的 license列表。如果列出多个license,用户可以选择它们中的一个而不是接受所有license。-->
    <licenses>
        <!--描述了项目的license,用于生成项目的web站点的license页面,其他一些报表和validation也会用到该元素。-->
        <license>
            <!--license用于法律上的名称-->
            <name>Apache 2</name>
            <!--官方的license正文页面的URL-->
            <url>http://www.baidu.com/banseon/LICENSE-2.0.txt</url>
            <!--项目分发的主要方式:
              repo,可以从Maven库下载
              manual, 用户必须手动下载和安装依赖-->
            <distribution>repo</distribution>
            <!--关于license的补充信息-->
            <comments>A business-friendly OSS license</comments>
        </license>
    </licenses>
    <!--SCM(Source Control Management)标签允许你配置你的代码库,供Maven web站点和其它插件使用。-->
    <scm>
        <!--SCM的URL,该URL描述了版本库和如何连接到版本库。欲知详情,请看SCMs提供的URL格式和列表。该连接只读。-->
        <connection>
            scm:svn:http://svn.baidu.com/banseon/maven/banseon/banseon-maven2-trunk(dao-trunk)
        </connection>
        <!--给开发者使用的,类似connection元素。即该连接不仅仅只读-->
        <developerConnection>
            scm:svn:http://svn.baidu.com/banseon/maven/banseon/dao-trunk
        </developerConnection>
        <!--当前代码的标签,在开发阶段默认为HEAD-->
        <tag/>
        <!--指向项目的可浏览SCM库(例如ViewVC或者Fisheye)的URL。-->
        <url>http://svn.baidu.com/banseon</url>
    </scm>
    <!--描述项目所属组织的各种属性。Maven产生的文档用-->
    <organization>
        <!--组织的全名-->
        <name>demo</name>
        <!--组织主页的URL-->
        <url>http://www.baidu.com/banseon</url>
    </organization>
    <!--构建项目需要的信息-->
    <build>
        <!--该元素设置了项目源码目录,当构建项目的时候,构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。-->
        <sourceDirectory>./</sourceDirectory>
        <!--该元素设置了项目脚本源码目录,该目录和源码目录不同:绝大多数情况下,该目录下的内容 会被拷贝到输出目录(因为脚本是被解释的,而不是被编译的)。-->
        <scriptSourceDirectory>./</scriptSourceDirectory>
        <!--该元素设置了项目单元测试使用的源码目录,当测试项目的时候,构建系统会编译目录里的源码。该路径是相对于pom.xml的相对路径。-->
        <testSourceDirectory>./</testSourceDirectory>
        <!--被编译过的应用程序class文件存放的目录。-->
        <outputDirectory>./</outputDirectory>
        <!--被编译过的测试class文件存放的目录。-->
        <testOutputDirectory>./</testOutputDirectory>
        <!--使用来自该项目的一系列构建扩展-->
        <extensions>
            <!--描述使用到的构建扩展。-->
            <extension>
                <!--构建扩展的groupId-->
                <groupId>org.springframework.boot</groupId>
                <!--构建扩展的artifactId-->
                <artifactId>spring-boot-starter-web</artifactId>
                <!--构建扩展的版本-->
                <version>2.6.6</version>
            </extension>
        </extensions>
        <!--当项目没有规定目标(Maven2 叫做阶段)时的默认值-->
        <defaultGoal>install</defaultGoal>
        <!--这个元素描述了项目相关的所有资源路径列表,例如和项目相关的属性文件,这些资源被包含在最终的打包文件里。-->
        <resources>
            <!--这个元素描述了项目相关或测试相关的所有资源路径-->
            <resource>
                <!-- 描述了资源的目标路径。该路径相对target/classes目录(例如${project.build.outputDirectory})。举个例 子,如果你想资源在特定的包里(org.apache.maven.messages),你就必须该元素设置为org/apache/maven /messages。然而,如果你只是想把资源放到源码目录结构里,就不需要该配置。-->
                <targetPath>./</targetPath>
                <!--是否使用参数值代替参数名。参数值取自properties元素或者文件里配置的属性,文件在filters元素里列出。-->
                <filtering>false</filtering>
                <!--描述存放资源的目录,该路径相对POM路径-->
                <directory>/</directory>
                <!--包含的模式列表,例如**/*.xml.-->
                <includes/>
                <!--排除的模式列表,例如**/*.xml-->
                <excludes/>
            </resource>
        </resources>
        <!--这个元素描述了单元测试相关的所有资源路径,例如和单元测试相关的属性文件。-->
        <testResources>
            <!--这个元素描述了测试相关的所有资源路径,参见build/resources/resource元素的说明-->
            <testResource>
                <targetPath>./</targetPath>
                <filtering>false</filtering>
                <directory>/</directory>
                <includes/>
                <excludes/>
            </testResource>
        </testResources>
        <!--构建产生的所有文件存放的目录-->
        <directory>./</directory>
        <!--产生的构件的文件名,默认值是${artifactId}-${version}。-->
        <finalName>xxx</finalName>
        <!--当filtering开关打开时,使用到的过滤器属性文件列表-->
        <filters/>
        <!--子项目可以引用的默认插件信息。该插件配置项直到被引用时才会被解析或绑定到生命周期。给定插件的任何本地配置都会覆盖这里的配置-->
        <pluginManagement>
            <!--使用的插件列表 。-->
            <plugins>
                <!--plugin元素包含描述插件所需要的信息。-->
                <plugin>
                    <!--插件在仓库里的group ID-->
                    <groupId>org.springframework.boot</groupId>
                    <!--插件在仓库里的artifact ID-->
                    <artifactId>spring-boot-starter-web</artifactId>
                    <!--被使用的插件的版本(或版本范围)-->
                    <version>2.6.6</version>
                    <!--是否从该插件下载Maven扩展(例如打包和类型处理器),由于性能原因,只有在真需要下载时,该元素才被设置成enabled。-->
                    <extensions>false</extensions>
                    <!--在构建生命周期中执行一组目标的配置。每个目标可能有不同的配置。-->
                    <executions>
                        <!--execution元素包含了插件执行需要的信息-->
                        <execution>
                            <!--执行目标的标识符,用于标识构建过程中的目标,或者匹配继承过程中需要合并的执行目标-->
                            <id>default-cli</id>
                            <!--绑定了目标的构建生命周期阶段,如果省略,目标会被绑定到源数据里配置的默认阶段-->
                            <phase>compile</phase>
                            <!--配置的执行目标-->
                            <goals/>
                            <!--配置是否被传播到子POM-->
                            <inherited>true</inherited>
                            <!--作为DOM对象的配置-->
                            <configuration/>
                        </execution>
                    </executions>
                    <!--项目引入插件所需要的额外依赖-->
                    <dependencies>
                        <!--参见dependencies/dependency元素-->
                        <dependency>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-starter-web</artifactId>
                            <version>2.6.6</version>
                        </dependency>
                    </dependencies>
                    <!--任何配置是否被传播到子项目-->
                    <inherited>true</inherited>
                    <!--作为DOM对象的配置-->
                    <configuration/>
                </plugin>
            </plugins>
        </pluginManagement>
        <!--使用的插件列表-->
        <plugins>
            <!--参见build/pluginManagement/plugins/plugin元素-->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.6.6</version>
                <extensions>false</extensions>
                <executions>
                    <execution>
                        <id>default-cli</id>
                        <phase>compile</phase>
                        <goals/>
                        <inherited>true</inherited>
                        <configuration/>
                    </execution>
                </executions>
                <dependencies>
                    <!--参见dependencies/dependency元素-->
                    <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                        <version>2.6.6</version>
                    </dependency>
                </dependencies>
                <goals/>
                <inherited>true</inherited>
                <configuration/>
            </plugin>
        </plugins>
    </build>
    <!--在列的项目构建profile,如果被激活,会修改构建处理-->
    <profiles>
        <!--根据环境参数或命令行参数激活某个构建处理-->
        <profile>
            <!--构建配置的唯一标识符。即用于命令行激活,也用于在继承时合并具有相同标识符的profile。-->
            <id>default</id>
            <!--自动触发profile的条件逻辑。Activation是profile的开启钥匙。profile的力量来自于它
            能够在某些特定的环境中自动使用某些特定的值;这些环境通过activation元素指定。activation元素并不是激活profile的唯一方式。-->
            <activation>
                <!--profile默认是否激活的标志-->
                <activeByDefault>false</activeByDefault>
                <!--当匹配的jdk被检测到,profile被激活。例如,1.4激活JDK1.4,1.4.0_2,而!1.4激活所有版本不是以1.4开头的JDK。-->
                <jdk/>
                <!--当匹配的操作系统属性被检测到,profile被激活。os元素可以定义一些操作系统相关的属性。-->
                <os>
                    <!--激活profile的操作系统的名字-->
                    <name>Windows XP</name>
                    <!--激活profile的操作系统所属家族(如 'windows')-->
                    <family>Windows</family>
                    <!--激活profile的操作系统体系结构 -->
                    <arch>x86</arch>
                    <!--激活profile的操作系统版本-->
                    <version>5.1.2600</version>
                </os>
                <!--如果Maven检测到某一个属性(其值可以在POM中通过${名称}引用),其拥有对应的名称和值,Profile就会被激活。如果值
                字段是空的,那么存在属性名称字段就会激活profile,否则按区分大小写方式匹配属性值字段-->
                <property>
                    <!--激活profile的属性的名称-->
                    <name>mavenVersion</name>
                    <!--激活profile的属性的值-->
                    <value>2.0.3</value>
                </property>
                <!--提供一个文件名,通过检测该文件的存在或不存在来激活profile。missing检查文件是否存在,如果不存在则激活
                profile。另一方面,exists则会检查文件是否存在,如果存在则激活profile。-->
                <file>
                    <!--如果指定的文件存在,则激活profile。-->
                    <exists>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</exists>
                    <!--如果指定的文件不存在,则激活profile。-->
                    <missing>/usr/local/hudson/hudson-home/jobs/maven-guide-zh-to-production/workspace/</missing>
                </file>
            </activation>
            <!--构建项目所需要的信息。参见build元素-->
            <build>
                <defaultGoal>install</defaultGoal>
                <resources>
                    <resource>
                        <targetPath>./</targetPath>
                        <filtering>false</filtering>
                        <directory>/</directory>
                        <includes/>
                        <excludes/>
                    </resource>
                </resources>
                <testResources>
                    <testResource>
                        <targetPath>./</targetPath>
                        <filtering>false</filtering>
                        <directory>/</directory>
                        <includes/>
                        <excludes/>
                    </testResource>
                </testResources>
                <directory>/</directory>
                <finalName>xxx</finalName>
                <filters/>
                <pluginManagement>
                    <plugins>
                        <!--参见build/pluginManagement/plugins/plugin元素-->
                        <plugin>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-starter-web</artifactId>
                            <version>2.6.6</version>
                            <extensions>false</extensions>
                            <executions>
                                <execution>
                                    <id>default-cli</id>
                                    <phase>compile</phase>
                                    <goals/>
                                    <inherited>true</inherited>
                                    <configuration/>
                                </execution>
                            </executions>
                            <dependencies>
                                <!--参见dependencies/dependency元素-->
                                <dependency>
                                    <groupId>org.springframework.boot</groupId>
                                    <artifactId>spring-boot-starter-web</artifactId>
                                    <version>2.6.6</version>
                                </dependency>
                            </dependencies>
                            <goals/>
                            <inherited>true</inherited>
                            <configuration/>
                        </plugin>
                    </plugins>
                </pluginManagement>
                <plugins>
                    <!--参见build/pluginManagement/plugins/plugin元素-->
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                        <version>2.6.6</version>
                        <extensions>false</extensions>  
                        <executions>
                            <execution>
                                <id>default-cli</id>
                                <phase>compile</phase>
                                <goals/>
                                <inherited>true</inherited>
                                <configuration/>
                            </execution>
                        </executions>
                        <dependencies>
                            <!--参见dependencies/dependency元素-->
                            <dependency>
                                <groupId>org.springframework.boot</groupId>
                                <artifactId>spring-boot-starter-web</artifactId>
                                <version>2.6.6</version>
                            </dependency>
                        </dependencies>
                        <goals/>
                        <inherited>true</inherited>
                        <configuration/>
                    </plugin>
                </plugins>
            </build>
            <!--模块(有时称作子项目) 被构建成项目的一部分。列出的每个模块元素是指向该模块的目录的相对路径-->
            <modules/>
            <!--发现依赖和扩展的远程仓库列表。-->
            <repositories>
                <!--参见repositories/repository元素-->
                <repository>
                    <releases>
                        <enabled>false</enabled>
                        <updatePolicy>never</updatePolicy>
                        <checksumPolicy>fail</checksumPolicy>
                    </releases>
                    <snapshots>
                        <enabled>false</enabled>
                        <updatePolicy>never</updatePolicy>
                        <checksumPolicy>fail</checksumPolicy>
                    </snapshots>
                    <id>bansoen-repository-proxy</id>
                    <name/>
                    <url/>
                    <layout>default</layout>
                </repository>
            </repositories>
            <!--发现插件的远程仓库列表,这些插件用于构建和报表-->
            <pluginRepositories>
                <!--包含需要连接到远程插件仓库的信息.参见repositories/repository元素-->
                <pluginRepository>
                    <releases>
                        <enabled>false</enabled>
                        <updatePolicy>never</updatePolicy>
                        <checksumPolicy>fail</checksumPolicy>
                    </releases>
                    <snapshots>
                        <enabled>false</enabled>
                        <updatePolicy>never</updatePolicy>
                        <checksumPolicy>fail</checksumPolicy>
                    </snapshots>
                    <id>bansoen-repository-proxy</id>
                    <name/>
                    <url/>
                    <layout>default</layout>
                </pluginRepository>
            </pluginRepositories>
            <!--该元素描述了项目相关的所有依赖。 这些依赖组成了项目构建过程中的一个个环节。它们自动从项目定义的仓库中下载。要获取更多信息,请看项目依赖机制。-->
            <dependencies>
                <!--参见dependencies/dependency元素-->
                <dependency>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                    <version>2.6.6</version>
                </dependency>
            </dependencies>
            <!--不赞成使用. 现在Maven忽略该元素.-->
            <reports/>
            <!--该元素包括使用报表插件产生报表的规范。当用户执行“mvn site”,这些报表就会运行。 在页面导航栏能看到所有报表的链接。参见reporting元素-->
            <reporting>
                ......
            </reporting>
            <!--参见dependencyManagement元素-->
            <dependencyManagement>
                <dependencies>
                    <!--参见dependencies/dependency元素-->
                    <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                        <version>2.6.6</version>
                    </dependency>
                </dependencies>
            </dependencyManagement>
            <!--参见distributionManagement元素-->
            <distributionManagement>
                ......
            </distributionManagement>
            <!--参见properties元素-->
            <properties/>
        </profile>
    </profiles>
    <!--模块(有时称作子项目) 被构建成项目的一部分。列出的每个模块元素是指向该模块的目录的相对路径-->
    <modules/>
    <!--发现依赖和扩展的远程仓库列表。-->
    <repositories>
        <!--包含需要连接到远程仓库的信息-->
        <repository>
            <!--如何处理远程仓库里发布版本的下载-->
            <releases>
                <!--true或者false表示该仓库是否为下载某种类型构件(发布版,快照版)开启。 -->
                <enabled>false</enabled>
                <!--该元素指定更新发生的频率。Maven会比较本地POM和远程POM的时间戳。这里的选项是:always(一直),daily(默认,每日),interval:X(这里X是以分钟为单位的时间间隔),或者never(从不)。-->
                <updatePolicy>always</updatePolicy>
                <!--当Maven验证构件校验文件失败时该怎么做:ignore(忽略),fail(失败),或者warn(警告)。-->
                <checksumPolicy>fail</checksumPolicy>
            </releases>
            <!-- 如何处理远程仓库里快照版本的下载。有了releases和snapshots这两组配置,POM就可以在每个单独的仓库中,为每种类型的构件采取不同的 策略。例如,可能有人会决定只为开发目的开启对快照版本下载的支持。参见repositories/repository/releases元素 -->
            <snapshots>
                <enabled>false</enabled>
                <updatePolicy>never</updatePolicy>
                <checksumPolicy>fail</checksumPolicy>
            </snapshots>
            <!--远程仓库唯一标识符。可以用来匹配在settings.xml文件里配置的远程仓库-->
            <id>banseon-repository-proxy</id>
            <!--远程仓库名称-->
            <name>banseon-repository-proxy</name>
            <!--远程仓库URL,按protocol://hostname/path形式-->
            <url>http://192.168.1.169:9999/repository/</url>
            <!-- 用于定位和排序构件的仓库布局类型-可以是default(默认)或者legacy(遗留)。Maven 2为其仓库提供了一个默认的布局;然 而,Maven 1.x有一种不同的布局。我们可以使用该元素指定布局是default(默认)还是legacy(遗留)。-->
            <layout>default</layout>
        </repository>
    </repositories>
    <!--发现插件的远程仓库列表,这些插件用于构建和报表-->
    <pluginRepositories>
        <!--包含需要连接到远程插件仓库的信息.参见repositories/repository元素-->
        <pluginRepository>
            <id>banseon-repository-proxy</id>
        </pluginRepository>
    </pluginRepositories>

    <!--该元素描述了项目相关的所有依赖。 这些依赖组成了项目构建过程中的一个个环节。它们自动从项目定义的仓库中下载。要获取更多信息,请看项目依赖机制。-->
    <dependencies>
        <dependency>
            <!--依赖的group ID-->
            <groupId>org.apache.maven</groupId>
            <!--依赖的artifact ID-->
            <artifactId>maven-artifact</artifactId>
            <!--依赖的版本号。 在Maven 2里, 也可以配置成版本号的范围。-->
            <version>3.6.3</version>
            <!-- 依赖类型,默认类型是jar。它通常表示依赖的文件的扩展名,但也有例外。一个类型可以被映射成另外一个扩展名或分类器。类型经常和使用的打包方式对应, 尽管这也有例外。一些类型的例子:jar,war,ejb-client和test-jar。如果设置extensions为 true,就可以在 plugin里定义新的类型。所以前面的类型的例子不完整。-->
            <type>jar</type>
            <!-- 依赖的分类器。分类器可以区分属于同一个POM,但不同构建方式的构件。分类器名被附加到文件名的版本号后面。例如,如果你想要构建两个单独的构件成 JAR,一个使用Java 1.4编译器,另一个使用Java 6编译器,你就可以使用分类器来生成两个单独的JAR构件。-->
            <classifier></classifier>
            <!--依赖范围。在项目发布过程中,帮助决定哪些构件被包括进来。欲知详情请参考依赖机制。
                - compile :默认范围,用于编译
                - provided:类似于编译,但支持你期待jdk或者容器提供,类似于classpath
                - runtime: 在执行时需要使用
                - test:    用于test任务时使用
                - system: 需要外在提供相应的元素。通过systemPath来取得
                - systemPath: 仅用于范围为system。提供相应的路径
                - optional:   当项目自身被依赖时,标注依赖是否传递。用于连续依赖时使用-->
            <scope>test</scope>
            <!--仅供system范围使用。注意,不鼓励使用这个元素,并且在新的版本中该元素可能被覆盖掉。该元素为依赖规定了文件系统上的路径。需要绝对路径而不是相对路径。推荐使用属性匹配绝对路径,例如${java.home}。-->
            <systemPath>/absolute-path</systemPath>
            <!--当计算传递依赖时, 从依赖构件列表里,列出被排除的依赖构件集。即告诉maven你只依赖指定的项目,不依赖项目的依赖。此元素主要用于解决版本冲突问题-->
            <exclusions>
                <exclusion>
                    <artifactId>spring-core</artifactId>
                    <groupId>org.springframework</groupId>
                </exclusion>
            </exclusions>
            <!--可选依赖,如果你在项目B中把C依赖声明为可选,你就需要在依赖于B的项目(例如项目A)中显式的引用对C的依赖。可选依赖阻断依赖的传递性。-->
            <optional>true</optional>
        </dependency>
    </dependencies>
    <!--不赞成使用. 现在Maven忽略该元素.-->
    <reports></reports>
    <!--该元素描述使用报表插件产生报表的规范。当用户执行“mvn site”,这些报表就会运行。 在页面导航栏能看到所有报表的链接。-->
    <reporting>
        <!--true,则,网站不包括默认的报表。这包括“项目信息”菜单中的报表。-->
        <excludeDefaults>false</excludeDefaults>
        <!--所有产生的报表存放到哪里。默认值是${project.build.directory}/site。-->
        <outputDirectory/>
        <!--使用的报表插件和他们的配置。-->
        <plugins>
            <!--plugin元素包含描述报表插件需要的信息-->
            <plugin>
                <!--报表插件在仓库里的group ID-->
                <groupId>org.springframework.boot</groupId>
                <!--报表插件在仓库里的artifact ID-->
                <artifactId>spring-boot-starter-web</artifactId>
                <!--被使用的报表插件的版本(或版本范围)-->
                <version>2.6.6</version>
                <!--任何配置是否被传播到子项目-->
                <inherited>true</inherited>
                <!--报表插件的配置-->
                <configuration/>
                <!--一组报表的多重规范,每个规范可能有不同的配置。一个规范(报表集)对应一个执行目标 。例如,有1,2,3,4,5,6,7,8,9个报表。1,2,5构成A报表集,对应一个执行目标。2,5,8构成B报表集,对应另一个执行目标-->
                <reportSets>
                    <!--表示报表的一个集合,以及产生该集合的配置-->
                    <reportSet>
                        <!--报表集合的唯一标识符,POM继承时用到-->
                        <id/>
                        <!--产生报表集合时,被使用的报表的配置-->
                        <configuration/>
                        <!--配置是否被继承到子POMs-->
                        <inherited/>
                        <!--这个集合里使用到哪些报表-->
                        <reports/>
                    </reportSet>
                </reportSets>
            </plugin>
        </plugins>
    </reporting>
    <!-- 继承自该项目的所有子项目的默认依赖信息。这部分的依赖信息不会被立即解析,而是当子项目声明一个依赖(必须描述group ID和 artifact ID信息),如果group ID和artifact ID以外的一些信息没有描述,则通过group ID和artifact ID 匹配到这里的依赖,并使用这里的依赖信息。-->
    <dependencyManagement>
        <dependencies>
            <!--参见dependencies/dependency元素-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.6.6</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <!--项目分发信息,在执行mvn deploy后表示要发布的位置。有了这些信息就可以把网站部署到远程服务器或者把构件部署到远程仓库。-->
    <distributionManagement>
        <!--部署项目产生的构件到远程仓库需要的信息-->
        <repository>
            <!--是分配给快照一个唯一的版本号(由时间戳和构建流水号)?还是每次都使用相同的版本号?参见repositories/repository元素-->
            <uniqueVersion>false</uniqueVersion>
            <id>banseon-maven2</id>
            <name>banseon maven2</name>
            <url>file://${basedir}/target/deploy</url>
            <layout>default</layout>
        </repository>
        <!--构件的快照部署到哪里?如果没有配置该元素,默认部署到repository元素配置的仓库,参见distributionManagement/repository元素-->
        <snapshotRepository>
            <uniqueVersion>false</uniqueVersion>
            <id>banseon-maven2</id>
            <name>Banseon-maven2 Snapshot Repository</name>
            <url>scp://svn.baidu.com/banseon:/usr/local/maven-snapshot</url>
            <layout>default</layout>
        </snapshotRepository>
        <!--部署项目的网站需要的信息-->
        <site>
            <!--部署位置的唯一标识符,用来匹配站点和settings.xml文件里的配置-->
            <id>banseon-site</id>
            <!--部署位置的名称-->
            <name>business api website</name>
            <!--部署位置的URL,按protocol://hostname/path形式-->
            <url>
                scp://svn.baidu.com/banseon:/var/www/localhost/banseon-web
            </url>
        </site>
        <!--项目下载页面的URL。如果没有该元素,用户应该参考主页。使用该元素的原因是:帮助定位那些不在仓库里的构件(由于license限制)。-->
        <downloadUrl/>
        <!--如果构件有了新的group ID和artifact ID(构件移到了新的位置),这里列出构件的重定位信息。-->
        <relocation>
            <!--构件新的group ID-->
            <groupId/>
            <!--构件新的artifact ID-->
            <artifactId/>
            <!--构件新的版本号-->
            <version/>
            <!--显示给用户的,关于移动的额外信息,例如原因。-->
            <message/>
        </relocation>
        <!-- 给出该构件在远程仓库的状态。不得在本地项目中设置该元素,因为这是工具自动更新的。有效的值有:none(默认),converted(仓库管理员从 Maven 1 POM转换过来),partner(直接从伙伴Maven 2仓库同步过来),deployed(从Maven 2实例部 署),verified(被核实时正确的和最终的)。-->
        <status>deployed</status>
    </distributionManagement>
    <!--以值替代名称,Properties可以在整个POM中使用,也可以作为触发条件(见settings.xml配置文件里activation元素的说明)。格式是<name>value</name>。-->
    <properties/>
</project>
阅读全文

spring

记录 2025/2/24

Spring Framework

IOC

IoC 是 Inversion of Control 的简写,译为“控制反转”,它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序。

Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别。Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。

IoC 容器是 Spring 框架中最重要的核心组件之一,它贯穿了 Spring 从诞生到成长的整个过程。

  • 控制反转是一种思想。

  • 控制反转是为了降低程序耦合度,提高程序扩展力。

  • 控制反转,反转的是什么?

    • 将对象的创建权利交出去,交给第三方容器负责。
    • 将对象和对象之间关系的维护权交出去,交给第三方容器负责。
  • 控制反转这种思想如何实现呢?

    • DI(Dependency Injection):依赖注入

依赖注入

依赖注入常见的实现方式包括两种:

  • 构造器注入
  • Setter 注入

Spring IoC 容器

Spring 的 IoC 容器就是 IoC思想的一个落地的产品实现。IoC容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建IoC 容器。Spring 提供了IoC 容器的两种实现方式:

  • BeanFactory
  • ApplicationContext

BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身,是 Spring 框架的基础接口,不提供完整的 IoC 功能,但是 Spring 框架中的其他组件都是以 BeanFactory 为基础构建的。

ApplicationContext 是 BeanFactory 的子接口,提供了更多的高级特性,它是 Spring 框架的一个更高级的容器,它除了提供 IoC 容器的基本功能外,还提供了事件传播、国际化信息绑定等功能。

ApplicationContext的实现类有:

  • ClassPathXmlApplicationContext:从类路径下加载配置文件
  • FileSystemXmlApplicationContext:从文件系统中加载配置文件
  • XmlWebApplicationContext:在 Web 应用中加载配置文件
  • AnnotationConfigApplicationContext:基于注解的配置类加载容器

Bean 的生命周期

Spring 容器管理 Bean 的生命周期,Spring 容器负责创建 Bean 实例,Spring 容器负责 Bean 的初始化和销毁。

Bean 的生命周期包括以下阶段:

  • 实例化 Bean:容器根据配置文件中的信息创建 Bean 实例。
  • 设置对象属性:容器在创建 Bean 的时候,会通过 set 方法设置 Bean 的属性值。
  • Bean 的后置处理器:容器会调用 Bean 的后置处理器方法。(postProcessBeforeInitialization)
  • Bean 的初始化:容器会调用 Bean 的初始化方法。
  • Bean 的后置处理器:容器会再次调用 Bean 的后置处理器方法。(postProcessAfterInitialization)
  • Bean 的销毁:容器会调用 Bean 的销毁方法。

Bean 的作用域

Bean 的作用域是指 Bean 实例的作用范围,Spring 容器支持以下几种作用域:

  • singleton:单例模式,一个 Bean 容器只有一个实例。
  • prototype:原型模式,每次从容器中获取 Bean 时,都会创建一个新的实例。
  • request:每次 HTTP 请求都会创建一个新的 Bean 实例。
  • session:每次 HTTP Session 都会创建一个新的 Bean 实例。
  • global-session:全局 Session 作用域,仅在基于 Servlet 的 Web 应用中有效。
  • application:全局作用域,整个应用中只有一个实例。
  • websocket:WebSocket 作用域,仅在基于 WebSocket 的 Web 应用中有效。
  • custom:自定义作用域。

AOP

AOP(Aspect Oriented Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善,它以通过预编译方式和运行期动态代理方式实现,在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP 的术语

  • Aspect:切面,是一个类,它包含了一些方法,这些方法可以在切入点之前或之后执行。
  • Joinpoint:连接点,是程序执行过程中的一个点,比如方法的调用或异常的处理。
  • Pointcut:切入点,是一组连接点的集合,可以通过表达式来描述。
  • Advice:通知,是切面在连接点执行的动作。
  • Introduction:引介,是一种特殊的通知,它向现有的类添加新方法和属性。
  • Target:目标对象,是被一个或多个切面所通知的对象。
  • Weaving:织入,是把切面连接到目标对象并创建新的代理对象的过程。
  • Proxy:代理,是一个对象,它通过连接到目标对象的方式间接控制对目标对象的访问。

AOP 的实现方式

  • 代理对象有接口:JDK 动态代理
  • 代理对象没有接口:CGLIB 动态代理

Resources

Spring用于访问资源的接口是 org.springframework.core.io.Resource,它是一个接口,Spring 提供了多种实现类,用于访问不同的资源。

实现类

  • UrlResource:用于访问 URL 资源。
  • ClassPathResource:用于访问类路径下的资源。
  • FileSystemResource:用于访问文件系统资源。
  • ServletContextResource:用于访问 ServletContext 资源。
  • InputStreamResource:用于访问输入流资源。
  • ByteArrayResource:用于访问字节数组资源。

加载资源

Spring 提供了 ResourceLoader 接口,用于加载资源。该接口实现类的实例可以获得一个Resource实例。ResourceLoaderAware接口是一个回调接口,用于设置ResourceLoader实例。如果 Bean 实例需要访问资源,有如下两种解决方案:

  • 获取 ResourceLoader 实例,然后调用 getResource() 方法。
  • 使用依赖注入

对于第一种方式,当程序获取 Resource 实例时,总需要提供 Resource 所在的位置,不管通过 FileSystemResource 创建实例,还是通过 ClassPathResource 创建实例,或者通过 ApplicationContext 的 getResource() 方法获取实例,都需要提供资源位置。这意味着:资源所在的物理位置将被耦合到代码中,如果资源位置发生改变,则必须改写程序。因此,通常建议采用第二种方法,让 Spring 为 Bean 实例依赖注入资源。

Validation

在开发中,我们经常遇到参数校验的需求,比如用户注册的时候,要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式,我们会把校验的代码和真正的业务处理逻辑耦合在一起,而且如果未来要新增一种校验逻辑也需要在修改多个地方。而spring validation允许通过注解的方式来定义对象校验规则,把校验和业务逻辑分离开,让代码编写更加方便。Spring Validation其实就是对Hibernate Validator进一步的封装,方便在Spring中使用。一般有多种校验方式:

  • 基于Validator接口的校验
  • 基于注解的校验
  • 基于自定义注解的校验

Spring Data

Transactions

Spring框架中的事务是通过AOP来实现的,Spring事务管理的底层实现是通过对DataSource和JDBC的封装来实现的。

基于注解的事务管理

Spring 通过 @Transactional 注解来实现事务管理,@Transactional 注解可以加在类上,也可以加在方法上。

事务属性

@Transactional 注解有以下几个属性:

  • propagation:事务的传播行为
    • Propagation.REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。
    • Propagation.SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
    • Propagation.MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
    • Propagation.REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
    • Propagation.NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    • Propagation.NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
    • Propagation.NESTED:如果当前存在事务,则在嵌套事务内执行,如果当前没有事务,则新建一个事务。
  • isolation:事务的隔离级别
  • timeout:事务的超时时间
  • readOnly:事务是否只读
  • rollbackFor:发生哪些异常回滚
  • noRollbackFor:发生哪些异常不回滚

Spring Boot

Spring Boot 是 Spring 的一个项目,它简化了 Spring 应用的初始搭建,提供了一些默认配置,可以快速地开发 Spring 应用。约定大于配置,Spring Boot 通过自动配置和起步依赖简化了项目的配置。

Spring Boot Starter

Spring Boot Starter 是 Spring Boot 的一个重要特性,它是一个依赖描述符,用于简化 Maven 或 Gradle 的配置。Spring Boot Starter 可以让你不需要关心 Spring Boot 的版本,只需要引入 Starter,Spring Boot 会自动配置项目。将功能场景提取出来,打包成一个 Starter,然后在项目中引入 Starter,就可以使用这个功能场景。

Spring Boot AutoConfiguration

版本

spring boot父项目spring-boot-starter-parent的父项目spring-boot-dependencies中定义了大量的依赖版本,这些版本是经过测试的,可以放心使用。如果我们在项目中引入了spring-boot-dependencies,就可以不用再指定版本号了。

注解

  • @SpringBootApplication:Spring Boot 应用的入口,它是一个组合注解,包含了 @Configuration@EnableAutoConfiguration@ComponentScan 注解。
  • @EnableAutoConfiguration:启用自动配置,Spring Boot 会根据项目中的依赖自动配置项目。
  • @Configuration:配置类,相当于 Spring 中的 XML 配置文件。
  • @AutoConfigurationPackage:自动配置包,用于自动配置类的扫描。将主配置类(@SpringBootApplication 注解的类)所在包及其子包下的所有类都注册到 Spring 容器中。
  • @Import:导入其他配置类。
  • @SpringBootConfiguration:Spring Boot 的配置类,它是 @Configuration 的派生注解。
  • @ConfigurationProperties:绑定配置文件中的属性值。
  • @Value:获取配置文件中的属性值。
  • @PropertySource:加载指定的配置文件。
  • @ImportResource:导入 Spring 的 XML 配置文件。

自动配置原理

spring boot启动时找到@SpringBootApplication注解的类,然后开启@EnableAutoConfiguration。其中在@EnableAutoConfiguration注解中,有一个@Import注解,这个注解导入了AutoConfigurationImportSelector类,这个类中有一个selectImports方法,这个方法会根据META-INF/spring.factories文件中的配置,获取EnableAutoConfiguration注解的值,然后根据这个值,导入对应的自动配置类。自动配置类中有@EnableConfigurationProperties注解,这个注解会导入ConfigurationPropertiesBindingPostProcessor类,这个类会将@ConfigurationProperties注解的类绑定到配置文件中的属性。自动配置类中还有很多@ConditionalOn注解,这些注解会根据条件来判断是否需要导入这个自动配置类。自动配置类中有Properties类,这个类中有很多属性,这些属性会从配置文件中读取,然后根据这些属性来配置项目。

配置加载位置

Spring Boot 会按照以下顺序加载配置文件,优先级从高到低:

  • 当前目录下的 config 目录
  • 当前目录
  • classpath 下的 config 目录
  • classpath 根目录
  • @PropertySource 注解指定的位置
  • spring.config.location 环境变量指定的位置

外部配置加载顺序

Spring Boot 会按照以下顺序加载外部配置,优先级从高到低:

  • 命令行参数
  • 来自 java:comp/env 的 JNDI 属性
  • Java 系统属性(System.getProperties())
  • 操作系统环境变量
  • RandomValuePropertySource 中的属性
  • application.propertiesapplication.yml 文件中的属性
  • @PropertySource 注解指定的属性
  • 默认属性
  • SpringApplication.setDefaultProperties 指定的属性

bootstrap和application

Spring Boot 有两个配置文件,一个是 bootstrap.propertiesbootstrap.yml,另一个是 application.propertiesapplication.ymlbootstrap 配置文件用于 Spring Boot 应用的引导阶段,它是 Spring Cloud 的配置文件,用于配置应用的上下文信息。application 配置文件用于 Spring Boot 应用的运行阶段,它是 Spring Boot 的配置文件,用于配置应用的运行信息。

加载顺序:

  • bootstrap.propertiesbootstrap.yml
  • bootstrap-{profile}.propertiesbootstrap-{profile}.yml
  • application.propertiesapplication.yml
  • application-{profile}.propertiesapplication-{profile}.yml

运行流程

Spring Boot 应用的运行流程如下:

  1. 创建 Spring Boot 应用。
    • 保存主配置类
    • 判断是否为 Web 应用
    • 获取所有的 ApplicationContextInitializer
    • 获取所有的 ApplicationListener
    • 从多个配置类中找到主配置类
  2. 调用 SpringApplication.run() 方法
    • 获取SpringApplicationRunListeners,并调用starting方法
    • 准备环境,创建环境后调用监听器environmentPrepared方法
    • 创建应用上下文(IOC容器)
    • 准备上下文,调用Initializer的初始化方法,调用监听器contextPrepared方法,最后调用监听器的contextLoaded方法
  3. 刷新应用上下文
    • 刷新应用上下文,IOC容器初始化
    • 回调事件,调用监听器的started方法
  4. 运行应用
    • callRunners方法,调用所有的CommandLineRunnerApplicationRunner的run方法
    • 回调事件ready,调用监听器的ready方法

日志

日志由日志门面(抽象层)和日志实现构成,Spring Boot 默认使用 SLF4J 作为日志门面,Logback 作为日志实现,并且引入了其他日志框架的适配器,可以使用其他日志框架。在导入依赖时,需排除默认的非 SLF4J 日志框架。

阅读全文
avatar
周文峰

疯疯癫癫,一笑一天
(笑不出来版)