Redis持久化RDB和AOF

Redis持久化

Redis提供多种不同级别的持久化方式:一种是RDB,另一种是AOF。
RDB会根据配置的规则定时将内存中的数据持久化到硬盘上,AOF则是在每次执行写命令之后将命令记录下来。两种持久化方式可以单独使用,但是通常会将两者结合使用。
RDB持久化和AOF持久化之间的异同是非常重要的,以下几个小节将详细地介绍这这两种持久化功能,并对它们的相同和不同之处进行说明。

RDB持久化

RDB持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。
RDB方式的持久化是通过快照的方式完成的。当符合某种规则时,会将内存中的数据全量生成一份副本存储到硬盘上,这个过程称作”快照”,Redis会在以下几种情况下对数据进行快照。

  1. 根据配置规则进行自动快照。
  2. 用户执行SAVE,BGSAVE命令。
  3. 执行FLUSHALL命令。
  4. 执行复制(replication)。

    执行快照场景

    根据配置自动快照,Redis允许用户自定义快照条件,当满足条件时自动执行快照,快照规则的配置方式如下。
    1
    2
    3
    save 900 1
    save 300 10
    save 60 10000

每个快照条件独占一行,他们之间是或(||)关系,只要满足任何一个就进行快照。上面配置save后的第一个参数T是时间,单位是秒,第二个参数M是更改的键的个数,含义是:当时间T内被更改的键的个数大于M时,自动进行快照。比如save 900 1的含义是15分钟内(900s)被更改的键的个数大于1时,自动进行快照操作。

最大值段和(分治法,动态规划)

问题

概念:给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整均为负数时定义子段和为0,依此定义,所求的最优值为:Max{0,a[i]+a[i+1]+…+a[j]},1<=i<=j<=n
一个数组a[]:需要求最大子段和的数组;
一个数组b[]:数组a子段和的数组,{a[0],a[0]+a[1],a[0]+a[1]+a[2]...........}
例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20。

解题

分治法

思路

如果将所给的序列a[1:n]分为长度相等的两段a[1:n/2]a[n/2+1:n],分别求出这两段的最大子段和,则a[1:n]的最大子段和:
a[]:1..........................n
分段处理:1..........n/2........n

三种情况

  • a[1:n]的最大子段和与a[1:n/2]的最大子段和相同(左边的子段和)
  • a[1:n]的最大子段和与a[n/2+1:n]的最大子段和相同(右边的子段和)
  • a[1:n]的最大子段和为a[i]+…+a[j],并且1<=i<=n/2,n/2+1<=j<=n。(子段和=左边子段和+右边子段和)

对于(1)和(2)两种情况可递归求得,但是对于情况(3),容易看出a[n/2],a[n/2+1]在最大子段中。
第3种情况:我们可以在a[1:n/2]中计算出s1=max(a[n/2]+a[n/2-1]+…+a[i]),0<=i<=n/2,并在a[n/2+1:n]中计算出s2= max(a[n/2+1]+a[n/2+2]+…+a[i]),n/2+1<=i<=n。则s1+s2为出现情况(3)的最大子段和。

分治算法

基本思想

当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出。对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法。如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。这就是分治策略的基本思想。
分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。
即一种分目标完成程序算法,简单问题可用二分法完成。
Java有ForkJoin模式,MongoDB有MapReduce模式,这些都是分而治之的思想。

步骤

分治法解题的一般步骤:

  1. 分解,将要解决的问题划分成若干规模较小的同类问题。
  2. 求解,当子问题划分得足够小时,用较简单的方法解决。
  3. 合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。

