Hexo


  • Home

  • Archives

Hello World

Posted on 2018-05-14

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

C++STL使用总结

Posted on 2018-04-03

learn sklearn(二) 特征选取

Posted on 2018-03-14

特征选取

概念:
将数据集中与要预测的值没有因果关系或者因果关系不大,或者冗余的特征去除,选取出对要预测的值关系密切的特征。

好处:
性能提升/提高模型的准确率

sklearn的feature_selection模块

简单特征选取

  • 根据单个特征的在整个数据集中的方差直接选择

    当某个特征在样例中方差越小时,也就是说它的一致性越高,对于整个的分类作用也就越小,当它小于 threshold时,我们就可以去除这个特征。

    在sklearn中用来 VarianceThreshold 来提取。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from sklearn.feature_selection import VarianceThreshold
    #定义特征矩阵(X)
    X = [[0, 0, 1], [0, 1, 0], [1, 0, 0], [0, 1, 1], [0, 1, 0], [0, 1, 1]]
    #如果一个特征出现的概率小于0.8,则删除其(注意:threshold是方差0.8是概率。根据 variance = p * (1 - p)计算)
    sel = VarianceThreshold(threshold=(0.8 * (1 - 0.8)))

    sel_X = sel.fit_transform(X)
    print(sel_X)
    [[0 1],
    [1 0],
    [0 0],
    [1 1],
    [1 0],
    [1 1]]
  • 单变量特征选择:Univariate feature selection

    上面的根据方差来选择特征显然太naive了,在单变量特征选择中,我们通过一些统计度量方法来选择。

    • SelectKBest:从特征值中选取K个最好的特征
    • SelectPercentile:从特征值中选取一定比例的特征
    • 对每个变量使用常用的单变量统计测试: 假阳性率(false positive rate)SelectFpr,伪发现率(false discovry rate)SelectFdr,或者族系误差(family wise error)SelectFwe。

      统计度量方法根据预测值可以分为两类:

    • 回归: f_regression, mutual_info_regression

    • 分类: chi2, f_classif, mutual_info_classif

      以SelectKBest为例:

      1
      2
      3
      4
      5
      6
      7
      8
      from sklearn.feature_selection import SelectKBest,f_classif
      from sklearn import datasets
      #load data
      iris = datasets.load_iris()
      X,Y = iris.data,iris.target
      # 使用SelectKBest函数,统计度量方法为f_classif,选取3个特征值
      Ksel = SelectKBest(f_classif, k=3).fit_transform(X, Y)
      print(Ksel.shape)

      OutPut:

      1
      (150, 3)

      TODO 参考f_classif,f_regression的详细内容

//在接着介绍sklearn的feature_selection模块前,先介绍一下有关特征选取的常用的两个过程。

递归式特征消除:Univariate feature selection

分两个部分介绍:

  • 子集搜索:递归式特征消除选择使用一个额外的估计器(这个估计器必须可以对每个特征赋予一定的权重)
  • 子集评价:通过coef_属性 或者feature_importances_属性获得每个特征的重要性,注意先归一化,去除掉最不重要的属性,知道满足要求。

提供的recursive feature elimination (RFE)函数:

- `RFE`:自动寻找到要求到的feature数量。
- `RFECV`:在一个交叉验证循环中自动找到最优的feature数量。

SelectFromModel:使用模型选取特征

总的来说类似上面的递归式特征消除,不过在子集评价中不是去掉最不重要的特征,而是去掉所有coef_属性 或者feature_importances_属性低于阀值的特征。

  • 基于L1正则选取。

    线性模型的L1正则会产生稀疏解,可以用此选取特征。可以用于此目的的稀疏评估器有用于回归的 linear_model.Lasso , 以及用于分类的 linear_model.LogisticRegression 和 svm.LinearSVC

    在 SVM 和逻辑回归中,参数 C 是用来控制稀疏性的:小的 C 会导致少的特征被选择。使用 Lasso,alpha 的值越大,越少的特征会被选择。

  • Tree-based feature selection(基于树的特征选取)

    树可以产生每个feature的重要性,因此也可用于特征选取,与SelectFromModel结合使用。

##

learn sklearn(三) SVM

Posted on 2018-03-14

SVM : 支持向量机

sklearn 中支持向量机函数主要有两类函数:

  • 回归:SVC,NuSVC,LinearSVC
  • 分类:SVR,NuSVR,LinearSVR

以SVC原型说明:

1
class sklearn.svm.SVC(C=1.0, kernel='rbf', degree=3, gamma='auto', coef0=0.0, shrinking=True, probability=False, tol=0.001, cache_size=200, class_weight=None, verbose=False, max_iter=-1, decision_function_shape='ovr', random_state=None)

C:代表SVM中经验项的重要性,在正则项与经验项中权衡。C越大,越可能过拟合,C越小,越可能欠拟合。

kernel:代表使用的核函数。常用的有:linear,rbf(高斯核),poly,sigmoid,自定义函数。

class_weight:数组形式,将第i个class的类的C替换为C * class_weight[i],提高某个类别的重要性。

sample_weight:类似class_weight,提升某个样本的重要性。
class_weight与sample_weight用来解决不平衡问题。

decision_function_shape:ovr,ovo用来解决多分类问题。

