动态代理的实现
前面我们已经实现了静态代理,现在我们来实现动态代理
着重学习两种动态代理:JDK动态代理、CGLIB动态代理
(1)我们先将之前的01-staticProxy1复制粘贴,取名为02-dynamicProxy
之前说过,静态代理与动态代理的区别就是静态代理有代理类而动态代理没有,那么我们实现动态代理就需要将之前的动态代理类(com.QST.proxy包)删除
(2)、在MyTset类中将
ISomeService service=new ServiceProxy(target);
改为
ISomeService service= Proxy.newProxyInstance(loader, interfaces, h);
(关于Proxy的API可以参照JDK6API.chm的Proxy(JDK6API.chm资源已经放入下载))
然后进行更改:
ISomeService service= Proxy.newProxyInstance(
target.getClass().getClassLoader(),//目标类的加载器
target.getClass().getInterfaces(), //目标类实现的所有接口
h);
h其实是InvocationHandler(接口对象:接口的实现类的对象),对于h我们可以创建内部匿名类类【注1】:
ISomeService service= Proxy.newProxyInstance(
target.getClass().getClassLoader(),//目标类的加载器
target.getClass().getInterfaces(), //目标类实现的所有接口
new InvocationHandler() { //内部匿名类
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
return null;
}
});
此时会出现错误:Type mismatch: cannot convert from Object to ISomeService
其实是转换类型出现了错误,下面的解释是不能从Object到ISomeService接口进行转换,那么我们把光标放在出错行,Ctrl 1选择解决方案Add cast to “ISomeService”(即对Proxy进行强转)
变为(ISomeService)Proxy.newProxyInstance(...);
(3)、开始增强目标类中的目标方法
大家可以看到在内部匿名类中有三个参数:Proxy代理对象、method目标方法、args目标方法的参数列表
首先
在内部匿名类中加入代码:
method.invoke(obj, args);
将obj改为target
此时出现第二次错误:cannot refer to a non-final variable target inside an inner class defined in a different method
意思是在一个内部类中不能引用一个非final的变量target
我们可以选定target利用Ctrl 1将其改为final类型
然后对method.invoke进行抽取局部变量(Alt shift L)输入result
抽取之后
method.invoke(obj, args);
变为
Object result = method.invoke(target, args);
大家可以看到method.invoke的返回值默认为Object类型
然后
将return null;改为:
return ((String)result).toUpperCase();
对原本为Object类型的result进行强转,使其变为String类型
运行可以发现Console栏出现下面结果:
大家可以看到虽然对目标方法进行了强化并且执行了doSecond方法,但是却报了空指针异常
原因是在执行强化了doFirst方法之后会继续运行doSecond方法,此时也会调用内部匿名类,但是在抽取变量的时候发现doSecond方法并不像doFirst方法一样有abcde的返回值,相反doSecond方法没有返回值,所以result就是空的,才会报空指针的异常
我们可以将return的result进行抽取局部变量,把return语句变为:
String result = ((String)result).toUpperCase();
return result;
去掉String
然后全选语句result=((String)result).toUpperCase(); Alt Shift Z,弹出:
按5选择if得到:
if (condition) {
result = ((String) result).toUpperCase();
}
将if的条件改为result !=null
运行
得到:
成功消除空指针异常
完成动态代理实现
【注1】:内部匿名类:
new一个接口或者一个类的对象(本文new了一个InvocationHandler接口),但是没有名字
JDK6API中文版资源下载放在这里 https://pan.baidu.com/s/1nFxzVH1BJnJ6k7fU7G6GLQ
好像设置了密码,如果需要在下面留言我发一下(免费)