Spring代理(Proxy)

一、简介

    代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。

    更通俗的说,代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可,而且代理的出现还可以让我们完成与另一个类之间的关系的统一管理,但是切记,代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。

    使用场景:如果需要委托类处理某一业务,那么我们就可以先在代理类中统一处理然后在调用具体实现类。

    按照代理的创建时期,代理类可以分为两种: 静态代理和动态代理。

二、静态代理

    由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。

 

    举个例子:给业务代码添加日志功能。

/*
    用户业务接口
*/
public interface UserService {
    public void add();
    public void update();
    public void delete();
    public void select();
}
/*
    用户业务实现类:关注纯粹的业务逻辑
*/
public class UserServiceImpl implements UserService {
 
    @Override
    public void add() {
        System.out.println("增加用户");
    }
 
    @Override
    public void update() {
        System.out.println("修改用户");
    }
 
    @Override
    public void delete() {
        System.out.println("删除用户");
    }
 
    @Override
    public void select() {
        System.out.println("查询用户");
    }
}
/*
    用户业务代理类:用于处理公共的业务 如日志
*/
public class UserServiceProxy implements UserService {
 
    private UserService userService=new UserServiceImpl();
 
    @Override
    public void add() {
        log("add");
        userService.add();
    }
 
    @Override
    public void update() {
        log("update");
        userService.update();
    }
 
    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }
 
    @Override
    public void select() {
        log("select");
        userService.delete();
    }
 
    public void log(String methodName) {
        System.out.println("执行" + methodName + "执行");
    }
 
}

使用静态代理的好处:

      (1)使得真实角色处理的业务更加的纯粹,不再去关注一些公共的事情。

      (2)公共的业务由代理来完成---实现了业务的分工。

      (3)公共业务发生扩展时,变得更加集中和方便。

静态代理的缺点:

      (1)类变的多了---多了代理类,工作量变大了,开发效率降低了。

三、动态代理

    代理类在程序运行时创建的方式被成为动态代理。也就是说,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的"指示"动态生成的。相比于静态代理,动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

(1)基于接口的动态代理:jdk动态代理

java.lang.reflect.Proxy:Java动态代理机制的主类,提供了一组静态方法来为一组接口动态地生成代理类及其实例。

//方法1: 该方法用于获取指定动态代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy)
 
//方法2:该方法用于获取关联于指定类装载器和一组接口的动态代理对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces)
 
//方法3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl)
 
/*
 方法4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理对象。
    loader:定义代理类的类加载器
    interfaces:代理类要实现的接口列表
    h:指派方法调用的调用处理程序
*/
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

 

java.lang.reflect.InvocationHandler:调用处理器接口,它自定义了一个invoke方法,用于集中处理在动态代理对象上的方法调用,通常在该方法中实现对委托类的代理访问。每次生成动态代理对象时都需要指定一个实现了该接口的调用处理器对象。

public interface InvocationHandler {
    /*
    proxy:在其上调用方法的代理实例
    method:对应于在代理实例上调用的接口方法的 Method 实例。
        Method 对象的声明类将是在其中声明方法的接口,
        该接口可以是代理类赖以继承方法的代理接口的超接口。
    args:包含传入代理实例上方法调用的参数值的对象数组,
        如果接口方法不使用参数,则为 null。基本类型的参数被包装在适当基本包装器类
        (如 java.lang.Integer 或 java.lang.Boolean)的实例中。
    Object:从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,
        则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。
        如果此方法返回的值为 null 并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出
        NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,
        则代理实例上的方法调用将抛出 ClassCastException。
    */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

java.lang.ClassLoader:类装载器,负责将类的字节码装载到Java虚拟机(JVM)中并为其定义类对象,然后该类才能被使用。Proxy静态方法生成代理类同样需要通过类装载器来进行装载才能使用,它与普通类的唯一区别就是其字节码是由JVM在运行时动态生成的而非预存在于任何一个.class文件中。每次生成动态代理对象时都需要指定一个类装载器对象。

举个例子:

/*
    用户业务接口
*/
public interface UserService{
	