参考

理解JVM

Posted on 2018-03-13

Java虚拟机工作原理

首先从总体上介绍一下JVM(Java虚拟机)。从一个Java源文件(.java)怎样一步步执行下去的。
  • java源文件通过前段编译器(javac)编译成为.class的字节码文件。(编译)
  • JRE通过类加载器将字节码文件加载到JVM的运行时数据区。(加载)
  • 执行引擎解释或者编译类文件,再由即使编译器将字节码转化为机器码,执行代码。
  • 通过GC(garbage collection)回收对象和卸载类

JVM结构
加载(Class Loader)部分内容可以在这里找到。

理解ORM和数据库知识

Posted on 2018-03-08

ORM

ORM(Object/Relational Mapping):对象关系映射。

  1. 是什么?
    我们知道Java是面向对象的,而一部分有价值的业务数据(User,Order,Address等)会保存在数据库中,而数据库是不能保存类的,这对于面向对象的程序员简直不能忍。所以需要把数据从数据库中取出来之后还需要对数据进行组装。举一个简单的例子:
    1
    2
    3
    4
    5
    6
    7
    class User{
    private long ID;
    private String name;
    private String job;
    private int age;
    ...
    }

这个User的实例,在数据库中至少保存name,job,age,ID四个属性。用JDBC/ODBC取出来之后,必须进行组装成一个对象,需要程序员对SQL有一定的熟悉而且还麻烦。而ORM像是在java程序和底层数据库之间架了一层,程序员只需要告诉ORM框架它的对象在数据库中是怎样储存的就可以,余下的都交给ORM框架。获得数据库中储存的数据到转化为对象只需要一步:告诉ORM框架你需要的类是什么样的(比如说查找一个ID为1的对象),之后ORM框架自动生成SQL并查找到数据拼装之后返回。

  1. ORM的优势
  • 提供面向对象的支持,把数据库领域的表,行,列映射到对象领域,因为开发者更加熟悉面向对象的原则。
  • 当业务逻辑中存在大量1:1,1:m,m:n的关联关系的时候,SQL的书写会变得更加复杂。
  • 让开发者专注在业务逻辑上,而不是SQL语言上。
  • 防止SQL注入(额外功能)
  • 可以更好的移植到其他数据库(不写SQL语句)
  1. ORM的劣势
  • 速度更慢(加了一层)
  • 很多数据库原生底层的功能不能使用了(procedure等)
  • O/R映射过程比较复杂(需要学习)
  • 查询语句(比较复杂的出现join aggressive等方法时)依旧比较复杂,SQL语句对开发者来说无法像裸SQL一样控制

hibernate 三种状态

  • 只要与session关联的就是持久态。
  • Session没关联,没有OID就是瞬时状态。
  • Session没关联,有OID的就是游离状态。
  • 在调用save方法后,u此时已经是持久化对象了,记住一点:如果一个对象以及是持久化状态了,那么此时对该对象进行各种修改,或者调用多次update、save方法时,hibernate都不会发送sql语句,只有当事物提交的时候,此时hibernate才会拿当前这个对象与之前保存在session中的持久化对象进行比较,如果不相同就发送一条update的sql语句,否则就不会发送update语句
  • 当save一执行的时候,此时hibernate会根据id的生成策略往数据库中再插入一条数据,所以如果调用save方法,此时数据库会发送一条插入的语句。
    参考
    参考1
[hibernate的N+1 TODO 问题]

数据库事务的ACID,乐观锁,悲观锁

ACID

  • 原子性(Atomicity)

    原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。

  • 一致性(Consistency)

    一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。

    拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。

    一致性是语义上的,而不是语法上的。

  • 隔离性(Isolation)

    隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。

    即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。

  • 持久性(Durability)

    持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

    例如我们在使用JDBC操作数据库时,在提交事务方法后,提示用户事务操作完成,当我们程序执行完成直到看到提示后,就可以认定事务以及正确提交,即使这时候数据库出现了问题,也必须要将我们的事务完全执行完成,否则就会造成我们看到提示事务处理完毕,但是数据库因为故障而没有执行事务的重大错误。

事务的隔离级别

先介绍一下三个概念(事务的隔离级别就是针对这三个概念而设置的)

  • 脏读
    脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
  • 不可重复读
    不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。

    例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。

    不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。

  • 幻读
    如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
    幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。

事务隔离的四个级别:

  • Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
  • Repeatable read (可重复读):可避免脏读、不可重复读的发生。
  • Read committed (读已提交):可避免脏读的发生。
  • Read uncommitted (读未提交):最低级别,任何情况都无法保证。

事务隔离

锁和事务隔离的关系:
人类的好朋友的回答

企业级引用系统开发技术(1)

Posted on 2018-03-06

stateful和stateless的讨论

想要区分什么是有状态和无状态,首先要明白什么是状态。

  1. 状态是什么?比如说一个人35岁,那么这个35岁就可以视为这个”人”的状态。在对象中像这类的“状态”就是用属性保存。比如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Person{
    private int age;

    public Person(){}

    public int getAge(){
    return this.age;
    }

    public void setAge(int newAge){
    this.age = newAge;
    }
    }

