Giter Site home page Giter Site logo

blog's Introduction

blog's People

Contributors

liangbizhi avatar

Watchers

 avatar

blog's Issues

关于Java动态生成代码

Java动态代理

http://www.importnew.com/27772.html

假设我们有接口:

public interface Hello {
    String sayHello(String name);
}

有其实现类:

public class HelloImpl implements Hello {
    @Override
    public String sayHello(String name) {
        return "hello, " + name;
    }
}

Java静态代理

于是我们可以编写HelloImpl的静态代理类实现:

public class StaticHelloProxy extends HelloImpl {

    private Hello hello = new HelloImpl();

    @Override
    public String sayHello(String name) {
        System.out.println("before say hello");
        return super.sayHello(name);
    }
}

Java动态代理

首先实现一个InvocationHandler,方法调用会被转发到该类的invoke()方法

public class HelloInvocationHandler implements InvocationHandler {

    private Hello hello;

    public HelloInvocationHandler(Hello hello) {
        this.hello = hello;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("sayHello".equals(method.getName())) {
            System.out.println("before invoke sayHello");
        }
        return method.invoke(hello, args);
    }
}

接着通过JDK动态代理获取Hello的代理对象:

public class JdkDynamicMain {
    public static void main(String[] args) {
        Hello hello = (Hello) Proxy.newProxyInstance(
                // 类加载器
                JdkDynamicMain.class.getClassLoader(),
                // 代理类需要实现的接口
                new Class[]{Hello.class},
                // 方法调用实际的处理者
                new HelloInvocationHandler(new HelloImpl()));

        System.out.println(hello.sayHello("bizhi"));
    }
}

可以发现hello.getClass().getName()com.sun.proxy.$Proxy0
hello.getClass().getSuperclass().getName()java.lang.reflect.Proxy

的确是动态生成了类型。

缺点:只支持接口代理。

CGLIB动态代理

假设有一个类:

public class Hello {
    public String sayHello(String name) {
        return "hello: " + name;
    }
}

首先实现一个MethodInterceptor,方法调用会被转发到该类的intercept()方法。

public class HelloMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before invoke sayHello");
        return methodProxy.invokeSuper(o, args);
    }
}

测试一下:

public class HelloMethodInterceptorMain {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Hello.class);
        enhancer.setCallback(new HelloMethodInterceptor());

        Hello hello = (Hello) enhancer.create();
        System.out.println(hello.sayHello("bizhi"));
    }
}

使用CGLIB为类动态添加属性

将属性写进配置文件中classpath:/config/PlainObject.properties中:

hello=你好

假设有普通类:

public class PlainObject {
}

封装的CGLIB类:

public class DynamicBean {
    private Object object = null;
    private BeanMap beanMap = null;

    public DynamicBean(Map propertyMap) {
        this.object = generateBean(propertyMap);
        this.beanMap = BeanMap.create(this.object);
    }

    private Object generateBean(Map propertyMap) {
        BeanGenerator generator = new BeanGenerator();
        // 所有属性名
        Set keySet = propertyMap.keySet();
        for (Iterator iterator = keySet.iterator(); iterator.hasNext(); ) {
            String key = (String) iterator.next();
            generator.addProperty(key, (Class) propertyMap.get(key));
        }
        return generator.create();
    }

    public void setValue(Object property, Object value) {
        beanMap.put(property, value);
    }

    public Object getValue(String property) {
        return beanMap.get(property);
    }

    public Object getObject() {
        return this.object;
    }
}

从配置文件读取配置并添加到类中逻辑:

public class ClassUtil {

    private static final String filePath = "/config/";

    public static Object dynamicClass(Object object) throws Exception {
        Map<String, Object> returnMap = new HashMap<>();
        Map<String, Object> typeMap = new HashMap<>();
        // 读取配置文件
        Properties properties = new Properties();

        String sourcepackage = object.getClass().getName();
        String classname = sourcepackage.substring(sourcepackage.lastIndexOf(".") + 1);
        InputStream in = ClassUtil.class.getResourceAsStream(filePath + classname + ".properties");

        properties.load(in);

        Set<String> keyList = properties.stringPropertyNames();
        // 先读取对象原有属性
        Class type = object.getClass();
        BeanInfo beanInfo = Introspector.getBeanInfo(type);
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();
            if (!"class".equals(propertyName)) {
                Method readMethod = descriptor.getReadMethod();
                Object result = readMethod.invoke(object, new Object());
                // 读取属性值
                if (result != null) {
                    returnMap.put(propertyName, result);
                } else {
                    returnMap.put(propertyName, "");
                }
                // 读取属性类型
                typeMap.put(propertyName, descriptor.getPropertyType());
            }
        }
        // 加载配置文件中的属性,即要添加的属性
        Iterator<String> iterator = keyList.iterator();
        while(iterator.hasNext()) {
            String key = iterator.next();
            returnMap.put(key, properties.getProperty(key));
            typeMap.put(key, Class.forName("java.lang.String"));
        }

        // map转换成实体对象
        DynamicBean bean = new DynamicBean(typeMap);
        // 赋值
        Set<String> keys = typeMap.keySet();
        for (String key : keys) {
            bean.setValue(key, returnMap.get(key));
        }
        Object obj = bean.getObject();
        return obj;
    }

}

测试类:

public class CGLibMain {
    public static void main(String[] args) throws Exception {
        PlainObject newObj = (PlainObject) ClassUtil.dynamicClass(new PlainObject());
        System.out.println(newObj);
    }
}

https://blog.csdn.net/ajun_studio/article/details/6807181

直接由字符串编译得到类

还有一种是通过JDK 6+的编译API把Java文件直接编译到内存的手段:

https://blog.csdn.net/u013335025/article/details/82021328

第一章

昔々から、僕は生れだ。

人生なんて、意味はまだ知らない。

そろそろいきましょうが。

間もなく、1番線に回り、福田方面行きが参ります。危ないですから、黄色線までお下がりください。

次は福田、福田です。お出口は左側です。地下鉄2番線お乗り換えです。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.