定义:代理一个对象,去执行对象的方法。
使用场景:根据开闭原则,很多时候我们不能去直接修改被代理的实现类,而又要增加业务逻辑,这时可以使用代理模式。
举例:比如我们调用一个第三方接口的方法,现在有个新需求,在执行某个方法前,需要记录日志,我们无法修改第三方接口,这时可以使用代理模式。
优点:程序扩展性、可维护性增强,无需更改以前的实现。
1. 静态代理
对每一个需要被代理的类,新增一个代理类;
1.1 支付接口
public interface PayService {
void pay();
}
1.2 被代理对象,实现支付接口
public class PayServiceImpl implements PayService{
@Override
public void pay() {
System.out.println("支付完成");
}
}
1.3 代理类,实现支付接口
public class StaticProxy implements PayService{
private PayService payService;
public StaticProxy(PayService payService) {
this.payService = payService;
}
@Override
public void pay() {
System.out.println("支付日志记录...");
payService.pay();
}
}
1.4 调用示例:
public class StaticProxyMain {
public static void main(String[] args) {
PayService payService = new PayServiceImpl();
StaticProxy proxy = new StaticProxy(payService);
proxy.pay();
}
}
打印结果如下:
支付日志记录...
支付完成
2.动态代理
采用InvocationHandler实现,InvocationHandler是一个JDK提供的标准接口。在动态代理实现时,无需指定被代理的类,在具体调用时再指定。
2.1 重写代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxy implements InvocationHandler{
private Object obj;
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(this.obj, args);
return result;
}
}
2.2 调用示例
import java.lang.reflect.Proxy;
public class DynamicProxyMain {
public static void main(String[] args) {
PayService payService = new PayServiceImpl();
DynamicProxy proxy = new DynamicProxy(new PayServiceImpl());
PayService payServiceProxy = (PayService) Proxy.newProxyInstance(payService.getClass().getClassLoader(), payService.getClass().getInterfaces(), proxy);
System.out.println("支付日志记录...");
payServiceProxy.pay();
}
}
打印结果和上面是一致的. 下面这段代码返回PayService,但并不是PayServiceImpl的实例,而是JVM给我们加过工的,包含了我们在invoke方法里的实现。debug,payServiceProxy类型为$Proxy0
PayService payServiceProxy = (PayService) Proxy.newProxyInstance(payService.getClass().getClassLoader(), payService.getClass().getInterfaces(), proxy);