	void add();

}
/*
    用户接口实现类
*/
public class UserServiceImpl implements UserService{

	@Override
	public void add() {
		System.out.println("用户实现类的add方法");
	}

}
/*
    动态代理实现
*/
public class ProxyInvocationHandler implements InvocationHandler {
	// 目标对象--真实对象
	private Object target;
    // 指定目标对象
	public void setTarget(Object target) {
		this.target = target;
	}

	/**
	 * 生成代理类:
	 */
	public Object getProxy() {
		return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}

	/**
	 * proxy:是代理类 method:代理类的实例(proxy)调用的处理程序(add)的方法对象
     * args 接口参数
	 * 比如调用proxy.add():此处method.getName就是add
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		log(method.getName());
		Object result = method.invoke(target, args);
		return result;
	}

	public void log(String methodName) {
		System.out.println("执行" + methodName + "方法");
	}

}
/*
    客户端测试
*/
public class Client {
    public static void main(String[] args) {
        UserService userService=new UserServiceImpl();
        ProxyInvocationHandler pih=new ProxyInvocationHandler();
        //指定真是对象
        pih.setTarget(userService);
        UserService proxy=(UserService)pih.getProxy();
        proxy.add();
    }
}

(2)基于类的动态代理:cglib

    CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。CGLIB是一个强大的高性能的代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供方法的interception(拦截)。CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也是使用ASM来生成java的字节码。当然不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。


实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口。

public interface MethodInterceptor extends Callback{
    /*
        obj表示增强的对象,即实现这个接口类的一个对象;
        method表示要被拦截的方法;
        args表示要被拦截方法的参数;
        proxy表示要触发父类的方法对象;
    */
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                               MethodProxy proxy) throws Throwable;
 
}

    Enhancer是cglib中使用频率很高的一个类,它是一个字节码增强器,可以用来为无接口的类创建代理。它的功能与java自带的Proxy类挺相似的。它会根据某个给定的类创建子类,并且所有非final的方法都带有回调钩子。

// 设置enhancer对象的父类
public void setSuperclass(Class superclass) {
		if (superclass != null && superclass.isInterface()) {
			setInterfaces(new Class[]{superclass});
		}
		else if (superclass != null && superclass.equals(Object.class)) {
			// affects choice of ClassLoader
			this.superclass = null;
		}
		else {
			this.superclass = superclass;
			// SPRING PATCH BEGIN
			setContextClass(superclass);
			// SPRING PATCH END
		}
	}
// 设置enhancer的回调对象
public void setCallback(final Callback callback) {
		setCallbacks(new Callback[]{callback});
	}

public void setCallbacks(Callback[] callbacks) {
		if (callbacks != null && callbacks.length == 0) {
			throw new IllegalArgumentException("Array cannot be empty");
		}
		this.callbacks = callbacks;
	}
/* 创建代理对象
    该方法含义就是如果有必要就创建一个新类,并且用指定的回调对象创建一个新的对象实例,
    使用的父类的参数的构造方法来实例化父类的部分。核心内容在createHelper()中,
*/
public Object create() {
		classOnly = false;
		argumentTypes = null;
		return createHelper();
	}
private Object createHelper() {
        // 方法校验callbackTypes、filter是否为空,以及为空时的处理。
		preValidate();
		Object key = KEY_FACTORY.newInstance((superclass != null) ? superclass.getName() : null,
				ReflectUtils.getNames(interfaces),
				filter == ALL_ZERO ? null : new WeakCacheKey<CallbackFilter>(filter),
				callbackTypes,
				useFactory,
				interceptDuringConstruction,
				serialVersionUID);
		this.currentKey = key;
        /*作为Enhancer父类AbstractClassGenerator.create()方法
            创建代理对象的参数。*/
		Object result = super.create(key);
		return result;
	}

 

protected Object create(Object key) {
		try {
			ClassLoader loader = getClassLoader();
			Map<ClassLoader, ClassLoaderData> cache = CACHE;
			ClassLoaderData data = cache.get(loader);
			if (data == null) {
				synchronized (AbstractClassGenerator.class) {
					cache = CACHE;
					data = cache.get(loader);
					if (data == null) {
						Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache);
						data = new ClassLoaderData(loader);
						newCache.put(loader, data);
						CACHE = newCache;
					}
				}
			}
			this.key = key;
			Object obj = data.get(this, getUseCache());
			if (obj instanceof Class) {
				return firstInstance((Class) obj);
			}
            // 真正创建代理对象方法在nextInstance()方法中
			return nextInstance(obj);
		}
		catch (RuntimeException | Error ex) {
			throw ex;
		}
		catch (Exception ex) {
			throw new CodeGenerationException(ex);
		}
	}