这就是一个有状态的类。

  1. 在java web中,singlton和prototype的使用

    • singlton(单例)默认是在全局中只有一个实例,所有调用都使用的是这一个实例。
    • prototype(原型)每次创建都会重新创建一个实例,将construct的过程走一遍。

      优缺点:
      由于singlton只有一个实例,而现实情况中经常会有多线程访问的情况,如果singlton是一个有状态的实例,那么就有可能出现竞争的情况,对资源进行竞争。
      prototype每次都会创建,我们知道每一次创建都需要消耗时间和资源,当有很多人访问的时候,代价又难以接受。
      所以对于web中应用,如果是没有状态的类,可以实现为单例,对于有状态的类,实现为原型。

  2. 更多的讨论

    在MVC架构中,struts由于与前段端交流,常会涉及到有状态的类,因此其为原型模式;而在spring中,默认为singlton(单例)模式。
    在MVC的Controller,Service,Dao层中,我们应该尽可能实现为无状态的类,只包含方法。

    servlet为无状态的类,session为有状态的类。

    更多的讨论

RMI(远程方法调用)

从三个方面理解RMI。

  1. 目的
    远程方法调用,就是为了让在某个java虚拟机上的对象像调用本地对象一样调用另一个java 虚拟机中的对象上的方法。是牵涉到多个JVM的过程。
  2. RMI的过程
    rmi
  • 为了在两个JVM中都通,有了RMI,使用Java远程消息交换协议JRMP(Java Remote Messaging Protocol)进行通信;
  • 为了屏蔽掉通信的具体实现,在客户端有stub,服务端有skeleton,两端通过这两个代理进行远端方法调用。(相当于加了一层)
  • 到目前为止,client端并不知道server端有那些可以调用的方法。通过设置一个中间rmiregister,server将提供的方法注册到该rmiregister中,client端可以到rmiregister中查找需要的远端调用。

    远端调用实现的过程:

    1. rmiregister运行
    2. server在rmiregister注册所提供的调用(将stub上传到rmiregister)
    3. client在rmiregister查找所需要的远端调用,并将其stub下载至本地至此,client端有stub,server端有skeleton,两端可以直接通信
    4. client远端调用
    5. client的stub发出远端调用请求
    6. server端的skeleton接收到stub发过来的远端调用,解析并调用远端调用的实现
    7. 第6步的返回值被skeleton发送值stub
    8. stub解析第6步的结果并返回给client。
  1. 代码实现
    在java1.8中,已经不需要使用rmic(rmi compile)手动编译stub和skeleton了所以过程会简单些。代码步骤(假设远端调用返回的对象是Warehouse):

    1. 定义Warehouse接口,并且继承自Remote
    2. 在服务器端定义WarehouseImpl,继承自UnicastRemoteObject
    3. 编写client和server端的代码
    4. 运行rmiregister
    5. 运行server端代码
    6. 运行client端代码

      最后client端代码:Warehouse.class,client.class
      服务器端代码:Warehouse.class WarehouseImpl.class,server.class

      注意:设置CLASSPATH,添加client和server的路径到CLASSPATH,否则java找不到其对应的class文件
      使用jndi,配置jndi.properties

      代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
//Warehouse 两端都有
public interface Warehouse extends Remote
{
double getPrice(String description) throws RemoteException;
}
//client
public class WarehouseClient
{
public static void main(String[] args) throws NamingException, RemoteException
{
// System.setProperty("java.security.policy", "client.policy");
// System.setSecurityManager(new SecurityManager());
Context namingContext = new InitialContext();

System.out.print("RMI registry bindings: ");
NamingEnumeration<NameClassPair> e = namingContext.list("rmi://localhost/");
while (e.hasMore())
System.out.println(e.next().getName());

String url = "rmi://localhost:1099/central_warehouse";
Warehouse centralWarehouse = (Warehouse) namingContext.lookup(url);

Scanner in = new Scanner(System.in);
System.out.print("Enter keywords: ");
String name = in.nextLine().split("\\s+")[0];
Double price = centralWarehouse.getPrice(name);

System.out.println("Price" + ": " + price);
}
}
//WarehouseImpl
public class WarehouseImpl extends UnicastRemoteObject implements Warehouse
{
private Map<String, Double> products;

/**
* Constructs a warehouse implementation.
*/
public WarehouseImpl() throws RemoteException
{
products = new HashMap<>();
}

public void add(String keyword, Double product)
{
products.put(keyword, product);
}

public double getPrice(String description) throws RemoteException
{
return products.get(description);
}

}
//server
public class WarehouseServer
{
public static void main(String[] args) throws RemoteException, NamingException
{
// System.setProperty("java.security.policy", "server.policy");
// System.setSecurityManager(new SecurityManager());

System.out.println("Constructing server implementation...");
WarehouseImpl centralWarehouse = new WarehouseImpl();
centralWarehouse.add("java",new Double(23.5));


System.out.println("Binding server implementation to registry...");
Context namingContext = new InitialContext();
namingContext.bind("rmi:central_warehouse", centralWarehouse);
System.out.println("Waiting for invocations from clients...");
}
}

//jndi.properties

java.naming.factory.initial=com.sun.jndi.rmi.registry.RegistryContextFactory
java.naming.provider.url=rmi://localhost:1099

