静态代理的实现
前面我们完成了静态代理测试环境的搭建,下面开始实现静态代理
为了实现Java分层开发的思想,我们将原先的MyTest.java类放入com.QST.test包中
(1)、右击src,新建ServiceProxy类,这个类是静态代理类,代理类和目标类实现相同的接口,所以创建时在Interface选项中选择Add,选中ISomeService接口,并且新建package,命名为com.QST.proxy
(2)、之前说过,使用代理对象是为了在不修改目标对象的基础上增强主业务逻辑(SSH前言学习(2)3、代理模式),ISomeService接口是主业务接口,那么主业务接口中的方法将要被静态代理增强;SomeServiceImpl类是目标类,也就是代理类要增强的类;
接下来就要演示静态代理类如何在不修改目标类的基础上对目标类进行增强:
(3)、将接口中和目标类中的void doFirst();方法改为String doFirst();并且在目标类中的String doFirst();方法中返回abcde即return “abcde”;使用代理类可以将返回的abcde增强为ABCDE;
(4)、
首先:
调用目标对象的目标方法doFirst,此时的目标方法doFirst返回为全小写字母:
ISomeService service=new SomeServiceImpl();
service.doFirst();
此时将光标放到service.doFirst();的分号之后,按住Alt Shift和L键,在跳出的窗口中输入result,这个操作是如果doFirst()方法有返回值(在目标类中doFirst()方法返回值为abcde),则将方法的返回值抽取,并用result接收,可以得到:
ISomeService service=new SomeServiceImpl();
String result = service.doFirst();
然后:
对目标方法增强,将目标方法返回的全小写字母变为全大写:
输入:
result.toUpperCase();
使接收到的abcde变为全大写,在result.toUpperCase();后再次抽取局部变量,即 将生成的全大写抽取,赋值给result,不过之前已经定义过result,所以去掉String变为
ISomeService service=new SomeServiceImpl();
String result = service.doFirst();
result = result.toUpperCase();
return result;
至此静态代理类完成,不过在测试之前还有地方需要修改,我们还记得之前的MyTset测试类中new的对象是SomeServiceImpl即目标类,所以我们需要将
ISomeService service=new SomeServiceImpl();
service.doFirst();
中的SomeServiceImpl目标类改为ServiceProxy静态代理类,并且抽取静态代理类中doFirst方法的返回值(Alt Shift L),将接收的返回值输出:
ISomeService service=new ServiceProxy();
String result = service.doFirst();
System.out.println(result);
跑一下MyTest类得到:
此时运用静态代理在未改变目标类的基础上实现了增强目标类的功能
但是正常情况下不可能只执行目标类的一个方法,目标类中也会存在不需要被增强而运行的方法,例如本例中的doSecond();方法
此时如果想要运行doSecond();方法,在MyTest测试类中输入service.doSecond();是不会显示目标类中的doSecond();方法的,因为虽然在目标类中的doSecond();方法有内容,但是我们在测试类中调用的是静态代理类的doSecond();方法,里面并没有内容
此时的ServiceProxy(静态代理类):
public class ServiceProxy implements ISomeService {
@Override
public String doFirst() {
// TODO Auto-generated method stub
ISomeService service=new SomeServiceImpl();
String result = service.doFirst();
result = result.toUpperCase();
return result;
}
@Override
public void doSecond() {
// TODO Auto-generated method stub
}
}
如果想运行doSecond方法,可以将ISomeService service=new SomeServiceImpl();语句复制到doSecond方法中,然后在MyTest中输入service.doSecond();
但是如果是少数类还好,一旦工程比较大方法比较多操作起来就会很繁琐,因此我们可以将service改个名字,然后由局部变量改为成员变量:
工程内变量改名:
将光标放在需要改名的变量上面,然后按下Alt Shift R,输入另一个名字,例如将service改为target,回车
局部变量改为成员变量:
光标选中target,按下Ctrl 1,选择Conver local variable to field
之后将target =new SomeServiceImpl();复制放入doSecond();中,然后target.doSecond();
public class ServiceProxy implements ISomeService {
private ISomeService target;
@Override
public String doFirst() {
target = new SomeServiceImpl();
String result = target.doFirst();
result = result.toUpperCase();
return result;
}
@Override
public void doSecond() {
// TODO Auto-generated method stub
target = new SomeServiceImpl();
target.doSecond();
}
}
此时MyTest中的service.doSecond();方法可以运行
输出:
但是也没有必要一直复制target=new SomeServiceImpl();并且写target.doSecond();
我们可以创建一个带参构造器,但是在此之前我们需要创建一个无参构造器来使程序更稳定:
(1)、创建无参构造器:
在private ISomeService target;下面按Alt Shift S 松开S按C,回车创建出无参构造器
(2)、创建带参构造器:
在无参构造器下面Alt Shift S 松开 O,回车
创建带参构造器
此时可以在doSecond方法中输入target.doSecond();在MyTest中加上
ISomeService target=new SomeServiceImpl();然后在ISomeService service=new ServiceProxy();的括号中加上target
最下面加上service.doSecond();
SomeService.java:
public class ServiceProxy implements ISomeService {
private ISomeService target;
public ServiceProxy() {
super();
// TODO Auto-generated constructor stub
}
public ServiceProxy(ISomeService target) {
super();
this.target = target;
}
@Override
public String doFirst() {
target = new SomeServiceImpl();
String result = target.doFirst();
result = result.toUpperCase();
return result;
}
@Override
public void doSecond() {
// TODO Auto-generated method stub
target.doSecond();
}
}
MyTest.java:
public class MyTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
ISomeService target=new SomeServiceImpl();
ISomeService service=new ServiceProxy(target);
String result = service.doFirst();
System.out.println(result);
service.doSecond();
}
}
运行结果: