JAVA反射与动态代理

一、了解类加载机制和类加载器

字节码

此处应有操作演示:javap反解析class文件

类加载机制

概述:Class文件由类装载器装载后,在JVM中将形成一份描述Class结构的元信息对象,通过该元信息对象可以获知Class的结构信息:如构造函数,属性和方法等,Java允许用户借由这个Class相关的元信息对象间接调用Class对象的功能。

虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。

类加载过程

(1) 加载阶段:查找和导入Class文件;

(i)通过一个类的全限定名来获取定义此类的二进制字节流

(ii)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构

(iii)在内存中生成代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口

(2) 链接:把类的二进制数据合并到JRE中;

(a)校验:检查载入Class文件数据的正确性;

(b)准备:给类的静态变量分配存储空间;

//思考:该阶段(准备)jvm对以下类变量是否分配内存及初始化值情况如何?
public String value1 = "1";
public static String value2 = "2";
public static final String value3 = "3";

 

(c)解析:将常量池中符号引用转成直接引用;

理解:符号引用、直接引用的含义。

(3) 初始化:对类的静态变量,静态代码块执行初始化操作

1.<clinit>()方法是由于编译器自动收集类中所有类变量赋值,静态语句块合并产生的,顺序是语句在源文件中的顺序。

2.<clinit>()方法与类的构造器不同,他不需要显示的调用父类的构造方法,因为jvm会保证在子类的<clinit>()方法执行之前,父类已经执行了。所以jvm执行的<clinit>()一定是object类。

3.如果一个类或者接口中没有静态语句或者静态块,则可以没有<clinit>()方法。

4.jvm会保证类的<clinit>()方法加锁。

类加载的时机(只加载一次)

1.创建类的实例的时候

2.访问类的静态变量的时候

3.调用类的静态方法的时候

4.使用反射方式来强制创建某个类或接口对应的java.lang.Class对象

5.初始化某个类的子类的时候

6.直接使用java.exe命令来运行某个主类

类加载器

查看sun.misc.Launcher/java.lang.ClassLoader源码、熟悉类加载器的双亲委托机制等。

1.Bootstrap ClassLoader 根类加载器,也被称为引导类加载器,负责Java核心类的加载,比如System类,在JDK中JRE的lib目录下rt.jar文件中的类

2.Extension ClassLoader 扩展类加载器, 负责JRE的扩展目录中jar包的加载,在JDK中JRE的lib目录下ext目录

3.System ClassLoader 系统类加载器, 负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径,主要是我们开发者自己写的类

说明:ContextClassLoader不是类加载器

package com.hy.reflect;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;

public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Class clazz1 = Class.forName("com.hy.reflect.Student");
        System.out.println(clazz1.getClassLoader());

        MyClassLoader classLoader = new MyClassLoader();
        Class clazz2 = classLoader.findClass("com.hy.reflect.Student");//如果此情况下,此处改成loadClass方法,显示结果怎么样?
        System.out.println(clazz2.getClassLoader());
        System.out.println("clazz1==clazz2:" + (clazz1 == clazz2));
    }

}

class MyClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> cls = findLoadedClass(name);
        if (cls != null) {
            return cls;
        }
        try {
            FileInputStream input = new FileInputStream(new File("/Users/zhouy/Documents/workspaces/test/hy-reflect-test/target/classes/com/hy/reflect/Student.class"));
            ByteArrayOutputStream output = new ByteArrayOutputStream();

            int len = 0;
            while ((len = input.read()) != -1) {
                output.write(len);
            }
            byte[] bytes = output.toByteArray();

            input.close();
            output.close();
            return defineClass(name, bytes, 0, bytes.length);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return super.loadClass(name);
    }
}

 

tomcat也是定义了自己的classloader,那么为啥不用jvm提供的classloader?

1.webapp隔离:由于各个webapp中的class和lib文件需要相互隔离,不能出现一个应用中加载的类库会影响到另一个应用的情况

2.安全性:与jvm相同,tomcat也期望使用单独的classloader去装载tomcat自身的类库,以免其他恶意或者无意的破坏

3.热部署:tomcat修改文件可以不用重启自动装载类库

 

扩展思维:借助自定义类加载器实现加密的class文件内容进行解密运行。

二、反射

概述:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

1、查看java.lang.Class、java.lang.reflect.*相关源码

2、获取Class对象的三种方式:

 1.调用某个对象的getClass()方法

 2.直接获取某一个对象的class

 3.使用Class类的forName静态方法(最常用)

3、通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法、main方法,并访问成员

4、利用反射获取泛型(提高可读性)和注解

泛型按照使用情况可以分为:泛型类、泛型方法、泛型接口

5、样例代码:

 
//Cache
package com.hy.reflect;

import java.io.Serializable;

public class Cache<T extends Serializable> {
    private T item;

    public Cache(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}

//Person
package com.hy.reflect;

import lombok.Getter;

import java.io.Serializable;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Getter
@Test("Batman")
public class Person implements Serializable {
    @Test("IronMan")
    protected String name;
    public int age;

    @Override
    @Test("anyone")
    public String toString() {
        return "Person[name:" + name + ",age:" + age + "]";
    }
}

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface Test {
    String value() default "";
}

//Student
package com.hy.reflect;

import lombok.Getter;

@Getter
public class Student extends Person {
    char sex;
    private float score;

    Student(String name) {
        this.name = name;
    }

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    protected Student(int age) {
        this.age = age;
    }

    private Student(float score) {
        this.score = score;
    }

    public void study1() {
        System.out.println("invoke public void study1()");
    }

    protected void study2() {
        System.out.println("invoke protected void study2()");
    }

    private void study3() {
        System.out.println("invoke private void study3()");
    }

    public static void main(String[] args){
        System.out.println("invoke public static void main(String[] args)");
    }
}

//RelectTest
package com.hy.reflect;

import org.junit.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.List;

public class RelectTest {

    @Test
    public void classLoaderTest() {
        ClassLoader classLoader = Student.class.getClassLoader();
        while (classLoader != null) {
            System.out.println(classLoader.getClass().getName());
            classLoader = classLoader.getParent();
        }
    }

    @Test
    public void getClassTest() {
        //第一种方式获取class对象
        Class class2 = new Student().getClass();
        //第二种方式获取class对象
        Class class1 = Student.class;
        System.out.println("class1==class2:" + (class1 == class2));
        //第三种方式获取class对象
        try {
            Class class3 = Class.forName("com.hy.reflect.Student");
            System.out.println("class1==class3:" + (class1 == class3));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void superClassTest() throws ClassNotFoundException {
        Class clazz = Class.forName("com.hy.reflect.Student");
        System.out.println("super class :" + clazz.getSuperclass());
        for (Class c : clazz.getInterfaces())
            System.out.println("interfaces :" + c);
    }

    @Test
    public void constructorTest() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clazz = Class.forName("com.hy.reflect.Student");

        System.out.println("-------------分割线1----------------------");
        Constructor[] constructors1 = clazz.getConstructors();
        for (Constructor constructor : constructors1) {
            System.out.println(constructor);
        }

        System.out.println("-------------分割线2----------------------");
        Constructor[] constructors2 = clazz.getDeclaredConstructors();
        for (Constructor constructor : constructors2) {
            System.out.println(constructor);
        }

        System.out.println("-------------分割线3----------------------");
        Constructor constructor3 = clazz.getConstructor(null);
        System.out.println(constructor3);
        System.out.println(constructor3.newInstance());

        System.out.println("-------------分割线4----------------------");
        Constructor constructor4 = clazz.getDeclaredConstructor(int.class);
        System.out.println(constructor4);
        System.out.println(constructor4.newInstance(99));

        System.out.println("-------------分割线5----------------------");
        Constructor constructor5 = clazz.getDeclaredConstructor(float.class);
        System.out.println(constructor5);
        constructor5.setAccessible(true);
        System.out.println(constructor5.newInstance(99.99f));
    }

    @Test
    public void fieldTest() throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clazz = Class.forName("com.hy.reflect.Student");

        System.out.println("-------------分割线1----------------------");
        Field[] fields1 = clazz.getFields();
        for (Field field : fields1) {
            System.out.println("field:" + field + ",type:" + field.getType() + ",genericType:" + field.getGenericType());
        }

        System.out.println("-------------分割线2----------------------");
        Field[] fields2 = clazz.getDeclaredFields();
        for (Field field : fields2) {
            System.out.println("field:" + field + ",type:" + field.getType() + ",genericType:" + field.getGenericType());
        }

        System.out.println("-------------分割线3----------------------");
        Field field3 = clazz.getField("age");//age公有
        System.out.println(field3);
        Object obj3 = clazz.getConstructor().newInstance();
        field3.set(obj3, 100);
        Student student3 = (Student) obj3;
        System.out.println(student3.getAge());

        System.out.println("-------------分割线4----------------------");
        Field field4 = clazz.getDeclaredField("score");//score私有
        System.out.println(field4);
        field4.setAccessible(true);
        Object obj4 = clazz.getConstructor().newInstance();
        field4.set(obj4, 100.1f);
        Student student4 = (Student) obj4;
        System.out.println(student4.getScore());
    }

    @Test
    public void methodTest() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clazz = Class.forName("com.hy.reflect.Student");

        System.out.println("-------------分割线1----------------------");
        Method[] methods1 = clazz.getMethods();
        for (Method method : methods1) {
            System.out.println("method:" + method + ",parameterCount:" + method.getParameterCount() + ",returnType:" + method.getReturnType());
        }

        System.out.println("-------------分割线2----------------------");
        Method[] methods2 = clazz.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.println("method:" + method + ",parameterCount:" + method.getParameterCount() + ",returnType:" + method.getReturnType());
        }

        System.out.println("-------------分割线3----------------------");
        Method method3 = clazz.getMethod("study1");//study1公有
        System.out.println(method3);
        Object obj3 = clazz.getConstructor().newInstance();
        method3.invoke(obj3);

        System.out.println("-------------分割线4----------------------");
        Method method4 = clazz.getDeclaredMethod("study3");//study3私有
        System.out.println(method4);
        method4.setAccessible(true);
        Object obj4 = clazz.getConstructor().newInstance();
        method4.invoke(obj4, null);
    }

    @Test
    public void invokeTest() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Student student1 = new Student();
        long start1 = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            student1.getName();
        }
        long end1 = System.currentTimeMillis();
        System.out.println("new Student()->" + (end1 - start1));

        System.out.println("-------------分割线1----------------------");
        Class clazz2 = Class.forName("com.hy.reflect.Student");
        Method method2 = clazz2.getMethod("getName");
        long start2 = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            method2.invoke(student1);
        }
        long end2 = System.currentTimeMillis();
        System.out.println("Class.forName(no access)->" + (end2 - start2));

        System.out.println("-------------分割线2----------------------");
        Class clazz3 = Class.forName("com.hy.reflect.Student");
        Method method3 = clazz3.getMethod("getName");
        method3.setAccessible(true);
        long start3 = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            method3.invoke(student1);
        }
        long end3 = System.currentTimeMillis();
        System.out.println("Class.forName(access)->" + (end3 - start3));
    }

    @Test
    public void mainTest() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class clazz = Class.forName("com.hy.reflect.Student");

        System.out.println("-------------分割线1----------------------");
        Method method1 = clazz.getMethod("main", String[].class);
        method1.invoke(null, (Object) new String[]{"..."});
    }

    @Test
    public void typeClearTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        List<String> list1 = new ArrayList<>();
        list1.add("aaa");
        list1.add("bbb");
//        list1.add(123);

        Class clazz = list1.getClass();
        Method method1 = clazz.getMethod("add", Object.class);
        method1.invoke(list1, 123);
        for (Object str : list1) {
            System.out.println(str);
        }
    }

    @Test
    public void typeTest() throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class clazz = Class.forName("com.hy.reflect.Cache");

        System.out.println("-------------分割线1----------------------");
        Field field1 = clazz.getDeclaredField("item");
        Type type1 = field1.getGenericType();
        System.out.println("type:" + type1);

        System.out.println("-------------分割线2----------------------");
        Method method2 = clazz.getDeclaredMethod("getItem");
        Type[] type2 = method2.getGenericParameterTypes();
        for (Type type : type2) {
            System.out.println("genericParameterType:" + type);
        }
        Type type = method2.getGenericReturnType();
        System.out.println("genericReturnType:" + type);
    }

    @Test
    public void annotationTest() throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class clazz = Class.forName("com.hy.reflect.Person");

        System.out.println("-------------分割线1----------------------");
        Annotation[] annotation1 = clazz.getAnnotations();
        for (Annotation annotation : annotation1)
            System.out.println(annotation);

        System.out.println("-------------分割线2----------------------");
        Annotation[] annotation2 = clazz.getDeclaredField("name").getAnnotations();
        for (Annotation annotation : annotation2)
            System.out.println(annotation);

        System.out.println("-------------分割线3----------------------");
        Annotation[] annotation3 = clazz.getDeclaredMethod("toString").getAnnotations();
        for (Annotation annotation : annotation3)
            System.out.println(annotation);
    }
}

 

思考1:

List<String> list1 = new ArrayList<String>();
List<Integer> list2 = new ArrayList<Integer>();

System.out.println("list1.getClass() == list2.getClass():"+(list1.getClass() == list2.getClass()));

思考2:

如何提升反射调用的性能?(建议从阅读java.lang.reflect.Method源码着手,特别留意AccessibleObject/MethodAccessor/ReflectionFactory

相关类)