[TODO activation pdf2]

  1. rmi和spring结合
  1. Java程序执行过程
    宏观上来看Java程序运行的过程。
  • 编写好的.java程序被编译成为.class文件(可以加密在编译好字后尽心加密 ,然后用自定义的类加载器解密)
  • 启动Java虚拟机,类加载器加载需要的类到内存中(可以包括解密过程)
  • 执行引擎执行该类

    如下图:
    Class Loader

  1. 加载过程
    Java程序启动过程中,会按照顺序有以下几个类加载器:
    class Loader1
  • 启动类加载器(BootstrapClassLoader):使用C语言编写(如果用java编写,而这个加载器也需要使用类加载器加载,形成一个环,无法加载),主要加载jre/lib下的文件,比如rt.jar等,该类无法被开发者使用。
  • 扩展类加载器(Extension ClassLoader):该类加载器负责加载JDK安装目录下的\jre\lib\ext的类,开发者也可以直接使用扩展类加载器。
  • 应用程序类加载器(AppClassLoader):负责加载用户类路径(Classpath)所指定的类,开发者可以直接使用该类加载器,如果应用程序中没有定义过自己的类加载器,该类加载器为默认的类加载器。
  • 用户自定义类加载器(User ClassLoader):JVM自带的类加载器是从本地文件系统加载标准的java class文件,而自定义的类加载器可以做到在执行非置信代码之前,自动验证数字签名,动态地创建符合用户特定需要的定制化构建类,从特定的场所(数据库、网络中)取得java class,用户使用的plugin classloader严格来说也是属于user
    classloader。

双亲委派模型

每个类加载器加载类的时候,首先调用它的父加载器,如果他的父加载器不能加载,再轮到它加载。
好处:首先从java的内库中加载相应的类,在加载器之间形成一种加载的优先级顺序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
//check the class has been loaded or not
Class c = findLoadedClass(name);
if(c == null) {
try{
if(parent != null) {//调用父加载器,递归上去,第一个使用的加载器就是启动类加载器
c = parent.loadClass(name, false);
} else{
c = findBootstrapClassOrNull(name);
}
} catch(ClassNotFoundException e) {
//if throws the exception , the father can not complete the load
}
if(c == null) {
c = findClass(name);
}
}
if(resolve) {
resolveClass(c);
}
return c;
}

双亲委派模型

如何使用自定义的类加载器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//Book类定义
public class Book
{
public String isbn;

public Book(String isbn)
{
this.isbn = isbn;
}

public Book() {
this.isbn = "123456789";
}

public String getIsbn()
{
return isbn;
}

public void setIsbn(String isbn){
this.isbn = isbn;
}

}

//User ClassLoader
import java.io.*;
public class myClassLoader extends ClassLoader {

@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bytes = this.loadByteClass(name);
return this.defineClass(name, bytes, 0, bytes.length);
}

private byte[] loadByteClass(String name){
InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
is = new FileInputStream(new File("/home/tbxsx/文档/大三下/企业级应用系统开发技术/serverComponent1/WarehouseClient/src/" +name+".class" ));
int c = 0;
while(-1 != (c = is.read())){
baos.write(c);
}
data = baos.toByteArray();

} catch (Exception e) {
e.printStackTrace();
} finally{
try {
if(is != null)
is.close();
if(baos != null)
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
}

//main test

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
myClassLoader mc = new myClassLoader();
Class<?> c = mc.loadClass("Book");
Method[] ms = c.getMethods();
Book b = (Book) c.newInstance();
for(Method m:ms){
System.out.println(m.getName());
}
Field[] fs = c.getFields();
for(Field f:fs){
System.out.println(f.getName());
}
Method m = c.getMethod("getIsbn");
Method m1 = c.getMethod("setIsbn",String.class);

System.out.println(m.getName());
System.out.println(m1.getName());
System.out.println("m1");

System.out.println(m.invoke(b));
m1.invoke(b,"hhh");
System.out.println(m.invoke(b));

}
}

//输出

getIsbn
setIsbn
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll
isbn
getIsbn
setIsbn
m1
123456789
hhh

注意:定义ClassLoader从根本上来说就是重载findClass函数,找到需要load的类的二进制文件,在loader中处理(解密验证等等处理)之后,通过defineClass函数之后返回

invoke函数(反射)
获得反射Class类的三种反射机制:
Person person = new Person();

  • 1、通过Object类的getClass()方法:(需要先实例化一个对象)
    Class clazz1 = person.getClass();
  • 2、通过对象实例方法获取对象:(需要先实例化一个对象)
    Class clazz2 = person.class;
  • 3、类的全路径:(不许呀实例对象)通过类的加载器实现
    Class clazz3 = Class.forName("com.cn.Person");
    invoke 参考
    运行时数据区:
  • 堆(类实例,java垃圾收集器)
  • 方法区(常量入”this is the string”,常量池)
  • 虚拟机栈(方法调用栈)
  • 本地方法栈
  • 程序计数器

前两个线程公用

JVM 参考

常用代码

Posted on 2018-03-06

mvn

使用mvn生成spring boot项目:

1
2
3
4
5
6
mvn clean
mvn build
mvn install
mvn package
mvn test
mvn compile

/usr的权限问题

