要用静态代理,必须有代理类,以及代理类和目标类(要被增强被代理的类)要实现同一个接口。首先我们定义一个接口,里面有2个方法。
public interface ISomeService {
public String doMethod1();
public String doMethod2();
}
接下来是目标类的实现情况:
public class ISomeServiceImpl implements ISomeService {
@Override
public String doMethod1() {
System.out.println("执行1方法");
return "abc";
}
@Override
public String doMethod2() {
System.out.println("执行2方法");
return "def";
}
}
方法1 和方法2我们都要它们返回小写的字符串,现在需求来了,我们要方法1返回的字符串abc变成大写,方法2返回的字符串 def我们再给它后面加上“nihao”。(有前提条件是,我们不可以动目标类,也就是说不能在 ISomeServiceImpl里改。)
接下来是代理类,我们取名为Proxy,它也要实现以上接口。
public class Proxy implements ISomeService{
ISomeService target = new ISomeServiceImpl();
public Proxy(ISomeService target) {
this.target = target;
}
@Override
public String doMethod1() {
//调用目标方法,该方法返回小写字母
System.out.println("在代理增强开始前");
String result = target.doMethod1();
result = result.toUpperCase();
System.out.println("在代理增强结束后");
//增强目标方法,把小写字母转换为大写字母
return result ;
}
@Override
public String doMethod2() {
System.out.println("在代理增强开始前");
String result = target.doMethod2();
result = result.concat(" ni hao ");
System.out.println("在代理增强结束后");
//增强目标方法,把小写字母转换为大写字母
return result ;
}
}
我们从以上代码可以看到,我们需要在代理类里面有目标类的实例,target,把它传入带参构造器。这样就一个代理类和一个目标类对应上了。代理类实现的2个方法里面,真正执行方法的是目标类实例target,但是我们可以在执行的前后对它进行操作(也就是代理,加强)。如图上打印“开始前 ”,“开始后”的位置。
接着我们就可以在Test里面看结果了。
public class MyTest {
public static void main(String[] args) {
ISomeService target = new ISomeServiceImpl();
//目标类对象 target
ISomeService proxy = new Proxy(target);
//将target传入 Proxy的构造器,让它们对应
String str1 = proxy.doMethod1();
//实质上proxy.doMethod1方法体里面,是target做了方法1,代理类只是给它加强了。
System.out.println(str1);
String str2 = proxy.doMethod2();
System.out.println(str2);
}
}
输出结果如下:
在代理增强开始前
执行1方法
在代理增强结束后
ABC
在代理增强开始前
执行2方法
在代理增强结束后
def ni hao
静态代理的缺点1: 因为代理类和目标类要实现同一个接口,所以里面会有很多代码在逻辑上是重复的,另外如果接口里再增加方法,实现类和代理类也要对应的都增加方法,方法多了过后,会有代码冗余的问题(相同/类似的代码过多,让人感觉很复杂)。
静态代理的缺点2:我们一个代理类只能代理一个类型的目标类,比如以上例子,我们的Proxy,只能为ISomeServiceImpl服务,如果再有别的类需要代理,我们这个代理类就不能用了,而是得再给别的类,写一个代理类,再使用。 静态代理不利于扩展。