三、静态代理

代理模式:

代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。 简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。

静态代理的代理关系在编译期间就已经确定了的。它适合于代理类较少且确定的情况。

 
package com.hy.reflect;

public class StaticProxyTest {
    public static void main(String[] args) {
        HelloService helloService = new StaticProxy(new HelloSericeImpl());
        helloService.sayHello("every one");
    }
}

class StaticProxy implements HelloService {
    private HelloService helloService;

    public StaticProxy(HelloService helloService) {
        this.helloService = helloService;
    }

    @Override
    public void sayHello(String name) {
        System.out.println("static proxy do something...");
        helloService.sayHello(name);
        System.out.println("static proxy do something...");
    }
}

interface HelloService {
    void sayHello(String name);
}

class HelloSericeImpl implements HelloService {

    @Override
    public void sayHello(String name) {
        System.out.println("Hello " + name);
    }
}

 

静态代理的缺点:

1.冗余。由于代理对象要实现与目标对象一致的接口/抽象类,会产生过多的代理类。

2.不易维护。如果真实类中有多个方法需要代理,每个方法都要去实现,一旦接口增加方法,目标对象与代理对象都要进行修改。

四、动态代理

动态代理:代理类在程序运行时创建的代理方式被称为动态代理

基于JDK的动态代理原理:主要是利用了Java的反射机制。

 
package com.hy.reflect;

import sun.misc.ProxyGenerator;