1
2
3
4
5
6
7
8
9
10
11
12
$ ls -al /usr
drwsr-xr-x 11 root root 4096 3月 8 10:30 .
drwxr-xr-x 25 root root 4096 3月 6 15:55 ..
drwsr-xr-x 2 root root 69632 3月 8 11:45 bin
drwsr-xr-x 2 root root 4096 11月 30 22:46 games
drwsr-xr-x 67 root root 20480 2月 28 15:20 include
drwsr-xr-x 176 root root 12288 3月 6 16:16 lib
drwsr-xr-x 11 root root 4096 11月 3 10:24 local
drwsr-xr-x 3 root root 4096 7月 20 2016 locale
drwsr-xr-x 2 root root 12288 3月 8 11:45 sbin
drwsr-xr-x 363 root root 12288 3月 6 16:16 share
drwsr-xr-x 7 root root 4096 3月 8 11:46 src

昨天一不小心将整个/usr权限改为777了,导致WiFi不能连接,sudo不能运行。也是醉了。

  1. sudo不能运行的原因。
    /usr/bin/sudo 的权限设置错误。
    进入su -
    然后修改其权限:
    chown root:root sudo #修改为root组的root用户
    chmod 4755 sudo #修改权限
    之后再进入/usr/lib/sudo/
    chown root:root sudoers.so
    chmod 4755 sudo
    到此sudo 能够运行了。
  2. 启动Soft update出错
    主要是/usr/lib/dbus-1.0/dbus-daemon-lauch-helper权限设置出错。
    改为:

    1
    -rwsr-xr-- 1 root messagebus ....
  3. 对于/usr目录下的其他软件
    sudo chmod -R 755 *

  4. 有可能/var/log/cups的文件不断增大,甚至可能是到达几十G,这有可能是/usr/lib/cups/notifier/dbus权限设置不对(具体的可以看cups的error_log文件),正确的权限是

    1
    -rwxr-xr-x  1 daemon root 14328 2月  20 01:51 dbus

修改好就可以了。

  1. 重启,没有问题了

spring-IoC-AOP

Posted on 2018-03-06

spring-IoC/DI

IoC(Inversion of Control)控制反转,IoC不是一种技术,本身是一种思想。想要理解IoC,首先需要理解两个词,Control(控制)和Inversion(反转)。

Control(控制)

什么是控制?以代码为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
public class BookController {

//@AutoWired
private BookService bookService;
public BookController(){
this.bookService = new BookService();
}

@ResponseBody
@RequestMapping(value = "bookIds",method = RequestMethod.GET)
public List<Book> bookIds(){
List<Book> list = bookService.fetchAll();
return list;
}
}

在这段代码中,BookController需要用到BookService,因此在前者中有一个后者的实例,换句话说,BookController可以通过这个实例控制BookService,这就是控制。而从另一个角度来说,也是BookController依赖于BookService(因为没有BookService,BookController的逻辑也不能实现)。

控制和依赖是共存的,控制也不局限于对另一个类的控制,还可以是文件,datasource等。

Inversion(反转)

什么是反转?我们先考虑什么是“正转”?
注意无论是“正转”还是反转,都是相对于BookController类来说的
还是以上面的代码为例,上面的代码中,BookController是占主要的地位的类,BookService只是BookController的一部分,由BookController控制BookService,这可以理解为“正转”,因为这是占主导地位的类控制占次要地位的类(也可以理解为依赖类控制被依赖的类),BookController主动new一个BookService的实例。

那么反转呢?反转就是在BookController和BookService中,BookController由原来的主动new一个对象,变为被动接受一个对象。就好像说,有一个第三方,在BookController需要一个BookService的时候,马上送上一个BookService。而这个第三方,就是spring容器。

DI(Dependency Injection)

依赖注入其实就是IoC的另一种说法。我们还是从两个方面来说什么是依赖注入。
什么是依赖:IoC控制的另一种说法,可以参考第一点
什么是注入:IoC容器给BookController送上一个BookService实例即可以视为注入。

AOP(Aspect-Oriented Programming)

概念理解,和OOP对比。

AOP面向切面编程。面向对象编程的核心是对象,一切皆对象,同样的,面向切面编程,核心是切面。想要理解什么是AOP,首先需要理解切面。

什么是切面?

OOP要求我们把功能分散到单独的类中去,做到一个类做一件事。但是当许多类都分散开来的时候,也会增加类的复杂性。一个例子就是:如果所有的类都有一个打印日志的操作,要么在每个类中重复一段打印日志的代码(重复代码);要不就是所有需要打印日志的类都依赖于一个log类(会增加所有这些类对于log类的依赖,重复逻辑)。如何才能去掉这些重复代码呢?AOP就是用来解决这个问题的,将log的方法视作一个切面,所有log操作只需要通过AOP织入即可,代码只需要写一份。
切面就是上面的log

所谓的面向切面编程,就是根据切面,在代码的适当位置(切入点)动态的插入适当的代码让其运行。

AOP:如果你有一个函数要测时间,那你就在函数开始和结束的地方各打一个时间戳,然后计算打印就行了。但如果你有一批函数,你要每个函数都这么干的话,明天老板说该上线了把debug代码都去掉怎么办,明天CTO说控制台输出太low了要改成发短信怎么办。所以你需要在一个统一的地方写这些东西。AOP就是通过配置,让符合某种条件的函数在开始和结束的时候都执行你规定的逻辑。 –摘抄自知乎

