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


由于静态代理会导致类文件大量增多,所以 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 创建

@CallerSensitivepublic 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 动态代理

@Overridepublic 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);  }}

 

图片

脑图:

https://processon.com/view/link/5ef8915be0b34d4dba5a959d


更多相关文章

  1. 构造方法的参数太多,如何解决?
  2. 面试官:为什么静态方法不能调用非静态方法和变量?
  3. ConcurrentHashMap之size()方法
  4. 为什么不推荐使用finalize方法,来看看对垃圾回收有什么影响吧

随机推荐

  1. 【Android】Android android:launchMode=
  2. Android编程: 调试方法
  3. Android 签名打包(cmd命令行)
  4. Android中的Layout_weight详解
  5. android system setup and building (1)
  6. android 开源框架
  7. 转 Android是什么?
  8. Android Windows
  9. gravity和layout_gravity的区别
  10. Android layout_margin 无效的解决办法