// 该方法是一个抽象方法,由子类Enhancer实现
abstract protected Object nextInstance(Object instance) throws Exception;
protected Object nextInstance(Object instance) {
		EnhancerFactoryData data = (EnhancerFactoryData) instance;

		if (classOnly) {
			return data.generatedClass;
		}

		Class[] argumentTypes = this.argumentTypes;
		Object[] arguments = this.arguments;
		if (argumentTypes == null) {
			argumentTypes = Constants.EMPTY_CLASS_ARRAY;
			arguments = null;
		}
        /*
        argumentTypes:为代理对象的构成器类型
        arguments:为代理对象构造方法参数
        callbacks:为对应回调对象。
        */
		return data.newInstance(argumentTypes, arguments, callbacks);
	}
// 最后根据这些参数,通过反射生成代理对象
public Object newInstance(Class[] argumentTypes, Object[] arguments, Callback[] callbacks) {
			setThreadCallbacks(callbacks);
			try {
				// Explicit reference equality is added here just in case Arrays.equals does not have one
				if (primaryConstructorArgTypes == argumentTypes ||
						Arrays.equals(primaryConstructorArgTypes, argumentTypes)) {
					// If we have relevant Constructor instance at hand, just call it
					// This skips "get constructors" machinery
					return ReflectUtils.newInstance(primaryConstructor, arguments);
				}
				// Take a slow path if observing unexpected argument types
				return ReflectUtils.newInstance(generatedClass, argumentTypes, arguments);
			}
			finally {
				// clear thread callbacks to allow them to be gc'd
				setThreadCallbacks(null);
			}

		}

举个例子:

/*
    用户业务类
*/
public class UserService {
	
	public UserService() {
		System.out.println("UserService构造器");
	}

	/**
	 * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
        cglib主要是通过继承覆盖实现的
	 */
	final public String sel(String name) {
		System.out.println("UserService的sel方法" + name);
		return null;
	}

	public void add() {
		System.out.println("UserService:add");
	}
}
/*    
    自定义方法拦截器类
*/
public class MyMethodInterceptor implements MethodInterceptor{
	 
    /**
     * sub:cglib生成的代理对象
     * method:被代理对象方法
     * objects:方法入参
     * methodProxy: 代理方法
     */
    @Override
    public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("======插入前置通知======");
        Object object = methodProxy.invokeSuper(sub, objects);
        System.out.println("======插入后者通知======");
        return object;
    }

}
/*
    客户端测试
*/
public class Client {
	public static void main(String[] args) {
        // 代理类class文件存入本地磁盘方便我们反编译查看源码
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        // 设置enhancer对象的父类
        enhancer.setSuperclass(UserService.class);
        // 设置enhancer的回调对象
        enhancer.setCallback(new MyMethodInterceptor());
        // 创建代理对象
        UserService proxy= (UserService)enhancer.create();
        // 通过代理对象调用目标方法
        proxy.add();
    }
}

生成的代理对象 

如果本文对您有很大的帮助,还请点赞关注一下。

 


版权声明:本文为qq_40298351原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。