设计模式之代理模式
定义
为其它对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。
场景
1)保护目标对象
2)增强目标对象
分类
静态代理:
静态代理的原理是创建一个类来代理原始类,这个代理类与原始类实现相同的接口,并在其方法中调用原始类的方法,在其中可以添加额外的逻辑。
需要注意的是,静态代理在编译期间就已经确定了,每添加一个代理类,就需要手动创建一个新的代理类。这使得静态代理不太适合大规模或频繁使用代理的情况。
动态代理:
Java动态代理是基于Java的反射机制实现的。
它使用了两个关键类:Proxy 和 InvocationHandler。当调用Proxy.newProxyInstance()方法时,Java运行时会在内存中动态生成一个代理类,该代理类继承自指定接口,并在其中实现了指定接口的所有方法。生成的代理类会拦截对接口方法的调用,并将这些调用转发到InvocationHandler的invoke()方法中。在invoke()方法中,可以通过反射获取到被代理方法的相关信息,通过反射调用原始对象的方法。
需要注意的是,动态代理只能代理接口,而不能代理具体的类。这是由于代理类是继承自接口的,所以只能代理接口中的方法。如果需要代理具体的类,可以考虑使用其他的代理技术,如CGLib代理。
CGLib代理:
CGLib代理是一种基于继承的动态代理技术。它通过字节码技术创建目标类的一个子类来实现代理功能,然后重写或增加子类的方法来拦截对目标类方法的调用。
动态代理实现
1:我们定义一个接口 Animal:
public interface Animal {
void makeSound();
}
2:创建一个实现该接口的类 Cat:
public class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵");
}
}
3:建一个实现 InvocationHandler 接口的代理类 AnimalProxy,它将充当动态代理的中介:
public class AnimalProxy implements InvocationHandler {
private Animal animal;
public AnimalProxy(Animal animal) {
this.animal = animal;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法调用前进行一些操作
System.out.println("调用前");
// 调用实际对象的方法
Object result = method.invoke(animal, args);
// 在方法调用后进行一些操作
System.out.println("调用后");
return result;
}
}
4:调用测试类:
public class Main {
public static void main(String[] args) {
// 创建真实对象
Animal cat = new Cat();
// 生成代理对象,这个对象实现了Animal接口,并且实现了Animal接口的所有方法
Animal proxy = (Animal) Proxy.newProxyInstance(
cat.getClass().getClassLoader(),
cat.getClass().getInterfaces(),
new AnimalProxy(cat)
);
// 调用代理对象的方法
proxy.makeSound();
}
}
CGLib代理实现
1:目标类
class TargetClass {
public void doSomething() {
System.out.println("TargetClass: Doing something");
}
}
2:设置回调:通过实现MethodInterceptor接口来创建一个回调对象,并将其设置到Enhancer对象中。MethodInterceptor接口中的intercept()方法用于拦截对目标方法的调用。
// 方法拦截器
class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 在目标方法执行前进行操作
System.out.println("Before method execution");
// 调用目标方法
Object result = proxy.invokeSuper(obj, args);
// 在目标方法执行后进行操作
System.out.println("After method execution");
return result;
}
}
3:调用,创建Enhancer对象:Enhancer是CGLib库中的一个类,它用于生成代理类。创建一个Enhancer对象,并设置目标类为其父类。
public static void main(String[] args) {
// 创建Enhancer对象
Enhancer enhancer = new Enhancer();
// 设置目标类
enhancer.setSuperclass(TargetClass.class);
// 设置回调对象
enhancer.setCallback(new MyMethodInterceptor());
// 创建代理类
TargetClass proxy = (TargetClass) enhancer.create();
// 使用代理类调用目标方法
proxy.doSomething();
}