一、概念
代理模式是一种设计模式,能够在不修改源目标的前提下,额外扩展源目标的功能。即通过访问源目标的代理类,再由代理类去访问源目标。这样一来,要扩展功能,就无需修改源目标的代码了。只需要在代理类上增加就可以了。
常见的代理分为:静态代理和动态代理。 至于两者之间的区别和优劣势,通过接下来的代码进行演示。
二、静态代理
要求:在某个类执行类中方法时,添加日志信息
1、定义接口
public interface Calculate {
public int add(int a,int b);
}
2、定义实现类
public class Calculator implements Calculate{
@Override
public int add(int a, int b) {
System.out.println(a+b);
return a+b;
}
}
3、定义代理类
public class CalculatorWithLog implements Calculate{
Calculator calculator = new Calculator();
public CalculatorWithLog (Calculator calculator){
this.calculator = calculator;
}
@Override
public int add(int a, int b) {
System.out.println("增强执行前日志");
int res = calculator.add(a,b);
System.out.println("增强执行后日志");
return res;
}
}
4、测试
public static void main(String[] args) {
Calculator calculator = new Calculator();
Calculate withLog = new CalculatorWithLog(calculator);
withLog.add(1, 3);
}
总结:
静态代理在实际使用过程中,会存在如下问题:
- 对于每一个目标类均需要编写相应的代理类,对于大量目标类编写对应的代理类不切实际
- 当接口改变时,所有的代理类和目标类均需要改变,耦合过深
二、动态代理
动态代理指在程序运行过程中,使用JDK的反射机制,创建代理对象,并动态指定代理的目标类 ,使用JDK反射包下的Proxy和InvocationHandler实现代理对象的动态创建。
1、Proxy类
动态代理中最核心的一个类,使用静态方法newProxyInstance(),创建代理对象,其方法入参包含:
- ClassLoader loader:类加载器,负责向内存中加载对象,需要使用对应目标对象的类加载器
- Class<?>[] interfaces:目标对象实现的接口
- InvocationHandler invocation:自定义代理类需要实现的功能,返回值为代理对象
2、InvocationHandler接口
接口中仅实现一个方法:invoke(),自定义代理类需要增强的功能在此方法中实现。
即invoke()方法中需要完成的功能:
- 调用目标类方法
- 功能增强,在目标方法调用前后,增加功能
3、动态代理示例
1、定义接口
同理静态代理部分
2、定义实现类
同理静态代理部分
3、创建InvocationHandler实现类,实现代理方法
public class MyInvocationHandler implements InvocationHandler {
private Object target = null;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = method.invoke(target,args);
System.out.println("代理增强!!");
return res;
}
}
其中,target对象为代理的目标对象
4、Proxy类创建代理对象,并通过接口类型调用方法
public static void main(String[] args) {
Calculator calculator = new Calculator();
InvocationHandler invocationHandler = new MyInvocationHandler(calculator);
Calculate x = (Calculate) Proxy.newProxyInstance(calculator.getClass().getClassLoader(),
calculator.getClass().getInterfaces(),
invocationHandler );
x.add(1,3);
}
总结:
相较于静态代理,动态代理可在不改变目标方法功能的前提下,完成代理功能增强,即在实际应用中,用于在不修改目标方法的基础上,增强不满足要求的方法。