理解设计模式之代理模式

  |   0 评论   |   0 浏览

代理模式 Proxy Pattern

  什么是代理模式?首先理解代理这个词,从概念上讲有代理人与被代理人之分,代理人替被代理人办事。那么从程序的角度上讲,就是代理类,对真实的类,进行逻辑功能增强。之前讲过装饰模式,装饰模式也是对一个类进行增强,那么装饰模式和代理模式到底有什么不同?首先,两者的业务出发点不同,装饰模式主要是理解被装饰对象方法的业务逻辑,并对其进行扩展增强,而代理模式并不关心你这个对象内部方法的业务逻辑是什么,而只关心你调用了什么方法,对你调用的方法进行拦截控制,进行额外的业务处理。其次两者的实现方式不一样,装饰模式实现难度小,代理模式实现难度大,不过目前已经有很多开源的工具供我们使用,我们只需要实现具体的代理逻辑即可。

代理模式的实现

  代理模式的实现我看网上资料分为静态代理和动态代理,说实话,我觉得静态代理不太合理,实现方式跟装饰模式没有太大不同,有些人说构造函数中直接分配代理对象,就是静态代理,我觉得这种方式有点牵强。首先违背开闭原则,代理类还要实现与被代理类的接口?这相当于跟业务进行了绑定,业务接口改变,代理类会跟着改变,这既不符合开闭原则,又与代理模式的设计理念相违背,代理根本不关心你这个类有多少个方法,我只关心你调用了何种方法,除非你新增的方法跟代理业务有关,否则根本不用管,但是静态代理就打破了这种模式,所以我觉得静态代理不合理。
  我觉得动态代理才是代理模式的精髓,有第三方工具来辅助动态代理的实现,首先是Java的标准实现:
1、接口定义

public interface Subject {
	public String getName();

	public void setName(String name);

	public int getAge();

	public void setAge(int age);
}

2、接口的实现对象

public class RealSubject implements Subject{
	private String name;

	private int age;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

3、代理拦截器实现

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxy implements InvocationHandler {

	private Object subject;

	public DynamicProxy(Object subject) {
		this.subject = subject;
	}

	@Override
	public Object invoke(Object object, Method method, Object[] args) throws Throwable {
		String methodName = method.getName();
		System.out.println("调用的方法:" + methodName);
		if ("setName".equals(methodName)) {
			args[0] = args[0] + "-Proxy";
		}
		Object obj = method.invoke(subject, args);
		return obj;
	}

}

4、测试类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class DynamicProxyTest {
	public static void main(String[] args) {
		RealSubject person = new RealSubject();
		InvocationHandler handler = new DynamicProxy(person);
		Subject proxy = (Subject) Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), handler);
		System.out.println(proxy.getClass());
		proxy.setName("michael");
		System.out.println(proxy.getName());
	}
}

  从上面可以看出,具体的代理拦截器中,代理了具体对象的方法执行,对其进行拦截处理,这是不是跟我们常见的一个词很相似?这个词就是AOP,面向切面的编程,没错,就是这个玩意。面向切面的编程就是根据方法拦截器来实现的,当然有其他第三方工具包来辅助,例如cglib。下面是基于cglib的方式来实现动态代理:
1、方法拦截器

import java.lang.reflect.Method;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class CglibMethodInterceptor implements MethodInterceptor {

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		String methodName = method.getName();
		System.out.println("before method " + methodName);
		Object result = proxy.invokeSuper(obj, args);
		System.out.println("after method " + methodName);
		return result;
	}

}

2、测试类

import org.springframework.cglib.proxy.Enhancer;

public class CglibTest {
	public static void main(String[] args) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(RealSubject.class);
		enhancer.setCallback(new CglibMethodInterceptor());
		RealSubject obj = (RealSubject) enhancer.create();
		System.out.println(obj.getClass());
		obj.setName("michael");
		System.out.println(obj.getName());
	}
}

  这里可以看到,基于cglib的方式要比java原生的方便很多,spring的AOP就是基于这种方式来实现的。


标题:理解设计模式之代理模式
作者:michael
地址:https://blog.junxworks.cn/articles/2018/10/07/1538883680651.html