import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxyTest {
    public static void main(String[] args) {
        saveProxyFile("/Users/zhouy/Documents/workspaces/test/hy-reflect-test/tmp/proxy/");

        long startTime = System.currentTimeMillis();
        HelloService helloService = (HelloService) Proxy.newProxyInstance(HelloService.class.getClassLoader(), new Class[]{HelloService.class}, new DynamicProxy(new HelloSericeImpl()));
        helloService.sayHello("every one");
        System.out.println("execute time:" + (System.currentTimeMillis() - startTime));
    }

    private static void saveProxyFile(String... filePath) {
        if (filePath.length == 0) {
            System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        } else {
            FileOutputStream out = null;
            try {
                byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", HelloSericeImpl.class.getInterfaces());
                out = new FileOutputStream(filePath[0] + "HelloService$Proxy0.class");
                out.write(classFile);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    if (out != null) {
                        out.flush();
                        out.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

class DynamicProxy implements InvocationHandler {
    private Object target;

    public DynamicProxy(Object obj) {
        this.target = obj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke before...");
        Object result = method.invoke(target, args);
        System.out.println("invoke after...");
        return result;
    }
}

 

动态代理特点:

1.动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。

2.动态代理是使用反射去调用真实类,处理代理的逻辑都在 InvocationHandler 实现类的 invoke 方法中,比静态代理好维护。但是JDK的动态代理机制必须基于接口,Proxy.newProxyInstance 方法必须传入一个接口,在非接口实现类中,只能使用静态代理,或使用第三方方案,例如CGLIB库。

CGLIB动态代理

CGLIB(Code Generation Library) 是一个基于 ASM 的字节码生成库,它允许在运行时对字节码进行修改和动态生成,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。CGLIB 通过 继承方式 实现代理。

优点:没有接口也能实现动态代理,而且采用字节码增强技术,性能也不错。 缺点:技术实现相对难理解些。

 
package com.hy.reflect;

import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class DynamicCglibTest {
    public static void main(String[] args) {
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "/Users/zhouy/Documents/workspaces/test/hy-reflect-test/tmp/cglib/");

        long startTime = System.currentTimeMillis();
        AbstractHelloService helloService = new AbstractHelloServiceImpl();
        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(helloService.getClass().getClassLoader());
        enhancer.setSuperclass(helloService.getClass());
        enhancer.setCallback(new DynamicCglib(helloService));

        AbstractHelloService proxyClass = (AbstractHelloService) enhancer.create();
        proxyClass.sayHello("any one");

        System.out.println("execute time:" + (System.currentTimeMillis() - startTime));
    }
}

class DynamicCglib implements MethodInterceptor {
    private Object target;

    public DynamicCglib(Object obj) {
        this.target = obj;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("startTime:" + System.currentTimeMillis());
        try {
            return method.invoke(target, objects);
        } finally {
            System.out.println("endTime:" + System.currentTimeMillis());
        }
    }
}

abstract class AbstractHelloService {
    abstract void sayHello(String name);
}

class AbstractHelloServiceImpl extends AbstractHelloService {

    @Override
    void sayHello(String name) {
        System.out.println("Hello " + name);
    }
}

 

CGLIB与JDK 动态代理的区别:

1.使用动态代理的对象必须实现一个或多个接口

2.使用cglib代理的对象则无需实现接口,达到代理类无侵入

3.cglib代理无需实现接口,通过生成类字节码实现代理,比反射稍快,不存在性能问题,但cglib会继承目标对象,需要重写方法,所以目标对象不能为final类

 

静态代理与动态代理的区别:

1.静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件

2.动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中

五、动态编程

动态编程就是绕过编译过程在运行时进行操作的技术,在Java中有如下几种方式:

 

  • 反射
  • 动态编译(JavaCompiler)
  • 调用JavaScript引擎
  • 动态生成字节码

 

 

 

 
package com.hy.reflect;

import javax.tools.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Arrays;

public class JavaCompilerTest {
public static void main(String[] args) {
String className = "com.hy.reflect.HelloWorldTest";
StringBuilder sb = new StringBuilder();
sb.append("package com.hy.reflect;");
sb.append("\n public class HelloWorldTest {");
sb.append("\n public static void main(String[] args) {");
sb.append("\n System.out.println(\"Hello World!\");");
sb.append("\n }");
sb.append("\n }");
Class clazz = new JavaCompilerTest().compiler(className, sb.toString());
try {
Method method = clazz.getMethod("main", String[].class);
method.invoke(null, new Object[]{new String[]{}});
} catch (Exception e) {
e.printStackTrace();
}
}

public Class<?> compiler(String className, String javaCodes) {
JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(null, null, null);
Iterable<String> options = Arrays.asList("-d", "/Users/zhouy/Documents/workspaces/test/hy-reflect-test/tmp/javacompiler/");
Iterable<? extends JavaFileObject> compilationFileObject = Arrays.asList(new StringJavaObject(className, javaCodes));
JavaCompiler.CompilationTask compilationTask = javaCompiler.getTask(null, fileManager, null, options, null, compilationFileObject);
if (compilationTask.call() == true) {
try {
return new MyClassLoader().findClass(className);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}

private static class StringJavaObject extends SimpleJavaFileObject {
private String content;

StringJavaObject(String name, String content) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.content = content;
}

public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return content;
}
}

class MyClassLoader extends ClassLoader {
public Class<?> findClass(String name) {
try {
FileInputStream input = new FileInputStream(new File("/Users/zhouy/Documents/workspaces/test/hy-reflect-test/tmp/javacompiler/com/hy/reflect/HelloWorldTest.class"));
ByteArrayOutputStream output = new ByteArrayOutputStream();
int len = 0;
while ((len = input.read()) != -1) {
output.write(len);
}
byte[] bytes = output.toByteArray();
input.close();
output.close();
return defineClass(name, bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
}

 

 

动态生成字节码主要有:

ASM :直接操作字节码指令,执行效率高,要是使用者掌握Java类字节码文件格式及指令,对使用者的要求比较高。

Javassit 提供了更高级的API,执行效率相对较差,但无需掌握字节码指令的知识,对使用者要求较低。

 

 

 

 

 

 

 
package com.hy.reflect;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

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

public class AssemblyTest {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
byte[] bytes = generate();
Class cls = new TestClassLoader().defineClass("com.hy.reflect.HelloWorldTest", bytes);
Method method = cls.getMethod("main", String[].class);
method.invoke(null, new Object[]{new String[]{}});
}

private static byte[] generate() {
ClassWriter cw = new ClassWriter(0);
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "com/hy/reflect/HelloWorldTest", null, "java/lang/Object", null);
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("Hello World!");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
mv.visitInsn(Opcodes.RETURN);
mv.visitMaxs(2, 1);
mv.visitEnd();
cw.visitEnd();
return cw.toByteArray();
}
}

class TestClassLoader extends ClassLoader {
public Class<?> defineClass(String name, byte[] b) {
return super.defineClass(name, b, 0, b.length);
}
}

 

 
//javassit样例代码:ganglia>

com.weshare.ganglia.Application static void localTest(){
try{
javassist.ClassPool classPool=javassist.ClassPool.getDefault();
classPool.importPackage("org.apache.hadoop.fs.Path");
javassist.CtClass ctClass=classPool.get("com.weshare.sdk.bone.service.HService");
ctClass.getConstructor("()V").insertAt(67,"conf.addResource(new Path(appProperty.getString(\"core.site\")));");
ctClass.toClass();}catch(Exceptione){logger.error("HService.getInstance error:{}",e);
}
} 。。。

 

 

六、应用

Spring框架(IOC/AOP)、Mybatis、事务、日志、系统监控、Dubbo等等。



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值