各方面的知识来源都在说,jdk动态代理要求类要有接口。实际上跟类没关系,jdk动态代理代理的就是接口。
最为典型的就是mybatis,我们可以看到Mapper接口明明没有实现方法,而实际上却走向了数据库操作,那么它就是对接口进行代理,增强了功能,不止增强了一点点,因为以前是接口根本就没有实现功能。
jdk动态代理的核心类就是Proxy.接下来看个示例:
1.接口类
public interface MyMapper {
void aaa();
int bbb();
}
2.接口实现类
public class MyObject implements MyMapper{
@Override
public void aaa() {
System.out.println("aaa");
}
@Override
public int bbb() {
System.out.println("bbb");
return 0;
}
public void ccc() {
System.out.println("ccc");
}
}
3.使用proxy进行测试
public class ProxyTest {
public static void main(String[] args) {
MyMapper mapper = new MyObject();
Object object = Proxy.newProxyInstance(ProxyTest.class.getClassLoader()
, new Class[] {MyMapper.class}
, (proxy,method,params) -> {
if (method.getName().equals("bbb")) {
return 1;
}else {
System.out.println("增强前");
Object invoke = method.invoke(mapper, params);
System.out.println("增强后");
return invoke;
}
});
MyMapper proxy = (MyMapper) object;
proxy.aaa();
System.out.println(proxy.bbb());
}
}
打印结果:
增强前
aaa
增强后
1
为什么会这样?这里面的道道还是比较多的,容我一一道来。
我们直接看测试类,Proxy这个类就是jdk动态代理的核心类,它 的核心方法就是创建一个接口的代理类,
我们可以看下newProxyInstance这个方法的参数,第一个参数是classLoader,一般来说,都是当前loader,这个没什么好说的,然后就是一组接口,这个可以通过class.interfaces来获得。
最后的那个参数是一个方法处理类InvocationHandler,也就是说,所创建的代理类,执行方法就是执行InvocationHandler的这个invoke方法。
就好比我们最后生成了一个Mapper的proxy,它调用方法是不走实际方法的,而是只走InvocationHandler.invoke方法,而我们在invoke里做了判断,如果是bbb方法,直接返回1,否则我们调用初始的那个对象的bbb方法,并且在调用方法前后分别打印一句话,这一切才造成了如上的结果。
需要注意的是,只能代理接口,不能代理实际类,否在会报错。