ASM

  • ASM
  • ASM获取方法参数名字
  • ASM增强代理类,并覆写方法
    • ASM工厂类`
    • Class的适配器类(ClassAdapter )`
    • [代理类
      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
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      141
      142
      	- [生成的class`](#%E7%94%9F%E6%88%90%E7%9A%84class)

      <!-- /TOC -->

      # ASM
      ASM是一个Java字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM可以直接产生二进制class文件,也可以在类被加载入Java虚拟机之前动态改变类行为。
      ASM实现可以是接口,也是可以类。
      Java class被存储在严格格式定义的`.class`文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及Java字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。
      ## JVM执行class的指令
      在Java中每一个方法在执行的时候JVM都会为其分配一个"帧",帧是用来存储方法中计算所需要的所有数据。其中第0个元素就是`this`,如果方法有参数传入会排在它的后面。
      ### ALOAD_0
      这个指令是`LOAD`系列指令中的一个,它的意思表示装载当前第0个元素到堆栈中。代码上相当于"this"。而这个数据元素的类型是一个引用类型。这些指令包含`ALOAD`,`ILOAD`,`LLOAD`,`FLOAD`,`DLOAD`。区分它们的作用就是针对不用数据类型而准备的`LOAD`指令,此外还有专门负责处理数组的指令`SALOAD`。
      ### Invokespecial
      这个指令是调用系列指令中的一个。其目的是调用对象类的方法。后面需要给上父类的方法完整签名。"#8"的意思是 `.class`文件常量表中第8个元素。值为`java/lang/Object."<init>":()V`。结合`ALOAD_0`。这两个指令可以翻译为`super()`。其含义是调用自己的父类构造方法。
      ### GETSTATIC
      这个指令是`GET`系列指令中的一个其作用是获取静态字段内容到堆栈中。这一系列指令包括了:`GETFIELD`、`GETSTATIC`。它们分别用于获取动态字段和静态字段。
      ### IDC
      这个指令的功能是从常量表中装载一个数据到堆栈中。
      ### Invokevirtual
      是一种调用指令,这个指令区别与`invokespecial`的是它是根据引用调用对象类的方法。这里有一篇文章专门讲解这两个指令:"http://wensiqun.iteye.com/blog/1125503"。
      ### RETURN
      这也是一系列指令中的一个,其目的是方法调用完毕返回,可用的其他指令有:`IRETURN`,`DRETURN`,`ARETURN`等,用于表示不同类型参数的返回。
      <!-- more -->
      # ASM获取方法参数名字
      ## ASM
      ```` java
      package asm;

      import java.io.IOException;
      import java.lang.reflect.Method;
      import java.lang.reflect.Modifier;

      import org.objectweb.asm.ClassReader;
      import org.objectweb.asm.ClassVisitor;
      import org.objectweb.asm.ClassWriter;
      import org.objectweb.asm.Label;
      import org.objectweb.asm.MethodVisitor;
      import org.objectweb.asm.Opcodes;
      import org.objectweb.asm.Type;

      import com.me.WorkServiceImpl;

      /**
      * <p>
      * 基于asm的工具类
      * </p>
      */
      public final class ASM {

      private ASM() {
      }

      /**
      *
      * <p>
      * 比较参数类型是否一致
      * </p>
      *
      * @param types
      * asm的类型({@link Type})
      * @param clazzes
      * java 类型({@link Class})
      * @return
      */
      private static boolean sameType(Type[] types, Class<?>[] clazzes) {
      // 个数不同
      if (types.length != clazzes.length) {
      return false;
      }
      for (int i = 0; i < types.length; i++) {
      if (!Type.getType(clazzes[i]).equals(types[i])) {
      return false;
      }
      }
      return true;
      }

      /**
      *
      * <p>
      * 获取方法的参数名
      * </p>
      *
      * @param m
      * @return
      */
      public static String[] getMethodParamNames(final Method method) {
      //参数名字
      final String[] paramNames = new String[method.getParameterTypes().length];
      //方法名字
      final String methodName = method.getDeclaringClass().getName();
      //class写入
      final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
      ClassReader classReader = null;
      try {
      //写入方法
      classReader = new ClassReader(methodName);
      } catch (IOException e) {
      e.printStackTrace();
      }
      classReader.accept(new ClassVisitor(Opcodes.ASM4, classWriter) {
      @Override
      public MethodVisitor visitMethod(final int access, final String name, final String desc, final String signature, final String[] exceptions) {
      //参数类型
      final Type[] args = Type.getArgumentTypes(desc);
      // 判断方法名字,方法参数
      if (!name.equals(method.getName()) || !sameType(args, method.getParameterTypes())) {
      return super.visitMethod(access, name, desc, signature, exceptions);
      }
      //方法访问
      MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, signature, exceptions);
      return new MethodVisitor(Opcodes.ASM4, methodVisitor) {
      @Override
      public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
      int i = index - 1;
      // 如果是静态方法,则第一就是参数
      // 如果不是静态方法,则第一个是"this",然后才是方法的参数
      if (Modifier.isStatic(method.getModifiers())) {
      i = index;
      }
      if (i >= 0 && i < paramNames.length) {
      paramNames[i] = name;
      }
      super.visitLocalVariable(name, desc, signature, start, end, index);
      }
      };
      }
      }, 0);
      return paramNames;
      }

      //ASM支持泛型
      public static void main(String[] args) throws SecurityException, NoSuchMethodException {
      //获取方法参数,方法名字,方法参数
      String[] s = getMethodParamNames(WorkServiceImpl.class.getMethod("work", String.class,Object.class));
      for (int i = 0; i < s.length; i++) {
      System.out.println(s[i]);
      }
      }

      }
      `

MethodParamNamesScanner

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package asm;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodNode;

import com.me.WorkServiceImpl;


/**
* 获取方法参数名字
*/
public class MethodParamNamesScanner {

/**
* 获取方法参数名列表
*
* @param clazz
* @param m
* @return
* @throws IOException
*/
public static List<String> getMethodParamNames(Class<?> clazz, Method method) throws IOException {
try (InputStream in = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class")) {
return getMethodParamNames(in, method);
}
}

public static List<String> getMethodParamNames(InputStream in, Method method) throws IOException {
try (InputStream ins = in) {
return getParamNames(ins, new EnclosingMetadata(method.getName(), Type.getMethodDescriptor(method),
method.getParameterTypes().length));
}
}

/**
* 获取构造器参数名列表
*
* @param clazz
* @param constructor
* @return
*/
public static List<String> getConstructorParamNames(Class<?> clazz, Constructor<?> constructor) {
try (InputStream in = clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class")) {
return getConstructorParamNames(in, constructor);
} catch (IOException e) {
e.printStackTrace();
}
return new ArrayList<String>();
}

public static List<String> getConstructorParamNames(InputStream ins, Constructor<?> constructor) {
try (InputStream in = ins) {
return getParamNames(
in,
new EnclosingMetadata(constructor.getName(), Type.getConstructorDescriptor(constructor), constructor
.getParameterTypes().length));
} catch (IOException e1) {
e1.printStackTrace();
}
return new ArrayList<String>();
}

/**
* 获取参数名列表辅助方法
*
* @param in
* @param m
* @return
* @throws IOException
*/
private static List<String> getParamNames(InputStream in, EnclosingMetadata enclosingMetadata) throws IOException {
ClassReader classReader = new ClassReader(in);
ClassNode classNode = new ClassNode();
classReader.accept(classNode, ClassReader.EXPAND_FRAMES);// 建议EXPAND_FRAMES
// ASM树接口形式访问
List<MethodNode> methods = classNode.methods;
List<String> list = new ArrayList<String>();
for (int i = 0; i < methods.size(); ++i) {
List<LocalVariable> varNames = new ArrayList<LocalVariable>();
MethodNode methodNode = methods.get(i);
// 验证方法签名
if (methodNode.desc.equals(enclosingMetadata.desc) && methodNode.name.equals(enclosingMetadata.name)) {
List<LocalVariableNode> local_variables = methodNode.localVariables;
for (int k = 0; k < local_variables.size(); k++) {
String varName = local_variables.get(k).name;
// index-记录了正确的方法本地变量索引。(方法本地变量顺序可能会被打乱。而index记录了原始的顺序)
int index = local_variables.get(k).index;
// 非静态方法,第一个参数是this
if (!"this".equals(varName)) {
varNames.add(new LocalVariable(index, varName));
}
}
LocalVariable[] tmpArr = varNames.toArray(new LocalVariable[varNames.size()]);
// 根据index来重排序,以确保正确的顺序
Arrays.sort(tmpArr);
for (int j = 0; j < enclosingMetadata.size; j++) {
list.add(tmpArr[j].name);
}
break;
}
}
return list;
}

/**
* 方法本地变量索引和参数名封装
*
* @author xby Administrator
*/
static class LocalVariable implements Comparable<LocalVariable> {
public int index;
public String name;

public LocalVariable(int index, String name) {
this.index = index;
this.name = name;
}

public int compareTo(LocalVariable o) {
return this.index - o.index;
}
}

/**
* 封装方法描述和参数个数
*
* @author xby Administrator
*/
static class EnclosingMetadata {
// method name
public String name;
// method description
public String desc;
// params size
public int size;

public EnclosingMetadata(String name, String desc, int size) {
this.name = name;
this.desc = desc;
this.size = size;
}
}

public static void main(String[] args) throws IOException {
for (Method m : WorkServiceImpl.class.getDeclaredMethods()) {
List<String> list = getMethodParamNames(WorkServiceImpl.class, m);
System.out.println(m.getName() + ":");
for (String str : list) {
System.out.println(str);
}
System.out.println("------------------------");
}
}
}

ASM增强代理类,并覆写方法

  1. 生成被代理类的子类,并重写所有方法(除java.lang.Object类定义的方法),增加beforeafter拦截。
  2. 重新定义被代理类的所有属性(不包括属性的赋值)。
  3. 把生成的class文件保存到硬盘中。
  4. 从内存中加载新生成的class。

    ASM工厂类

    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
    package asm;

    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;

    import org.objectweb.asm.ClassReader;
    import org.objectweb.asm.ClassVisitor;
    import org.objectweb.asm.ClassWriter;

    /**
    *
    * <p>
    * asm 代理工厂
    * </p>
    */
    public class AsmFactory {
    public static final String SUFIX = "$EnhancedByCc";
    public static BytecodeLoader classLoader = new BytecodeLoader();

    /**
    *
    * <p>
    * 根据字节码加载class
    * </p>
    */
    public static class BytecodeLoader extends ClassLoader {
    public Class<?> defineClass(String className, byte[] byteCodes) {
    return super.defineClass(className, byteCodes, 0, byteCodes.length);
    }
    }

    /**
    *
    * <p>
    * 返回代理类(增强类)
    * </p>
    *
    * @param <T>
    * @param clazz
    * @return
    * @throws Exception
    */
    @SuppressWarnings("unchecked")
    protected static <T> Class<T> getEnhancedClass(Class<T> clazz) {
    String enhancedClassName = clazz.getName() + SUFIX;
    try {
    return (Class<T>) classLoader.loadClass(enhancedClassName);
    } catch (ClassNotFoundException classNotFoundException) {//class没有找到,重新加载class
    ClassReader reader = null;
    try {
    reader = new ClassReader(clazz.getName());
    } catch (IOException ioexception) {
    throw new RuntimeException(ioexception);
    }
    ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
    //初始化classvisitor
    ClassVisitor visitor = new ClassAdapter(enhancedClassName, clazz, writer);
    reader.accept(visitor, 0);
    byte[] byteCodes = writer.toByteArray();
    //写入class文件
    writeClazz(enhancedClassName, byteCodes);
    Class<T> result = (Class<T>) classLoader.defineClass(enhancedClassName, byteCodes);
    return result;
    }
    }

    /**
    *
    * <p>
    * 把java字节码写入class文件
    * </p>
    *
    * @param <T>
    * @param name
    * @param data
    * @throws FileNotFoundException
    * @throws IOException
    */
    public static <T> void writeClazz(String name, byte[] data) {
    try {
    File file = new File("C:/TEMP/" + name + ".class");
    FileOutputStream fout = new FileOutputStream(file);
    fout.write(data);
    fout.close();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    public static void main(String[] args) throws InstantiationException, IllegalAccessException {
    Class<RoleService> rsCls = getEnhancedClass(RoleService.class);
    rsCls.newInstance().executeOuter(1);
    }

    }

Class的适配器类(ClassAdapter )

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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
package asm;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;

/**
*
* <p>根据class A生成一个class B extends A</p>
* <li>重写A及A父类的所有方法,eg. public void xx() {super.xx();}
* <li>copy A类定义的所有属性
*
1、生成被代理类的子类,并重写所有方法(除java.lang.Object类定义的方法),增加before和after拦截。
2、重新定义被代理类的所有属性(不包括属性的赋值)。
3、把生成的class文件保存到硬盘中。
4、从内存中加载新生成的class。
*
*/
public class ClassAdapter extends ClassVisitor implements Opcodes{
public static final String INIT = "<init>";
private ClassWriter classWriter;
//原始类名字
private String originalClassName;
//增强类名字
private String enhancedClassName;
//原始类
private Class<?> originalClass;


/**
*
* <p>Title: </p>
* <p>Description: </p>
* @param enhancedClassName 增强类
* @param targetClass 目标类
* @param writer class写入
*/
public ClassAdapter(String enhancedClassName, Class<?> targetClass, ClassWriter writer) {
super(Opcodes.ASM4, writer);
this.classWriter = writer;
this.originalClassName = targetClass.getName();
this.enhancedClassName = enhancedClassName;
this.originalClass = targetClass;
}

@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
cv.visit(version, Opcodes.ACC_PUBLIC, toAsmCls(enhancedClassName), signature, name, interfaces);
}

/**
* 访问属性
*/
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
// 拷贝所有属性 可使用java反射给属性赋值(生成class后newInstance在赋值)
return super.visitField(access, name, desc, signature, value);
}

@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
// 删除所有方法
return null;
}

/**
* 把类名中的.替换为/
*
* @param className
* @return
*/
private static String toAsmCls(String className) {
return className.replace('.', '/');
}

/**
*
* <p>
* 前置方法
* </p>
*
* @see TxHandler
* @param mWriter
*/
private static void doBefore(MethodVisitor mWriter, String methodInfo) {
mWriter.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mWriter.visitLdcInsn("before method : " + methodInfo);
mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
// 或者直接调用静态方法
// mWriter.visitLdcInsn(methodInfo);
// mWriter.visitMethodInsn(INVOKESTATIC,toAsmCls(TxHandler.class.getName()),"before","(Ljava/lang/String;)V");
}

/**
*
* <p>
* 后置方法
* </p>
*
* @see TxHandler
* @param mWriter
*/
private static void doAfter(MethodVisitor mWriter, String methodInfo) {
mWriter.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mWriter.visitLdcInsn("after method : " + methodInfo);
mWriter.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
}

/**
* 判断方法是否可以重新覆写
* <p>
* object类本身的方法不做重写
* </p>
* <p>
* "main" 方法不做重写
* </p>
*
* @param m
* @return
*/
public static boolean needOverride(Method method) {
// object类本身的方法不做重写
if (method.getDeclaringClass().getName().equals(Object.class.getName())) {
return false;
}
// "main" 方法不做重写
if (Modifier.isPublic(method.getModifiers()) && Modifier.isStatic(method.getModifiers()) && method.getReturnType().getName().equals("void")
&& method.getName().equals("main")) {
return false;
}
return true;
}

@Override
public void visitEnd() {
// 如果originalClass定义了私有成员变量,那么直接在visitMethod中复制originalClass的<init>会报错。
// ALOAD 0
// INVOKESPECIAL cc/RoleService.<init>()V
// RETURN
// // 调用originalClassName的<init>方法,否则class不能实例化
MethodVisitor mvInit = classWriter.visitMethod(ACC_PUBLIC, INIT, "()V", null, null);
mvInit.visitVarInsn(ALOAD, 0);
mvInit.visitMethodInsn(INVOKESPECIAL, toAsmCls(originalClassName), INIT, "()V");
mvInit.visitInsn(RETURN);
mvInit.visitMaxs(0, 0);
mvInit.visitEnd();

// 获取所有方法,并重写(main方法 和 Object的方法除外)
Method[] methods = originalClass.getMethods();
for (Method m : methods) {
//不覆写main方法
if (!needOverride(m)) {
continue;
}
//类型
Type mt = Type.getType(m);
StringBuilder methodInfo = new StringBuilder(originalClassName);
methodInfo.append(".").append(m.getName());
methodInfo.append("|");

Class<?>[] paramTypes = m.getParameterTypes();
//类型名字
for (Class<?> t : paramTypes) {
methodInfo.append(t.getName()).append(",");
}
if (paramTypes.length > 0) {
//删除最后一个“,”
methodInfo.deleteCharAt(methodInfo.length() - 1);
}

// 方法是被哪个类定义的
String declaringCls = toAsmCls(m.getDeclaringClass().getName());
// 方法 description
MethodVisitor mWriter = classWriter.visitMethod(ACC_PUBLIC, m.getName(), mt.toString(), null, null);
// insert code here (before)
doBefore(mWriter, methodInfo.toString());
int i = 0;
// 如果不是静态方法 load this对象
if (!Modifier.isStatic(m.getModifiers())) {
mWriter.visitVarInsn(ALOAD, i++);
}
StringBuilder sb = new StringBuilder(m.getName());
// load 出方法的所有参数
for (Class<?> tCls : m.getParameterTypes()) {
Type t = Type.getType(tCls);
sb.append(loadCode(t)).append(",");
mWriter.visitVarInsn(loadCode(t), i++);
if (t.getSort() == Type.LONG || t.getSort() == Type.DOUBLE) {
i++;
}
}
// super.xxx();
mWriter.visitMethodInsn(INVOKESPECIAL, declaringCls, m.getName(), mt.toString());
// 处理返回值类型
Type rt = Type.getReturnType(m);
// 没有返回值
if (rt.toString().equals("V")) {
doAfter(mWriter, methodInfo.toString());
mWriter.visitInsn(RETURN);
}
// 把return xxx() 转变成 : Object o = xxx(); return o;
else {
int storeCode = storeCode(rt);
int loadCode = loadCode(rt);
int returnCode = rtCode(rt);
mWriter.visitVarInsn(storeCode, i);
doAfter(mWriter, methodInfo.toString());
mWriter.visitVarInsn(loadCode, i);
mWriter.visitInsn(returnCode);
}
// 已设置了自动计算,但还是要调用一下,不然会报错
mWriter.visitMaxs(i, ++i);
mWriter.visitEnd();
}
cv.visitEnd();
}

/**
*
* <p>
* get StoreCode(Opcodes#xStore)
* </p>
*
*
* @param type
* @return
*/
public static int storeCode(Type type) {
//排序
int sort = type.getSort();
switch (sort) {
case Type.ARRAY:
sort = ASTORE;
break;
case Type.BOOLEAN:
sort = ISTORE;
break;
case Type.BYTE:
sort = ISTORE;
break;
case Type.CHAR:
sort = ISTORE;
break;
case Type.DOUBLE:
sort = DSTORE;
break;
case Type.FLOAT:
sort = FSTORE;
break;
case Type.INT:
sort = ISTORE;
break;
case Type.LONG:
sort = LSTORE;
break;
case Type.OBJECT:
sort = ASTORE;
break;
case Type.SHORT:
sort = ISTORE;
break;
default:
break;
}
return sort;
}

/**
*
* <p>
* get StoreCode(Opcodes#xLOAD)
* </p>
*
* @param type
* @return
*/
public static int loadCode(Type type) {
int sort = type.getSort();
switch (sort) {
case Type.ARRAY:
sort = ALOAD;
break;
case Type.BOOLEAN:
sort = ILOAD;
break;
case Type.BYTE:
sort = ILOAD;
break;
case Type.CHAR:
sort = ILOAD;
break;
case Type.DOUBLE:
sort = DLOAD;
break;
case Type.FLOAT:
sort = FLOAD;
break;
case Type.INT:
sort = ILOAD;
break;
case Type.LONG:
sort = LLOAD;
break;
case Type.OBJECT:
sort = ALOAD;
break;
case Type.SHORT:
sort = ILOAD;
break;
default:
break;
}
return sort;
}

/**
*
* <p>
* get StoreCode(Opcodes#xRETURN)
* </p>
*
* @param type
* @return
*/
public static int rtCode(Type type) {
int sort = type.getSort();
switch (sort) {
case Type.ARRAY:
sort = ARETURN;
break;
case Type.BOOLEAN:
sort = IRETURN;
break;
case Type.BYTE:
sort = IRETURN;
break;
case Type.CHAR:
sort = IRETURN;
break;
case Type.DOUBLE:
sort = DRETURN;
break;
case Type.FLOAT:
sort = FRETURN;
break;
case Type.INT:
sort = IRETURN;
break;
case Type.LONG:
sort = LRETURN;
break;
case Type.OBJECT:
sort = ARETURN;
break;
case Type.SHORT:
sort = IRETURN;
break;
default:
break;
}
return sort;
}
}

代理类

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
package asm;


/**
* <p></p>
*/
public class RoleService extends Service{
private String field1 = "";

public String executeOuter(Integer name) {
System.out.println("executeOuter call super.query()");
return query();
}

@Override
public String query() {
System.out.println("execute (RoleService): query");
return "query result (RoleService)";
}

public String getField1() {
return field1;
}

public void setField1(String field1) {
this.field1 = field1;
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Service.java 11:59:38 AM Apr 27, 2012
*
* Copyright(c) 2000-2012 HC360.COM, All Rights Reserved.
*/
package asm;


/**
* <p></p>
*
*/
public class Service extends Dao{

@Override
public void insert(Object o) {
super.insert(o);
}

}
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
/**
* Dao.java 11:58:24 AM Apr 27, 2012
*
* Copyright(c) 2000-2012 HC360.COM, All Rights Reserved.
*/
package asm;
/**
* <p></p>
*
*/
public class Dao {
public void insert(Object o) {
System.out.println("insert : " + o);
}

public String query() {
System.out.println("execute (Dao): query");
return "query result (Dao)";
}
public String query2() {
System.out.println("execute (Dao): query2");
return "query2 result (Dao)";
}

public int test() {
System.out.println("execute (Dao) : test");
return 0;
}

protected void testProtected() {
System.out.println("execute (Dao) : testProtected");
testPrivate();
}

private void testPrivate() {
System.out.println("execute (Dao) : testPrivate");
}

public Dao[] testArray(String[] s,Object o) {
System.out.println("execute (Dao) : testArray");
return null;
}
}

生成的class

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
package asm;

import java.io.PrintStream;

public class RoleService$EnhancedByCc extends RoleService
{
private String field1;

public String executeOuter(Integer paramInteger)
{
System.out.println("before method : asm.RoleService.executeOuter|java.lang.Integer");
String str = super.executeOuter(paramInteger);
System.out.println("after method : asm.RoleService.executeOuter|java.lang.Integer");
return str;
}

public String query()
{
System.out.println("before method : asm.RoleService.query|");
String str = super.query();
System.out.println("after method : asm.RoleService.query|");
return str;
}

public void setField1(String paramString)
{
System.out.println("before method : asm.RoleService.setField1|java.lang.String");
super.setField1(paramString);
System.out.println("after method : asm.RoleService.setField1|java.lang.String");
}

public String getField1()
{
System.out.println("before method : asm.RoleService.getField1|");
String str = super.getField1();
System.out.println("after method : asm.RoleService.getField1|");
return str;
}

public void insert(Object paramObject)
{
System.out.println("before method : asm.RoleService.insert|java.lang.Object");
super.insert(paramObject);
System.out.println("after method : asm.RoleService.insert|java.lang.Object");
}

public String query2()
{
System.out.println("before method : asm.RoleService.query2|");
String str = super.query2();
System.out.println("after method : asm.RoleService.query2|");
return str;
}

public int test()
{
System.out.println("before method : asm.RoleService.test|");
int i = super.test();
System.out.println("after method : asm.RoleService.test|");
return i;
}

public Dao[] testArray(String[] paramArrayOfString, Object paramObject)
{
System.out.println("before method : asm.RoleService.testArray|[Ljava.lang.String;,java.lang.Object");
Dao[] arrayOfDao = super.testArray(paramArrayOfString, paramObject);
System.out.println("after method : asm.RoleService.testArray|[Ljava.lang.String;,java.lang.Object");
return arrayOfDao;
}
}

(转载)01背包问题(动态规划算法)

概述

有n个物品,第i个物品价值为v,重量为w,其中v和w均为非负数,背包的容量是W。现需要考虑如何选择装入背包的物品,使装入背包的物品总价值最大。

物品编号 1 2 3 4 5
价值v 4 5 10 11 13
重量w 3 4 7 8 9


动态规划算法

引言

在现实生活中,有一类活动的过程,由于它的特殊性,可将过程分成若干个互相联系的阶段,在它的每一阶段都需要作出决策,从而使整个过程达到最好的活动效果。当然,各个阶段决策的选取不是任意确定的,它依赖于当前面临的状态,又影响以后的发展,当各个阶段决策确定后,就组成一个决策序列,因而也就确定了整个过程的一条活动路线。
这种把一个问题看作是一个前后关联具有链状结构的多阶段过程就称为多阶段决策过程,这种问题就称为多阶段决策问题。
多阶段决策问题中,各个阶段采取的决策,一般来说是与时间有关的,决策依赖于当前状态,又随即引起状态的转移,一个决策序列就是在变化的状态中产生出来的,故有“动态”的含义,称这种解决多阶段决策最优化问题的方法为动态规划方法。

概念

动态规划主要用于求解以时间划分阶段的动态过程的优化问题,但是一些与时间无关的静态规划(如线性规划、非线性规划),只要人为地引进时间因素,把它视为多阶段决策过程,也可以用动态规划方法方便地求解。
动态规划程序设计是对解最优化问题的一种途径、一种方法,而不是一种特殊算法。不像搜索或数值计算那样,具有一个标准的数学表达式和明确清晰的解题方法。动态规划程序设计往往是针对一种最优化问题,由于各种问题的性质不同,确定最优解的条件也互不相同,因而动态规划的设计方法对不同的问题,有各具特色的解题方法,而不存在一种万能的动态规划算法,可以解决各类最优化问题。
因此在学习时,除了要对基本概念和方法正确理解外,必须具体问题具体分析处理,以丰富的想象力去建立模型,用创造性的技巧去求解。我们也可以通过对若干有代表性的问题的动态规划算法进行分析、讨论,逐渐学会并掌握这一设计方法。

多阶段决策问题

如果一类活动过程可以分为若干个互相联系的阶段,在每一个阶段都需作出决策(采取措施),一个阶段的决策确定以后,常常影响到下一个阶段的决策,从而就完全确定了一个过程的活动路线,则称它为多阶段决策问题。
各个阶段的决策构成一个决策序列,称为一个策略。每一个阶段都有若干个决策可供选择,因而就有许多策略供我们选取,对应于一个策略可以确定活动的效果,这个效果可以用数量来确定。策略不同,效果也不同,多阶段决策问题,就是要在可以选择的那些策略中间,选取一个最优策略,使在预定的标准下达到最好的效果。

(转载)Spring Bean生命周期,实例化顺序

简介

Spring中Bean容器的生命周期。

首先明确一点,并非Spring容器中所有的Bean都有生命周期行为,只有接受容器管理生命周期的Bean才具有生命周期行为;而单例(Singleton)Bean接受容器管理,非单例(non-singleton)Bean在实例化后,完全交给了客户端代码管理,容器不再跟踪其生命周期,每次客户请求,容器都会创建一个新的实例,所以Spring容易无法知晓Bean何时销毁。
Bean容器的生命周期。其实上图有个节点没有画出,就是在实例化所有Bean之前会执行BeanFactoryPostProcessors

Spring四种注入方式(IOC)

Set方式

1
2
3
4
5
6
7
8
9
10
11
12
13
public class SpringAction1 {
// 注入对象springDao
private SpringDao springDao;

// 一定要写被注入对象的set方法
public void setSpringDao(SpringDao springDao) {
this.springDao = springDao;
}

public void ok() {
springDao.ok();
}
}
1
2
3
4
5
6
7
package test.spring1;

public class SpringDao {
public void ok() {
System.out.println("Spring dao");
}
}
1
2
3
4
5
<bean name="springAction" class="test.spring1.SpringAction1">  
<!-- 依赖注入,配置当前类中相应的属性 -->
<property name="springDao" ref="springDao"></property>
</bean>
<bean name="springDao" class="test.spring1.SpringDao"></bean>
1
2
SpringAction1 springAction1 = (SpringAction1) ContextUtil.getBean("springAction", SpringAction1.class);
springAction1.ok();

变位词(编程珠玑)

问题

给定一本英语单词词典,请找出所有的变位词集。所谓的变位词是指,组成各个单词的字母完全相同,只是字母排列的顺序不同。
例如,“pots”,”stop”和“tops”互为变位词,因为每个单词都可以通过改变其他单词中字母的顺序来得到。

解决思路

编程珠玑的变位词程序要按照三个步骤来执行,其中前一个步骤程序的输出作为下一个步骤程序的输入:

  • 程序标识单词。
  • 程序排序标识后的文件。
  • 程序将这些单词压缩为每个变位词类一行的形式。

单词的字典的处理过程:

由以上可看出需要三个程序的处理。

sign程序

假设输入单词的长度不超过100,对每个输入的单词依照字母进行排序,将结果输入这个单词所对应的“签名”。

sort程序

程序排序后的输出的“签名”,对其输出的结果排序,如上图。

squash程序

将同一个变位词类中的各个单词放到同一行中。

清理Spring内省对象

问题

在服务器运行过程中,Spring不停的运行计划任务和OpenSessionInViewFilter,使得Tomcat反复加载对象而产生框架并用时可能产生的内存泄漏,则使用IntrospectorCleanupListener作为相应的解决办法。

解决方式

Spring中的提供一个名为org.springframework.web.util.IntrospectorCleanupListener的监听器。它主要负责处理由JavaBeans Introspector(内省对象)的使用而引起的内存泄露。

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×