再谈Java,反射

好像,是学过~

眼下,却怎也想不起来可以用他~

他是谁呢?他就是Java reflect.

【背景描述】

A的运行,依赖于B框架,还依赖了C jar包。其中,B、C皆为基础jar包,为众多系统使用,但相互间无必然联系。

有一天,A提出一个需求,要在dev下同一线程当中,需要B、C共享一些资源,如某些变量。

从实现上来讲,B、C就必须打通,即要相互依赖彼此。

【万分纠结】

这时候B、C就头痛了。B作为框架jar包,自是不能依赖于任何一个小小的上层jar包,而C作为通用的上层jar包,不止适用于B框架,对于UVW框架,也都是要适用的,也断然不可依赖B。

那么,应该怎么办呢?

【方案】

好了,开始想办法。

雨伞 方法一

描述:A反正已经依赖了B,也依赖了C,那么就干脆由A做二者的调停者,即C提供出回调接口,让A调B,然后在必要的时候回调C。

优势:B、C之间保持独立,升级也相对方便。(一旦扯上关系,升级起来就“扯”了)

劣势:A需要改代码,这是他最不愿意做的事情。(1)A可能代表着很多个系统,一改则全都要改,不现实;(2)这个功能仅在dev下使用,如果改了代码,线上就也得这么着run,这是最不希望看到的。(3)这段代码,与A具体的业务逻辑半毛钱关系都没有,硬生生的放在那儿,好生奇怪。

雨伞 方法二

描述:C稍微妥协一下,也不引入B的jar包,而只是用“reflect”来具体引用B提供的类及方法。同时需要加两处开关,(1) 环境开关,仍由B提供(B是框架嘛,自然做滴要多一点),(2)reflect来找这个类的这个方法,如果调不到,那就是A系统没有配置,暂时不启用这个功能,还是可以照run。完美,兼容。有些约束条件:

  • B提供的类名、方法名、必要的几个参数的类型,不许变;
  • 静态类,静态方法;(因为没必要设计成为单例或pojo对象,不需要维护什么属性状态值,只需将B、C共享的那一部分资源,放到线程的threadlocal当中就行了,B提供get/set方法给C用即可,如此便“通”也)
  • B类依赖的其他类(import),必须全都具备,这样C通过reflect方式调用才可能成功;

优势:没有明显jar包依赖,B、C基本做到了依然的“我行我素”,保持了自身的清白。

劣势:把B的类、方法、类形式,显式的限死了,绝对不能改,改了的后果就是那个功能不生效了,这样也算硬编码了吧?还是不够优雅。

雨伞 方法三…

其实,蹩脚的方法我还想了很多种,这里不再一一列举,哪位大侠路过,有没有好的意见建议呢?


【扩展】

下次,这些个情况,我得想起reflect:

再忘,就罚自己吃一桶冰淇淋!!!

(1)reflect是解除依赖的好办法,无论是系统间,还是系统内部上、下层间。编译时不care,运行时才care。

(2)用于某些模块集成场合。例如,当你不能在开发时即得到其目标类完整接口定义,只能根据命名规则去进行集成时。
(3)可以延伸到包装、动态代理等模式的应用中。
(4)有时候也干些hack的事情,比如绕过private保护机制啥的。

(5)较底层的代码,reflect用的比较多,例如Spring, SSH框架的实现。

反射,却也引入了一定的不优雅:类名、方法、参数类型,均不得变。

http://wenku.baidu.com/view/1cd6aa8302d276a200292eed.html

http://www.cnblogs.com/alipayhutu/archive/2012/04/09/2439499.html

【代码demo】

public class Main {
    
    /** 统一上下文类名 */
    private String CLASS_NAME = "com.hutu.reflect.UniformedContextManager";
    
    /** 获取统一上下文的方法名 */
    private String GET_METHOD_NAME = "checkExit";
    
    /** 设置统一上下文的方法名 */
    private String SET_METHOD_NAME = "checkEntrance";
    
    private Method getContextMethod = null;
    private Method setContextMethod = null;
    
    /**
     * 构造函数.
     */
    public Main() throws Exception{
        Class<?> classType = Class.forName(CLASS_NAME);
 
        // checkExit(String id, String ...other),注意第2个参数
        this.getContextMethod = classType.getMethod(GET_METHOD_NAME, new Class[] { String.class, String[].class });
        
        // checkEntrance(Object obj)
        this.setContextMethod = classType.getMethod(SET_METHOD_NAME, Object.class);
    }
    
    /**
     * 该方法获取统一上下文.
     * 
     * @param message
     * @return
     */
    public byte[] getUniformedContext(Message message){
        byte[] result = null;
        
        if(this.getContextMethod == null){
            return result;
        }
        
        try {
            // 静态方法
            Object projInfo = getContextMethod.invoke(null, new Object[] { message.getMessageId(), null});
            
            result = projInfo.toString().getBytes();
 
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    
    /**
     * 调用该方法设置统一上下文.
     * 
     * @param message
     */
    public void setUniformedContext(Message message){
        if(null == this.setContextMethod || null == message){
            return ;
        }
        try {
            // 静态方法,注意参数的写法,不能写作:null或new Object[]{}
            setContextMethod.invoke(null, new Object[]{null}); 
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        
    }
 
    /**
     * 主函数入口.
     * 
     * @param args
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
 
        try{
            Main o = new Main();
            o.getUniformedContext(new Message());
            o.setUniformedContext(new Message());
        }catch(Exception e){
            e.printStackTrace();
        }
    }
原文地址:https://www.cnblogs.com/alipayhutu/p/2562856.html