java动态代理是一个挺有意思的东西,他有时候可以被使用的很灵活。像rpc的调用,调用方只是定义的一个接口,动态代理让他匹配上对应的不同接口;mybatis内部的实现,编码时,只是实现了mapper层的接口和sql的xml的配置,动态代理把他们连起来。记得之前在一家公司,他们使用thrift做rpc的解决方案,每个项目都得管理thrift的连接和关闭,代码考来考去,在spring下还得不断new对象。后来参照mybatis的实现方式,使用动态代理,做成spring注入的方式,方便很多,程序员只需要加些配置就好了。

 

       java动态代理是一个挺有意思的东西,他有时候可以被使用的很灵活。像rpc的调用,调用方只是定义的一个接口,动态代理让他匹配上对应的不同接口;mybatis内部的实现,编码时,只是实现了mapper层的接口和sql的xml的配置,动态代理把他们连起来。记得之前在一家公司,他们使用thrift做rpc的解决方案,每个项目都得管理thrift的连接和关闭,代码考来考去,在spring下还得不断new对象。后来参照mybatis的实现方式,使用动态代理,做成spring注入的方式,方便很多,程序员只需要加些配置就好了。

 

     先来一个动态代理的简单实例:

/**
 * Created by sten on 7/12/16.
 */
public interface Person {

    void eat() ;
}
 
/**
 * Created by sten on 7/12/16.
 */
public class Chinese implements Person {

    @Override
    public void eat() {
        System.out.print("eat fish.");
    }
}
 
/**
 * Created by sten on 7/12/16.
 */
public class InvocationTest implements InvocationHandler {

    private Person person ;

    public InvocationTest(Person person) {
        this.person = person ;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(person, args);
    }
}
 
/**
 * Created by sten on 7/12/16.
 */
public class Main {

    public static void main(String[] args) {

        Chinese chinese = new Chinese() ;

        Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),
                new Class[]{Person.class},
                new InvocationTest(chinese));

        person.eat();
    }

}

 

 

这是一般动态代理的范式,Chinese代理Person的实现,接口person每个方法的调用,实际执行的方法是InvocationTest.invoke, 当然,还有动态代理还有其他实现方式。

 

这里实现简单实现下mybatis的动态代理:

 

假设解析完mapper和xml,知道每个mapper的方法对应的sql了,通过类名和方法名,就可以执行sql

 

 

/**
 * Created by sten on 7/12/16.
 */
public class SqlMap {

    private Map<String, String> map = new HashedMap() ;

    public SqlMap() {
        map.put("Class1.method1","select sql1") ;
        map.put("Class1.method2","delete sql1") ;
        map.put("Class1.method3","update sql1") ;
        map.put("Class1.method4","insert sql1") ;
        map.put("Class2.method1","select sql2") ;
        map.put("Class2.method2","delete sql2") ;
        map.put("Class2.method3","update sql2") ;
        map.put("Class2.method4","insert sql2") ;
    }

    public String getSql(String classNameMethodName) {
        return  map.get(classNameMethodName) ;
    }

}

 

 

假设定义的一个mapper

 

/**
 * Created by sten on 7/12/16.
 */
public interface Class1 {

    String method1() ;

    String method2() ;

    String method3() ;

    String method4() ;
}

 


 

InvocationHandler的实现

 

/**
 * Created by sten on 7/12/16.
 */
public class InvocationSql implements InvocationHandler {

    private Class interfaceObject ;

    private SqlMap sqlMap ;

    public InvocationSql(Class interfaceObject, SqlMap sqlMap) {
        this.interfaceObject = interfaceObject ;
        this.sqlMap = sqlMap ;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        String key = interfaceObject.getClass().getName() + "." + method.getName() ;
        String value = sqlMap.getSql(key) ;

        return value ;
    }
}

 


 

根据mapper接口生成对象

 

/**
 * Created by sten on 7/12/16.
 */
public class TargetProxy<T> {

    public T  getTarget(Class<T> interfaceObject, SqlMap sqlMap) {

        InvocationSql invocationSql = new InvocationSql(interfaceObject, sqlMap) ;

        return (T)newProxyInstance(interfaceObject.getClassLoader(),new Class[] {interfaceObject},
                invocationSql) ;
    }

}

 


 

执行生成的对象

 

/**
 * Created by sten on 7/12/16.
 */
public class Bitis {


    public static void main(String[] args) {

        TargetProxy targetProxy = new TargetProxy() ;

        Class1 class1 = (Class1) targetProxy.getTarget(Class1.class, new SqlMap());

        class1.method1() ;
    }

}

 

 

 

 

 

 

松下问童子,言师采药去。 只言此山中,云深不知处。