SSH前言学习笔记(4)

动态代理的实现

前面我们已经实现了静态代理,现在我们来实现动态代理

着重学习两种动态代理: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接口),但是没有名字

猜你喜欢

转载自blog.csdn.net/ValarMorghulisZ/article/details/80049647