package demo;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
public class MethodAgentMain {
/** 被转换的类 */
public static final String TRANSFORM_CLASS = "org.example.agent.AgentTest";
/** 静态加载。Java agent指定的premain方法,会在main方法之前被调用 */
public static void premain(String args, Instrumentation instrumentation) {
System.out.println("premain start!");
addTransformer(instrumentation);
System.out.println("premain end!");
}
/** 动态加载。Java agent指定的premain方法,会在main方法之前被调用 */
public static void agentmain(String args, Instrumentation instrumentation) {
System.out.println("agentmain start!");
addTransformer(instrumentation);
Class>[] classes = instrumentation.getAllLoadedClasses();
if (classes != null){
for (Class> c: classes) {
if (c.isInterface() ||c.isAnnotation() ||c.isArray() ||c.isEnum()){
continue;
}
if (c.getName().equals(TRANSFORM_CLASS)) {
try {
System.out.println("retransformClasses start, class: " + c.getName());
/*
* retransformClasses()对JVM已经加载的类重新触发类加载。使用的就是上面注册的Transformer。
* retransformClasses()可以修改方法体,但是不能变更方法签名、增加和删除方法/类的成员属性
*/
instrumentation.retransformClasses(c);
System.out.println("retransformClasses end, class: " + c.getName());
} catch (UnmodifiableClassException e) {
System.out.println("retransformClasses error, class: " + c.getName() + ", ex:" + e);
e.printStackTrace();
}
}
}
}
System.out.println("agentmain end!");
}
private static void addTransformer (Instrumentation instrumentation) {
/* Instrumentation提供的addTransformer方法,在类加载时会回调ClassFileTransformer接口 */
instrumentation.addTransformer(new ClassFileTransformer() {
public byte[] transform(ClassLoader l,String className, Class> c,ProtectionDomain pd, byte[] b){
try {
className = className.replace("/", ".");
if (className.equals(TRANSFORM_CLASS)) {
final ClassPool classPool = ClassPool.getDefault();
final CtClass clazz = classPool.get(TRANSFORM_CLASS);
for (CtMethod method : clazz.getMethods()) {
/*
* Modifier.isNative(methods[i].getModifiers())过滤本地方法,否则会报
* javassist.CannotCompileException: no method body at javassist.CtBehavior.addLocalVariable()
* 报错原因如下
* 来自Stack Overflow网友解答
* Native methods cannot be instrumented because they have no bytecodes.
* However if native method prefix is supported ( Transformer.isNativeMethodPrefixSupported() )
* then you can use Transformer.setNativeMethodPrefix() to wrap a native method call inside a non-native call
* which can then be instrumented
*/
if (Modifier.isNative(method.getModifiers())) {
continue;
}
method.insertBefore("System.out.println(\"" + clazz.getSimpleName() + "."
+ method.getName() + " start.\");");
method.insertAfter("System.out.println(\"" + clazz.getSimpleName() + "."
+ method.getName() + " end.\");", false);
}
return clazz.toBytecode();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}, true);
}
}
编译打包:
执行 mvn clean package 编译打包,最终打包生成了 agent jar 包,结果示例:
image.png
1.1.1 编写验证 agent 功能的测试类
创建 agent-example工程,目录结构如下:
image.png
编写测试 agent 功能的类 AgentTest.java
package org.example.agent;
public class AgentTest {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 1000; i++) {
System.out.println("process result: " + process());
Thread.sleep(5000);
}
}
public static String process() {
System.out.println("process!");
return "success";
}
}
1.2 使用 java agent 静态加载方式实现
在 IDEA 的 Run/Debug Configurations 中,点击 Modify options,勾选上 add VM options,在 VM options 栏增加 -javaagent:/工程的父目录/demo-javaagent/demo-javaagent/target/demo-javaagent-1.0-jar-with-dependencies.jar
* The redefinition may change method bodies, the constant pool and attributes.
* The redefinition must not add, remove or rename fields or methods, change the
* signatures of methods, or change inheritance. These restrictions maybe be
* lifted in future versions. The class file bytes are not checked, verified and installed
* until after the transformations have been applied, if the resultant bytes are in
* error this method will throw an exception.
agent 中的 class 由 system calss loader(默认AppClassLoader) 加载,premain() 方法会调用 Instrumentation API,然后 Instrumentation API 调用 JVMTI(JVMTI的内容将在后面补充),在需要加载的类需要被加载时,会回调 JVMTI,然后回调 Instrumentation API,触发ClassFileTransformer.transform(),最终修改 class 的字节码。
protected Class> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// 判断是否已经加载过了,如果没有,则进行load
// First, check if the class has already been loaded
Class> c = findLoadedClass(name);
if (c == null) {
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
// findClass()内部最终会调用 Java agent 中 ClassFileTransformer.transform()
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
最近受我的朋友委托用js+HTML做一个像手册一样的程序,里面要有可展开的大纲,模糊查找等功能。我这个人说实在的懒,本来是不愿意的,但想起了父亲以前教我要给朋友搞好关系,再加上这也可以巩固自己的js技术,于是就开始开发这个程序,没想到却出了点小问题,我做的查找只能绝对查找。具体的js代码如下:
function search(){
var arr=new Array("my
实例:
CREATE OR REPLACE PROCEDURE test_Exception
(
ParameterA IN varchar2,
ParameterB IN varchar2,
ErrorCode OUT varchar2 --返回值,错误编码
)
AS
/*以下是一些变量的定义*/
V1 NUMBER;
V2 nvarc
Spark Streaming简介
NetworkWordCount代码
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
代码示例:
# include <stdio.h>
//冒泡排序
void sort(int * a, int len)
{
int i, j, t;
for (i=0; i<len-1; i++)
{
for (j=0; j<len-1-i; j++)
{
if (a[j] > a[j+1]) // >表示升序
nginx日志分割 for linux 默认情况下,nginx是不分割访问日志的,久而久之,网站的日志文件将会越来越大,占用空间不说,如果有问题要查看网站的日志的话,庞大的文件也将很难打开,于是便有了下面的脚本 使用方法,先将以下脚本保存为 cutlog.sh,放在/root 目录下,然后给予此脚本执行的权限
复制代码代码如下:
chmo
http://bukhantsov.org/2011/08/how-to-determine-businessobjects-service-pack-and-fix-pack/
The table below is helpful. Reference
BOE XI 3.x
12.0.0.
y BOE XI 3.0 12.0.
x.
y BO
大家都知道吧,这很坑,尤其是用惯了mysql里的自增字段设置,结果oracle里面没有的。oh,no 我用的是12c版本的,它有一个新特性,可以这样设置自增序列,在创建表是,把id设置为自增序列
create table t
(
id number generated by default as identity (start with 1 increment b