所以,我们大概就是,要做下面的这样一个切面:
@Override protected void onMethodEnter() { //在方法入口处植入 String className = getClass().getName(); String s = className + "." + methodName; TimeHolder.start(s); } @Override protected void onMethodExit(int i) { //在方法出口植入 String className = getClass().getName(); String s = className + "." + methodName; long cost = TimeHolder.cost(s); System.out.println(s + ": " + cost); }但是,习惯了动态代理的我们,看上面的代码可能会有点误解。上面的代码,不是在执行目标方法前,调用切面;而是:直接把切面代码嵌入了目标方法。
想必大家都明确了要达成的目标了,下面说,怎么做。
java agent/instrumentation机制这部分,大家可以结合开头那个链接一起学习。
首先,我请大家看看java命令行的选项。直接在cmd里敲java,出现如下:
看了和没看一样,那我们再看一张图,在大家破解某些java编写的软件时,可能会涉及到jar包破解,比如:
大家可以使用jad这类反编译软件,打开jar包看下,看看里面是啥:
可以发现,里面有一个MANIFEST.MF文件,里面指定了Premain-Class这个key-value,从这个名字,大家可能知道了,我们平时运行java程序,都是运行main方法,这里来个premain,那这意思,就是在main方法前面插个队呗?
你说的没有错,确实是插队了,拿上面的破解jar包举例,里面的Premain-Class方法,对应的Agent类,反编译后的代码如下:
核心代码就是图里那一行:
java.lang.instrument.Instrumentation public interface Instrumentation { /** * Registers the supplied transformer. All future class definitions * will be seen by the transformer, except definitions of classes upon which any * registered transformer is dependent. * The transformer is called when classes are loaded, when they are * {@linkplain #redefineClasses redefined}. and if <code>canRetransform</code> is true, * when they are {@linkplain #retransformClasses retransformed}. * See {@link java.lang.instrument.ClassFileTransformer#transform * ClassFileTransformer.transform} for the order * of transform calls. * If a transformer throws * an exception during execution, the JVM will still call the other registered * transformers in order. The same transformer may be added more than once, * but it is strongly discouraged -- avoid this by creating a new instance of * transformer class. * <P> * This method is intended for use in instrumentation, as described in the * {@linkplain Instrumentation class specification}. * * @param transformer the transformer to register * @param canRetransform can this transformer's transformations be retransformed * @throws java.lang.NullPointerException if passed a <code>null</code> transformer * @throws java.lang.UnsupportedOperationException if <code>canRetransform</code> * is true and the current configuration of the JVM does not allow * retransformation ({@link #isRetransformClassesSupported} is false) * @since 1.6 */ void addTransformer(ClassFileTransformer transformer, boolean canRetransform); ... }