代理模式在开源代码中的应用

代理模式的作用是为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。

由于静态代理会导致类文件大量增多,所以 Java 中动态代理使用的较多。

案例一

JDK 中的动态代理的使用,实现 InvocationHandler 接口,只能代理接口的实现类

package com.xiongjun.proxy.dynamicproxy;

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

/**
 * JDK 自带动态代理
 * 
 * @author ConstXiong
 */
public class JdkDynamicProxy implements InvocationHandler {

	private Object target;
	
	public JdkDynamicProxy(Object target) {
		this.target = target;
	}

	@SuppressWarnings("unchecked")
	public <T> T getProxy() {
		return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),
				target.getClass().getInterfaces(), this);
	}

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result = null;
		long t1 = System.currentTimeMillis();
		result = method.invoke(target, args);//目标类的方法调用,与结果获取
		System.out.println("login cost time : " + (System.currentTimeMillis() - t1));
		return result;
	}

}

客户端代码:

JdkDynamicProxy proxy = new JdkDynamicProxy(new ServiceImpl());
Service jdkService = proxy.getProxy();
jdkService.login("", "");

InvocationHandler 接口的源码,是被代理实例的处理程序实现,代理实例的方法调用会被关联到 invoke 方法

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}

代理实例通过 Proxy 类的静态工厂方法 newProxyInstance 创建

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    Objects.requireNonNull(h);
    final Class<?>[] intfs = interfaces.clone();//复制接口的Class对象数组
    //校验权限
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }
    //调用本地方法根据类加载器和Class对象数组,获取被代理对象的Class的对象
    Class<?> cl = getProxyClass0(loader, intfs);
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        //获取构造方法对象
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {//非public修改可见权限
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        return cons.newInstance(new Object[]{h});//创建被代理对象实例
    } catch (IllegalAccessException|InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

案例二

使用 cglib 类库完成动态代理,不要求被代理类必须实现接口

package com.xiongjun.proxy.dynamicproxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * 使用 cglib 类库完成动态代理 
 * 
 * @author ConstXiong
 */
public class CglibProxy implements MethodInterceptor {

	private CglibProxy() {
	}
	
	//单例模式获取代理类对象
	private static CglibProxy proxy = new CglibProxy();
	
	public static CglibProxy getInstance() {
		return proxy;
	}
	
	
	/**
	 * 获取被代理后的目标类
	 * @param clazz 目标类
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getProxy(Class<T> clazz) {
		return (T) Enhancer.create(clazz, this);
	}
	
	/**
	 * 代理执行目标类方法
	 */
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		Object result = null;
		long t1 = System.currentTimeMillis();
		result = proxy.invokeSuper(obj, args);//目标类的方法调用,与结果获取
		System.out.println("login cost time : " + (System.currentTimeMillis() - t1));
		
		return result;
	}
 
}

客户端代码:

Service cglibService = CglibProxy.getInstance().getProxy(ServiceImpl.class);
cglibService.login("", "");

Cglib 借助 Enhancer 创建被代理对象实例,Enhancer 底层是借助 ASM 工具生成字节码,实例化对象的。

/**
 * Helper method to create an intercepted object.
 * For finer control over the generated instance, use a new instance of <code>Enhancer</code>
 * instead of this static method.
 * @param type class to extend or interface to implement
 * @param callback the callback to use for all methods
 */
public static Object create(Class type, Callback callback) {
    Enhancer e = new Enhancer();
    e.setSuperclass(type);
    e.setCallback(callback);
    return e.create();
}

案例三

使用 Spring aop 中的 ProxyFactory 完成环绕代理

import java.util.Random;
 
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
 
/**
 * 使用 spring aop 完成环绕代理
 * @author ConstXiong
 */
public class ServiceAroundAdvice implements MethodInterceptor {
	
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Object result = null;
		long start = System.currentTimeMillis();//计时开始
		result = invocation.proceed();//目标类的方法调用,与结果获取
		long end = System.currentTimeMillis();//计时结束
		System.out.println("耗时:" + (end - start) + "毫秒");//打印耗时
		return result;
	}
	
}

客户端代码:

ProxyFactory proxyFactory = new ProxyFactory(); //创建代理工厂类
proxyFactory.setTarget(new ServiceImpl()); //设置被代理类
proxyFactory.addAdvice(new ServiceAroundAdvice()); //添加增强器
Service service = (Service) proxyFactory.getProxy(); //获取代理类
service.login("ConstXiong", "123456");

Spring aop 创建代理对象实例的源码逻辑在这里,可以看出它根据情况使用了 JDK 动态代理和 Cglib 动态代理

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
		Class<?> targetClass = config.getTargetClass();
		if (targetClass == null) {
			throw new AopConfigException("TargetSource cannot determine target class: " +
					"Either an interface or a target is required for proxy creation.");
		}
		if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
			return new JdkDynamicAopProxy(config);
		}
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

【Java学习资源】整理推荐


【Java面试题与答案】整理推荐

猜你喜欢

转载自blog.csdn.net/meism5/article/details/107477264