簡(jiǎn)單實(shí)現(xiàn)
Q:通過(guò)代理接口的方式進(jìn)行聲明, 然而不通過(guò)類實(shí)現(xiàn)的方式進(jìn)行使用,而是使用其他方式實(shí)現(xiàn).
比如MyBatis
如何做到只定義接口, 邏輯寫到xml中,就可以調(diào)用接口?
FeignClient
為什么只做了聲明,卻可以直接使用接口進(jìn)行注入?
A: 其實(shí)這些底層都是用于了一個(gè)叫做代理的方式來(lái)實(shí)現(xiàn)的
比如 現(xiàn)在有一個(gè)接口是這樣的
interface TestInterface {
String test01();
String test02(String st, String st2);
}
借助 代理的方式給他提供方法的實(shí)現(xiàn),需要用到 Proxy.newProxyInstance
這個(gè)方法
newProxyInstance
侵佃,方法有三個(gè)參數(shù):
-
loader
: 用哪個(gè)類加載器去加載代理對(duì)象 -
interfaces
: 動(dòng)態(tài)代理類需要實(shí)現(xiàn)的接口 -
h
:InvocationHandler
類型 動(dòng)態(tài)代理方法在執(zhí)行時(shí),會(huì)調(diào)用h
里面的invoke
方法去執(zhí)行
loader
實(shí)例很好獲得, 使用getClass().getClassLoader()
即可.
現(xiàn)在來(lái)構(gòu)造一個(gè) interfaces
的實(shí)例
new Class[]{TestInterface.class}
構(gòu)造一個(gè) h
的對(duì)象
static class TestProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
動(dòng)態(tài)創(chuàng)建一個(gè)接口的實(shí)例
InvocationHandler h = new TestProxy();
TestInterface obj = (TestInterface) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{TestInterface.class}, h);
以上,就完成了大概調(diào)用的編寫. 接著來(lái)完成接口實(shí)現(xiàn).
完善TestProxy.invoke
方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 假設(shè)這里按照不同的需求進(jìn)行了實(shí)現(xiàn).
switch (method.getName()) {
case "tet01": {
return "invoke==>" + UUID.randomUUID().toString();
}
case "test02": {
return "invoke==>" + Arrays.asList(args);
}
}
return null;
}
}
完成 方法的調(diào)用
InvocationHandler h = new TestProxy();
TestInterface obj = (TestInterface) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{TestInterface.class}, h);
//調(diào)用接口中的方法.
String res = obj.test01();
System.out.println(res);
簡(jiǎn)單的封裝
創(chuàng)建一個(gè)工廠
static class TestFactory {
public static <T> T newInstance(Class<T> clazz) {
InvocationHandler h = new TestProxy();
return (T) Proxy.newProxyInstance(TestFactory.class.getClassLoader(), new Class[]{clazz}, h);
}
}
通過(guò)工廠來(lái)調(diào)用
TestInterface t = TestFactory.newInstance(TestInterface.class);
String res = t.test02("111", "222");
System.out.println(res);
完整的測(cè)試類
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.UUID;
public class TestProxyClazz {
interface TestInterface {
String test01();
String test02(String st, String st2);
}
static class TestProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
switch (method.getName()) {
case "tet01": {
return "invoke==>" + UUID.randomUUID().toString();
}
case "test02": {
return "invoke==>" + Arrays.asList(args);
}
}
return null;
}
}
static class TestFactory {
public static <T> T newInstance(Class<T> clazz) {
InvocationHandler h = new TestProxy();
return (T) Proxy.newProxyInstance(TestFactory.class.getClassLoader(), new Class[]{clazz}, h);
}
}
@Test
public void tet01() {
InvocationHandler h = new TestProxy();
TestInterface obj = (TestInterface) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{TestInterface.class}, h);
String res = obj.test01();
System.out.println(res);
}
@Test
public void tet02() {
TestInterface t = TestFactory.newInstance(TestInterface.class);
String res = t.test02("111", "222");
System.out.println(res);
}
}
總結(jié)
通過(guò)這種代理方式,可以很輕松做到動(dòng)態(tài)創(chuàng)建接口實(shí)現(xiàn)類.