概述
Javassist是一款字节码编辑工具,可以直接编辑和生成Java生成的字节码,以达到对.class文件进行动态修改的效果。熟练使用这套工具,可以让Java编程更接近与动态语言编程。
下面一个方法的目的是获取一个类加载器(ClassLoader),以加载指定的.jar或.class文件,在之后的代码中会使用到。
- private static ClassLoader getLocaleClassLoader() throws Exception {
- List<URL> classPathURLs = new ArrayList<>();
-
- classPathURLs.add(classesPath.toURI().toURL());
-
-
- File[] jarFiles = libPath.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.endsWith(".jar");
- }
- });
- Assert.assertFalse(ObjectHelper.isArrayNullOrEmpty(jarFiles));
-
-
- for (File jarFile : jarFiles) {
- classPathURLs.add(jarFile.toURI().toURL());
- }
-
-
- return new URLClassLoader(classPathURLs.toArray(new URL[classPathURLs.size()]));
- }
获取类型信息
- @Test
- public void test() throws NotFoundException {
-
- ClassPool classPool = ClassPool.getDefault();
-
-
- CtClass ctClass = classPool.get("java.lang.String");
-
- System.out.println(ctClass.getName());
- System.out.println("\tpackage " + ctClass.getPackageName());
- System.out.print("\t" + Modifier.toString(ctClass.getModifiers()) + " class " + ctClass.getSimpleName());
- System.out.print(" extends " + ctClass.getSuperclass().getName());
-
- if (ctClass.getInterfaces() != null) {
- System.out.print(" implements ");
- boolean first = true;
- for (CtClass c : ctClass.getInterfaces()) {
- if (first) {
- first = false;
- } else {
- System.out.print(", ");
- }
- System.out.print(c.getName());
- }
- }
- System.out.println();
- }
修改类方法
- @Test
- public void test() throws Exception {
-
- ClassLoader classLoader = getLocaleClassLoader();
-
- Class<?> clazz = classLoader.loadClass("edu.alvin.reflect.TestLib");
-
-
- ClassPool classPool = ClassPool.getDefault();
-
- classPool.appendClassPath(new ClassClassPath(clazz));
-
- CtClass ctClass = classPool.get(clazz.getName());
-
-
- CtClass[] paramTypes = {classPool.get(String.class.getName())};
-
- CtMethod method = ctClass.getDeclaredMethod("show", paramTypes);
-
- CtMethod newMethod = CtNewMethod.copy(method, ctClass, null);
-
- String oldName = method.getName() + "$Impl";
- method.setName(oldName);
-
-
- newMethod.setBody("{System.out.println(\"执行前\");" + oldName + "($$);System.out.println(\"执行后\");}");
-
- ctClass.addMethod(newMethod);
-
-
- clazz = ctClass.toClass();
-
- clazz.getMethod("show", String.class).invoke(clazz.newInstance(), "hello");
- ctClass.defrost();
- }
动态创建类
- @Test
- public void test() throws Exception {
- ClassPool classPool = ClassPool.getDefault();
-
-
- CtClass ctClass = classPool.makeClass("edu.alvin.reflect.DynamiClass");
-
-
-
-
- CtField field = new CtField(classPool.get(String.class.getName()), "value", ctClass);
- field.setModifiers(Modifier.PRIVATE);
-
- ctClass.addMethod(CtNewMethod.setter("setValue", field));
- ctClass.addMethod(CtNewMethod.getter("getValue", field));
- ctClass.addField(field);
-
-
-
- CtConstructor constructor = new CtConstructor(null, ctClass);
- constructor.setModifiers(Modifier.PUBLIC);
- constructor.setBody("{}");
- ctClass.addConstructor(constructor);
-
- constructor = new CtConstructor(new CtClass[] {classPool.get(String.class.getName())}, ctClass);
- constructor.setModifiers(Modifier.PUBLIC);
- constructor.setBody("{this.value=$1;}");
- ctClass.addConstructor(constructor);
-
-
- CtMethod method = new CtMethod(CtClass.voidType, "run", null, ctClass);
- method.setModifiers(Modifier.PUBLIC);
- method.setBody("{System.out.println(\"执行结果\" + this.value);}");
- ctClass.addMethod(method);
-
-
- Class<?> clazz = ctClass.toClass();
- Object obj = clazz.newInstance();
- clazz.getMethod("setValue", String.class).invoke(obj, "hello");
- clazz.getMethod("run").invoke(obj);
-
- obj = clazz.getConstructor(String.class).newInstance("OK");
- clazz.getMethod("run").invoke(obj);
- }
创建代理类
- @Test
- public void test() throws Exception {
-
- ProxyFactory factory = new ProxyFactory();
-
-
- factory.setSuperclass(TestProxy.class);
-
-
- factory.setFilter(new MethodFilter() {
- @Override
- public boolean isHandled(Method m) {
- return m.getName().startsWith("get");
- }
- });
-
- Class<?> clazz = factory.createClass();
- TestProxy proxy = (TestProxy) clazz.newInstance();
- ((ProxyObject)proxy).setHandler(new MethodHandler() {
- @Override
- public Object invoke(Object self, Method thisMethod, Method proceed, Object[] args) throws Throwable {
-
-
- System.out.println(thisMethod.getName() + "被调用");
- try {
- Object ret = proceed.invoke(self, args);
- System.out.println("返回值: " + ret);
- return ret;
- } finally {
- System.out.println(thisMethod.getName() + "调用完毕");
- }
- }
- });
-
- proxy.setName("Alvin");
- proxy.setValue("1000");
- proxy.getName();
- proxy.getValue();
- }
其中,TestProxy类内容如下:
- public class TestProxy {
- private String name;
- private String value;
-
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getValue() {
- return value;
- }
- public void setValue(String value) {
- this.value = value;
- }
- }
获取方法名称
- @Test
- public void test() throws Exception {
-
- ClassLoader classLoader = getLocaleClassLoader();
-
- Class<?> clazz = classLoader.loadClass("edu.alvin.reflect.TestLib");
-
-
- ClassPool classPool = ClassPool.getDefault();
- classPool.appendClassPath(new ClassClassPath(clazz));
- CtClass ctClass = classPool.get(clazz.getName());
-
-
- CtMethod method = ctClass.getDeclaredMethod("show", ObjectHelper.argumentsToArray(CtClass.class, classPool.get("java.lang.String")));
-
- int staticIndex = Modifier.isStatic(method.getModifiers()) ? 0 : 1;
-
-
- MethodInfo methodInfo = method.getMethodInfo();
- CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
- LocalVariableAttribute localVariableAttribute = (LocalVariableAttribute)codeAttribute.getAttribute(LocalVariableAttribute.tag);
-
- for (int i = 0; i < method.getParameterTypes().length; i++) {
- System.out.println("第" + (i + 1) + "个参数名称为: " + localVariableAttribute.variableName(staticIndex + i));
- }
- }
关于“获取方法名称”,其主要作用是:当Java虚拟机加载.class文件后,会将类方法“去名称化”,即丢弃掉方法形参的参数名,而是用形参的序列号来传递参数。如果要通过Java反射获取参数的参数名,则必须在编辑是指定“保留参数名称”。Javassist则不存在这个问题,对于任意方法,都能正确的获取其参数的参数名。
Spring MVC就是通过方法参数将请求参数进行注入的,这一点比struts2 MVC要方便很多,Spring也是借助了Javassist来实现这一点的。
Javassist字节码增强示例
原文:http://www.cnblogs.com/cunkouzh/p/4924481.html