AOP理解

1
2
3
4
Aspect(切面):从所有类中横向找出的共同逻辑
Join point(连接点):从程序中找出的可以拦截点(spring中只可以是method,不能是构造器)
Advice: 需要动态插入的逻辑代码(有after,before,around等多种)
Pointcut: 切入点,可以理解为找出来的特定的连接点,Advice在只能在Pointcut中被插入。

示例

ExampleController类:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.demo.web;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Example {

@RequestMapping("/")
public String home() {
return "Hello World!";
}
}

Aspect类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.example.demo.Aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect
@Component
public class WebLogAspect {
protected static org.slf4j.Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

// @Pointcut("execution(public * com.example.demo..*.*(..))")
@Pointcut("execution(public * com.example.demo.web.Example.home(..))")
public void webLog() {
}

@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
System.out.println( "进入doBefore切面");
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();

// 记录下请求内容
logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
logger.info("ARGS : " + Arrays.toString(joinPoint.getArgs()));

}

@Around("webLog()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println( "around the aspect");
Object o = joinPoint.proceed();
System.out.println( "around the aspect1");
return o;
}

@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
}
}

输出:

1
2
3
4
5
6
7
8
around the aspect
进入doBefore切面
2018-03-07 16:23:54.237 INFO 22622 --- [nio-8888-exec-1] com.example.demo.Aop.WebLogAspect : URL : http://localhost:8888/
2018-03-07 16:23:54.238 INFO 22622 --- [nio-8888-exec-1] com.example.demo.Aop.WebLogAspect : HTTP_METHOD : GET
2018-03-07 16:23:54.238 INFO 22622 --- [nio-8888-exec-1] com.example.demo.Aop.WebLogAspect : IP : 127.0.0.1
2018-03-07 16:23:54.239 INFO 22622 --- [nio-8888-exec-1] com.example.demo.Aop.WebLogAspect : CLASS_METHOD : com.example.demo.web.Example.home
2018-03-07 16:23:54.239 INFO 22622 --- [nio-8888-exec-1] com.example.demo.Aop.WebLogAspect : ARGS : []
around the aspect1

可见执行顺序是:
Around的ProceedingJoinPoint.proceed()前的方法,Before方法,被织入的方法,Around的proceed之后的方法,After执行,然后是AfterReturing方法。

除了@Around外,每个方法里都可以加或者不加参数JoinPoint,如果有用JoinPoint的地方就加,不加也可以,JoinPoint里包含了类名、被切面的方法名,参数等属性,可供读取使用。@Around参数必须为ProceedingJoinPoint,pjp.proceed相应于执行被切面的方法。@AfterReturning方法里,可以加returning = “XXX”,XXX即为在controller里方法的返回值。

当出现异常的时候,情况比较复杂,分有没有around方法讨论,因为如果有around则around当中理因处理该Exception,如果没有处理,则该exception会抛出到上一层,然后强行结束该around的advice,接着执行After方法,然后是afterthrowing方法。如果around执行了异常处理,那么afterthrow不会执行。

总结:around在before之前,after(所有类别after方法)之前执行。
afterreturing和afterthrowing在after之后执行。
[TODO poingcut的语句编写 AOP通过代理实现的原理]
详细用法参考

spring启动的顺序

spring-data-mongodb

Posted on 2018-03-06

spring-data-mongodb

1. mapping(定义Document)

所有的映射均由org.springframework.data.mongodb.core.convert.MappingMongoConverter类实现。
几点基准:

  • 每个类均映射为一个mongodb中的Collection,Collection的名称使用驼峰式命名。
  • 除@DbRef指定的属性之外,所有的属性均保存在该类中,包括嵌入在该类里的类。

1.1 _id字段的映射

@Id,@Field,id(属性名为id)均可用来指定_id。
|Field definition|Resulting Id-Fieldname in MongoDB|
|:—:|:—:|
|String id|_id|
|@Field String id|_id|
|@Field(“x”) String id|x|
|@Id String x|_id|
|@Field(“x”) @Id String x|_id|
|||
TODO 如果id不能转化为一个ObjectId怎么办?

1.2 映射的type对应

Type Type conversion Sample
String native {“firstname” : “Dave”}

double, Double, float, Float|native|{“weight” : 42.5}|
int, Integer, short, Short|native 32-bit integer|{“height” : 42}
long, Long|native 64-bit integer|{“height” : 42}|
Date, Timestamp|native|{“date” : ISODate(“2019-11-12T23:00:00.809Z”)}|
Array, List, BasicDBList|native|{“cookies” : [ … ]}
TODO test array?

