简单实现
Q:通过代理接口的方式进行声明, 然而不通过类实现的方式进行使用,而是使用其他方式实现.
比如MyBatis
如何做到只定义接口, 逻辑写到xml中,就可以调用接口?
FeignClient
为什么只做了声明,却可以直接使用接口进行注入?
A: 其实这些底层都是用于了一个叫做代理的方式来实现的
比如 现在有一个接口是这样的
interface TestInterface {
String test01();
String test02(String st, String st2);
}
借助 代理的方式给他提供方法的实现,需要用到 Proxy.newProxyInstance
这个方法
newProxyInstance
,方法有三个参数:
-
loader
: 用哪个类加载器去加载代理对象 -
interfaces
: 动态代理类需要实现的接口 -
h
:InvocationHandler
类型 动态代理方法在执行时,会调用h
里面的invoke
方法去执行
loader
实例很好获得, 使用getClass().getClassLoader()
即可.
现在来构造一个 interfaces
的实例
new Class[]{TestInterface.class}
构造一个 h
的对象
static class TestProxy implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
动态创建一个接口的实例
InvocationHandler h = new TestProxy();
TestInterface obj = (TestInterface) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{TestInterface.class}, h);
以上,就完成了大概调用的编写. 接着来完成接口实现.
完善TestProxy.invoke
方法
@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;
}
}
完成 方法的调用
InvocationHandler h = new TestProxy();
TestInterface obj = (TestInterface) Proxy.newProxyInstance(getClass().getClassLoader(),
new Class[]{TestInterface.class}, h);
//调用接口中的方法.
String res = obj.test01();
System.out.println(res);
简单的封装
创建一个工厂
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);
}
}
通过工厂来调用
TestInterface t = TestFactory.newInstance(TestInterface.class);
String res = t.test02("111", "222");
System.out.println(res);
完整的测试类
package cn.com.dunlop.util;
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);
}
}
总结
通过这种代理方式,可以很轻松做到动态创建接口实现类.
网友评论