1.3 注解(Mapping annotation overview)

  • @Id - applied at the field level to mark the field used for identity purpose.

  • @Document - applied at the class level to indicate this class is a candidate for mapping to the database. You can specify the name of the collection where the database will be stored.

  • @DBRef - applied at the field to indicate it is to be stored using a com.mongodb.DBRef.

  • @Indexed - applied at the field level to describe how to index the field.

  • @CompoundIndex - applied at the type level to declare Compound Indexes

  • @GeoSpatialIndexed - applied at the field level to describe how to geoindex the field.

  • @TextIndexed - applied at the field level to mark the field to be included in the text index.

  • @Language - applied at the field level to set the language override property for text index.

  • @Transient - by default all private fields are mapped to the document, this annotation excludes the field where it is applied from being stored in the database

  • @PersistenceConstructor - marks a given constructor - even a package protected one - to use when instantiating the object from the database. Constructor arguments are mapped by name to the key values in the retrieved Document.

  • @Value - this annotation is part of the Spring Framework . Within the mapping framework it can be applied to constructor arguments. This lets you use a Spring Expression Language statement to transform a key’s value retrieved in the database before it is used to construct a domain object. In order to reference a property of a given document one has to use expressions like: @Value("#root.myProperty") where root refers to the root of the given document.

  • @Field - applied at the field level and described the name of the field as it will be represented in the MongoDB BSON document thus allowing the name to be different than the fieldname of the class.

  • @Version - applied at field level is used for optimistic locking and checked for modification on save operations. The initial value is zero which is bumped automatically on every update.
    记录的版本,示例

@TypeAlias("pers")在mongodb中该类的_class为pers。
@PersistenceConstructor标记一个构造器,指定用来构造类的实例,并可以结合@Value使用,可以达到修改构造器用处。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Document
static class ObjectContainer {

@Field("property") private final PrimitiveContainer m_property;

@PersistenceConstructor
public ObjectContainer(@Value("#root.property") PrimitiveContainer a_property) {
m_property = a_property;
}

public PrimitiveContainer property() {
return m_property;
}
}

2. 操作Mongodb

最常用的两个操作Mongodb的类是MongoTemple,Repository类。

2.1 连接Mongodb

使用MongoClient

1
2
3
public MongoClient mongoClient() {
return new MongoClient();
}

常用的MongoClient类构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public MongoClient(String host) {
this(new ServerAddress(host));
}

public MongoClient(String host, int port) {
this(new ServerAddress(host, port));
}

public MongoClient(ServerAddress addr) {
this(addr, (new Builder()).build());
}

public MongoClient(MongoClientURI uri) {
super(uri);
}

MongoClientFactoryBean对应MongoClient的工厂模式,可以用来构建MongoClient(createInstance方法)。

2.2 使用MongoTemple

MongoTemple的三种构造方法

  1. MongoTemplate(MongoClient mongo, String databaseName) - takes the com.mongodb.MongoClient object and the default database name to operate against.

  2. MongoTemplate(MongoDbFactory mongoDbFactory) - takes a MongoDbFactory object that encapsulated the com.mongodb.MongoClient object, database name, and username and password.

  3. MongoTemplate(MongoDbFactory mongoDbFactory, MongoConverter mongoConverter) - adds a MongoConverter to use for mapping.

MongoTemple的CRUD:

插入数据:

1
2
3
4
5
6
7
8
9
void save (Object objectToSave) Save the object to the default collection.

void save (Object objectToSave, String collectionName) Save the object to the specified collection.

A similar set of insert operations is listed below

void insert (Object objectToSave) Insert the object to the default collection.

void insert (Object objectToSave, String collectionName) Insert the object to the specified collection.

区别:
insert在出现相同的id的时候,会出现错误,而save会覆盖原值。(只限于id)

1
2
insertAll(Collection objectionsToSave)
insert methods that take a Collection as the first argument. This inserts a list of objects in a single batch write to the database.

Update:

1
2
3
updateFirst Updates the first document that matches the query document criteria with the provided updated document.

updateMulti Updates all objects that match the query document criteria with the provided updated document.

常见的update方法的示例

1
2
WriteResult wr = mongoTemplate.updateMulti(new Query(where("accounts.accountType").is(Account.Type.SAVINGS)),
new Update().inc("accounts.$.balance", 50.00), Account.class);

Update的方法(和mongodb中的原生update方法类似):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[TODO to review]

Update addToSet (String key, Object value) Update using the $addToSet update modifier
Update currentDate (String key) Update using the $currentDate update modifier
Update currentTimestamp (String key) Update using the $currentDate update modifier with $type timestamp
Update inc (String key, Number inc) Update using the $inc update modifier
Update max (String key, Object max) Update using the $max update modifier
Update min (String key, Object min) Update using the $min update modifier
Update multiply (String key, Number multiplier) Update using the $mul update modifier
Update pop (String key, Update.Position pos) Update using the $pop update modifier
Update pull (String key, Object value) Update using the $pull update modifier
Update pullAll (String key, Object[] values) Update using the $pullAll update modifier
Update push (String key, Object value) Update using the $push update modifier
Update pushAll (String key, Object[] values) Update using the $pushAll update modifier
Update rename (String oldName, String newName) Update using the $rename update modifier
Update set (String key, Object value) Update using the $set update modifier
Update setOnInsert (String key, Object value) Update using the $setOnInsert update modifier
Update unset (String key) Update using the $unset update modifier

删除数据

1
2
3
4
5
6
7
8
9
10
11
template.remove(tywin, "GOT");                                          <1>    
template.remove(query(where("lastname").is("lannister")), "GOT"); <2>
template.remove(new Query().limit(3), "GOT"); <3>
template.findAllAndRemove(query(where("lastname").is("lannister"), "GOT");<4>
template.findAllAndRemove(new Query().limit(3), "GOT"); <5>

Remove a single entity via its _id from the associated collection.
Remove all documents matching the criteria of the query from the GOT collection.
Remove the first 3 documents in the GOT collection. Unlike <2>, the documents to remove are identified via their _id executing the given query applying sort, limit and skip options first and then remove all at once in a separate step.
Remove all documents matching the criteria of the query from the GOT collection. Unlike <3>, documents do not get deleted in a batch but one by one.
Remove the first 3 documents in the GOT collection. Unlike <3>, documents do not get deleted in a batch but one by one.

区别:
remove当有多个需要删除的记录时,一次删除;而findAllAndRemove则是一跳一条记录删除。

Upsert数据
如果数据库中没有该记录则插入数据库中:

1
template.upsert(query(where("ssn").is(1111).and("firstName").is("Joe").and("Fraizer").is("Update")), update("address", addr), Person.class);

查找并修改数据:返回原值

1
2
3
4
5
6
7
<T> T findAndModify(Query query, Update update, Class<T> entityClass);

<T> T findAndModify(Query query, Update update, Class<T> entityClass, String collectionName);

<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass);

<T> T findAndModify(Query query, Update update, FindAndModifyOptions options, Class<T> entityClass, String collectionName);

如果想返回新值:

1
p = template.findAndModify(query, update, new FindAndModifyOptions().returnNew(true), Person.class);

The FindAndModifyOptions lets you set the options of returnNew, upsert, and remove.

查找数据:[TODO review]

  1. BasicQuery用于直接处理mongo的查找语句。

    1
    2
    BasicQuery query = new BasicQuery("{ age : { $lt : 50 }, accounts.balance : { $gt : 1000.00 }}");
    List<Person> result = mongoTemplate.find(query, Person.class);
  2. 标准面向对象的Query方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    Criteria all (Object o) Creates a criterion using the $all operator
    Criteria and (String key) Adds a chained Criteria with the specified key to the current Criteria and returns the newly created one
    Criteria andOperator (Criteria…​ criteria) Creates an and query using the $and operator for all of the provided criteria (requires MongoDB 2.0 or later)
    Criteria elemMatch (Criteria c) Creates a criterion using the $elemMatch operator
    Criteria exists (boolean b) Creates a criterion using the $exists operator
    Criteria gt (Object o) Creates a criterion using the $gt operator
    Criteria gte (Object o) Creates a criterion using the $gte operator
    Criteria in (Object…​ o) Creates a criterion using the $in operator for a varargs argument.
    Criteria in (Collection<?> collection) Creates a criterion using the $in operator using a collection
    Criteria is (Object o) Creates a criterion using field matching ({ key:value }). If the specified value is a document, the order of the fields and exact equality in the document matters.
    Criteria lt (Object o) Creates a criterion using the $lt operator
    Criteria lte (Object o) Creates a criterion using the $lte operator
    Criteria mod (Number value, Number remainder) Creates a criterion using the $mod operator
    Criteria ne (Object o) Creates a criterion using the $ne operator
    Criteria nin (Object…​ o) Creates a criterion using the $nin operator
    Criteria norOperator (Criteria…​ criteria) Creates an nor query using the $nor operator for all of the provided criteria
    Criteria not () Creates a criterion using the $not meta operator which affects the clause directly following
    Criteria orOperator (Criteria…​ criteria) Creates an or query using the $or operator for all of the provided criteria
    Criteria regex (String re) Creates a criterion using a $regex
    Criteria size (int s) Creates a criterion using the $size operator
    Criteria type (int t) Creates a criterion using the $type operator
1
2
List<Person> result = mongoTemplate.find(query(where("age").lt(50)
.and("accounts.balance").gt(1000.00d)), Person.class);
  1. 其他find的方法:

    1
    2
    3
    4
    5
    `findAll` Query for a list of objects of type T from the collection.
    `findOne` Map the results of an ad-hoc query on the collection to a single instance of an object of the specified type.
    `findById` Return an object of the given id and target class.
    `find` Map the results of an ad-hoc query on the collection to a List of the specified type.
    `findAndRemove` Map the results of an ad-hoc query on the collection to a single instance of an object of the specified type. The first document that matches the query is returned and also removed from the collection in the database.
  2. TextQuery

    1
    2
    TextQuery.searching(new TextCriteria().matching("coffee").matching("-cake"));
    TextQuery.searching(new TextCriteria().matching("coffee").notMatching("cake"));
  3. Query by Example(QBE)
    TODO

2.3 使用Spring Data Repositories

Repositories只是作为一个Spring-data的一个标示,同时也是其的一个核心借口,内部不存在方法,所有的方法都是通过Spring的内部注入机制注入。
在Repositories上层是CrudRepository。CrudRepository借口定义了几个基本的方法。spring-data同时提供JpaRepository,MongoRepository接口,屏蔽了底层实现逻辑。
在CrudRepository上层是PagingAndSortingRepository,该接口定义了分页查询等接口。

12

Tbxsx

14 posts
19 tags
© 2018 Tbxsx
Powered by Hexo
|
Theme — NexT.Pisces v5.1.4