java静态代理和动态代理

一、什么是代理模式

      代理模式指一个对象A通过持有另一个对象B,可以具有对象B同样的行为。简单点说,就是多一个代理对象,替原对象处理一些操作。在一些情况下,一个对象不能或者不想直接访问另一个对象,那么就会通过一个中介对象帮忙访问处理。这个中介对象就是代理对象,这种模式即为代理模式。通过代理模式,我们可以更好的保护原本业务,不被外界代码所侵入,形成防御式编程。
代理模式一般分为三种角色:
      • 抽象(Subject)主题角色:通过接口或者抽象类声明真实主题和代理对象实现的业务方法。也是通过接口或者抽象类,声明真实主题和代理的共同接口方法。
      • 真实(Real Subject)主题角色:实现了抽象主题中的具体业务方法,是最终要引用的对象。
      • 代理(Proxy)主题角色:提供了与真实主题相同的接口,包含了真实主题的引用,它可以访问、控制或者增强真实主题的功能。
代理模式的优点:
      • 降低代码的耦合度,拓展性好;
      • 保护目标对象;
      • 增强目标对象。
代理模式的缺点:
      • 类的数量增加;
      • 增加了代理对象,处理变慢;
      • 系统复杂度增加。
使用代理模式的主要两个目的:保护目标对象,增强目标对象。
      java实现代理有两种方式,静态代理和动态代理。java动态代理的实现方式一般为:JDK动态代理和CGLib动态代理,javasist动态代理。

二、静态代理和动态代理

1、静态代理

      静态代理就是在代码运行前代理类已经存在,一旦创建了,在程序运行期间不允许被修改或者很难被修改。这种代理类是在编译前就创建好了,由我们手动创建,不是编译器自动生成,编译前,接口,代理类,目标对象就确定下来了。一般静态代理中,代理类和目标类都会实现同一个接口或者继承同一父类。
Subject类,定义了超市的行为,送货到家

package com.chenys.proxyTest;
/**
 * @author chenys
 *  抽象主题角色 - 超市的行为
 *  Subject
 */
public interface SuperMarketAction {
    /**
     * 送货操作
     */
    void deliverGoods();
}

RealSubject类,定义Proxy所代表的真实实体。即超市

package com.chenys.proxyTest;
/**
 * @author chenys
 *  Real Subject  - 超市
 */
public class SuperMarket implements SuperMarketAction{
    /**
     * 送货
     */
    @Override
    public void deliverGoods() {
        System.out.println("SuperMarket.deliverGoods()");
    }
}

Proxy代理类,通过保存引用访问实体

package com.chenys.proxyTest;
/**
 * @author chenys
 * Proxy代理类 - 物流公司
 */
public class ExpressCompanyProxy implements SuperMarketAction{
    private SuperMarket superMarket;
    public ExpressCompanyProxy(SuperMarket superMarket) {
        this.superMarket = superMarket;
    }
    /**
     * 代理类执行操作 - 寄快递,相当于超市将物品发给物流公司,由物流公司进行分发到各个人手中。
     */
    @Override
    public void deliverGoods() {
        System.out.println("代理类调用委托类方法之前");
        superMarket.deliverGoods();
        System.out.println("代理类调用委托类方法之后");
    }
}

未使用代理类测试

package com.chenys.proxyTest;
/**
 * 测试类
 */
public class StaticProxyMain {
    
    public static void main(String[] args) {
        SuperMarket superMarket = new SuperMarket();
        superMarket.deliverGoods();
    }
}

测试结果

SuperMarket.deliverGoods()

使用代理类测试

package com.chenys.proxyTest;
/**
 * 测试类
 */
public class StaticProxyMain {
    public static void main(String[] args) {
        SuperMarket superMarket = new SuperMarket();
        ExpressCompanyProxy proxy = new ExpressCompanyProxy(superMarket);
        proxy.deliverGoods();
    }
}

测试结果

代理类调用委托类方法之前
SuperMarket.deliverGoods()
代理类调用委托类方法之后

2、动态代理

      动态代理,在程序运行时,根据指示动态的生成代理类。JAVA的动态代理常用的有JDK动态代理和CGLib动态代理。

2-1、JDK动态代理

      JDK动态代理,主要使用java.lang.reflect包下面的Proxy类和InvocationHandler接口。
Subject类,定义了超市的行为,送货到家

package com.chenys.proxyTest;
/**
 * @author chenys
 *  抽象主题角色 - 超市的行为
 *  Subject
 */
public interface SuperMarketAction {
    /**
     * 送货操作
     */
    void deliverGoods();
}

RealSubject类,定义Proxy所代表的真实实体。即超市

package com.chenys.proxyTest;
/**
 * @author chenys
 *  Real Subject  - 超市
 */
public class SuperMarket implements SuperMarketAction{
    /**
     * 送货
     */
    @Override
    public void deliverGoods() {
        System.out.println("SuperMarket.deliverGoods()");
    }
}

Proxy代理类,动态生成

package com.chenys.jdkproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 动态代理 - 实现InvocationHandler接口
 * Each proxy instance has an associated invocation handler.
 *  * When a method is invoked on a proxy instance, the method
 *  * invocation is encoded and dispatched to the {@code invoke}
 *  * method of its invocation handler.
 *  每个动态代理示例都有这样一个关联接口,当动态代理示例对象执行方法时,会调用InvocationHandler的invoke方法进行增强调用
 */
public class SuperMarketInvocationHandler implements InvocationHandler {
    /**
     * 被代理对象
     */
    private SuperMarketAction superMarket;
    /**
     * 构造函数
     * @param superMarket
     */
    public SuperMarketInvocationHandler(SuperMarketAction superMarket) {
        this.superMarket = superMarket;
    }
    /**
     * 代理对象增强方式
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理类调用委托类方法之前");
        Object result = method.invoke(superMarket, args);
        System.out.println("代理类调用委托类方法之后");
        return result;
    }
    /**
     * 创建代理对象
     * @return
     */
    public Object createProxy() {
       return Proxy.newProxyInstance(superMarket.getClass().getClassLoader(),superMarket.getClass().getInterfaces(),this);
    }
}

执行方法

package com.chenys.jdkproxy;
import java.lang.reflect.Proxy;
/**
 * main方法
 */
public class JdkProxy {
    public static void main(String[] args) {
        // 方式一
        proxy1();
        System.out.println("-------------------------");
        // 方式二
        proxy2();
    }
    public static void proxy1() {
        // 创建要被代理的类
        SuperMarketAction superMarketAction = new SuperMarket();
        // 创建要被代理类的处理方式
        SuperMarketInvocationHandler invocationHandler = new SuperMarketInvocationHandler(superMarketAction);
        // 创建代理对象
        SuperMarketAction proxy = (SuperMarketAction) Proxy.newProxyInstance(superMarketAction.getClass().getClassLoader(), superMarketAction.getClass().getInterfaces(), invocationHandler);
        // 通过代理对象进行调用
        proxy.deliverGoods();
    }
    public static void proxy2() {
        SuperMarketAction superMarketAction = new SuperMarket();
        SuperMarketInvocationHandler invocationHandler = new SuperMarketInvocationHandler(superMarketAction);
        SuperMarketAction proxy = (SuperMarketAction) invocationHandler.createProxy();
        proxy.deliverGoods();
    }
}

执行结果,方式一和方式二结果一样的,都能正确创建出代理对象,并进行调用

代理类调用委托类方法之前
SuperMarket.deliverGoods()
代理类调用委托类方法之后
-------------------------
代理类调用委托类方法之前
SuperMarket.deliverGoods()
代理类调用委托类方法之后

我们来看看java.lang.reflect.InvocationHandler接口的invoke方法

/**
* proxy: 方法被调用的代理对象实例
* method: 被调用的方法对象
* args: 被调用的方法参数
**/
public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

再来看看java.lang.reflect.Proxy的newProxyInstance方法

/**
* loader :被代理对象的类加载器
* interfaces :被代理对象的接口列表
* h :代理类调用方法时处理方式
**/
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

我们来看看上面例子生成的代理类,再上述main方法中,新增一行代码,可以生成com/sun/proxy文件夹,里面会有$Proxy0.class,这个就是jdk动态生成的代理类了

 public static void main(String[] args) {
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        // 方式一
        proxy1();
        System.out.println("-------------------------");
        // 方式二
        proxy2();
    }

$Proxy0.class的内容如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.chenys.jdkproxy.SuperMarketAction;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements SuperMarketAction {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m0;
    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }
    /**
    * 调用h.invoke方法,增强equals()方法
    **/
    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
    /**
    * 调用h.invoke方法,增强deliverGoods()方法
    **/
    public final void deliverGoods() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    /**
    * 调用h.invoke方法,增强toString()方法
    **/
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
   /**
    * 调用h.invoke方法,增强hashCode()方法
    **/
    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    /**
    * 通过反射,获取代理类的接口方法
    *
    **/
    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("com.chenys.jdkproxy.SuperMarketAction").getMethod("deliverGoods");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
2-2、CGLib动态代理

Subject类,定义了超市的行为,送货到家

package com.chenys.proxyTest;
/**
 * @author chenys
 *  抽象主题角色 - 超市的行为
 *  Subject
 */
public interface SuperMarketAction {
    /**
     * 送货操作
     */
    void deliverGoods();
}

RealSubject类,定义Proxy所代表的真实实体。即超市

package com.chenys.proxyTest;
/**
 * @author chenys
 *  Real Subject  - 超市
 */
public class SuperMarket implements SuperMarketAction{
    /**
     * 送货
     */
    @Override
    public void deliverGoods() {
        System.out.println("SuperMarket.deliverGoods()");
    }
}

Proxy代理类,动态生成

package com.chenys.cglibproxy;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
 * 代理类处理方法
 */
public class MethodHandler implements MethodInterceptor {
    public MethodHandler() {
    }
    /**
     * @param obj         被代理的对象(需要增强的对象)
     * @param method      被拦截的方法(需要增强的方法)
     * @param args        方法入参
     * @param methodProxy 用于调用原始方法
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理类调用委托类方法之前");
        Object result = methodProxy.invokeSuper(obj, args);
        System.out.println("代理类调用委托类方法之后");
        return result;
    }
}

调用

package com.chenys.cglibproxy;
import org.springframework.cglib.proxy.Enhancer;
/**
 * cglib调用
 */
public class CGLibProxy {
    public static void main(String[] args) {
        // 声明cglib代理增强器对象
        Enhancer enhancer = new Enhancer();
        // 设置被代理的超类
        enhancer.setSuperclass(SuperMarket.class);
        // 设置代理方法的增强方法拦截器
        enhancer.setCallback(new MethodHandler());
        // 创建代理对象
        SuperMarket superMarket = (SuperMarket) enhancer.create();
        // 调用方法
        superMarket.deliverGoods();
    }
}

运行结果:

代理类调用委托类方法之前
SuperMarket.deliverGoods()
代理类调用委托类方法之后

通过cgliib生成的动态代理如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.chenys.cglibproxy;
import java.lang.reflect.Method;
import org.springframework.cglib.core.ReflectUtils;
import org.springframework.cglib.core.Signature;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class SuperMarket$$EnhancerByCGLIB$$cef7fc40 extends SuperMarket implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$deliverGoods$0$Method;
    private static final MethodProxy CGLIB$deliverGoods$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;
    private static final Method CGLIB$equals$1$Method;
    private static final MethodProxy CGLIB$equals$1$Proxy;
    private static final Method CGLIB$toString$2$Method;
    private static final MethodProxy CGLIB$toString$2$Proxy;
    private static final Method CGLIB$hashCode$3$Method;
    private static final MethodProxy CGLIB$hashCode$3$Proxy;
    private static final Method CGLIB$clone$4$Method;
    private static final MethodProxy CGLIB$clone$4$Proxy;
    public SuperMarket$$EnhancerByCGLIB$$cef7fc40() {
        CGLIB$BIND_CALLBACKS(this);
    }
    static {
        CGLIB$STATICHOOK1();
    }
    public final boolean equals(Object var1) {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        if (var10000 != null) {
            Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);
            return var2 == null ? false : (Boolean)var2;
        } else {
            return super.equals(var1);
        }
    }
    public final String toString() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        return var10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();
    }
    public final int hashCode() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        if (var10000 != null) {
            Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);
            return var1 == null ? 0 : ((Number)var1).intValue();
        } else {
            return super.hashCode();
        }
    }
    protected final Object clone() throws CloneNotSupportedException {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        return var10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();
    }
    public Object newInstance(Callback var1) {
        CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});
        SuperMarket$$EnhancerByCGLIB$$cef7fc40 var10000 = new SuperMarket$$EnhancerByCGLIB$$cef7fc40();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }
    public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {
        CGLIB$SET_THREAD_CALLBACKS(var3);
        SuperMarket$$EnhancerByCGLIB$$cef7fc40 var10000 = new SuperMarket$$EnhancerByCGLIB$$cef7fc40;
        switch(var1.length) {
        case 0:
            var10000.<init>();
            CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
            return var10000;
        default:
            throw new IllegalArgumentException("Constructor not found");
        }
    }
    public Object newInstance(Callback[] var1) {
        CGLIB$SET_THREAD_CALLBACKS(var1);
        SuperMarket$$EnhancerByCGLIB$$cef7fc40 var10000 = new SuperMarket$$EnhancerByCGLIB$$cef7fc40();
        CGLIB$SET_THREAD_CALLBACKS((Callback[])null);
        return var10000;
    }
    public Callback getCallback(int var1) {
        CGLIB$BIND_CALLBACKS(this);
        MethodInterceptor var10000;
        switch(var1) {
        case 0:
            var10000 = this.CGLIB$CALLBACK_0;
            break;
        default:
            var10000 = null;
        }
        return var10000;
    }
    public Callback[] getCallbacks() {
        CGLIB$BIND_CALLBACKS(this);
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }
    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {
        CGLIB$STATIC_CALLBACKS = var0;
    }
    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {
        CGLIB$THREAD_CALLBACKS.set(var0);
    }
    public void setCallback(int var1, Callback var2) {
        switch(var1) {
        case 0:
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var2;
        default:
        }
    }
    public final void deliverGoods() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (var10000 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }
        if (var10000 != null) {
            var10000.intercept(this, CGLIB$deliverGoods$0$Method, CGLIB$emptyArgs, CGLIB$deliverGoods$0$Proxy);
        } else {
            super.deliverGoods();
        }
    }
    public void setCallbacks(Callback[] var1) {
        this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
    }
    public static MethodProxy CGLIB$findMethodProxy(Signature var0) {
        String var10000 = var0.toString();
        switch(var10000.hashCode()) {
        case -2002897756:
            if (var10000.equals("deliverGoods()V")) {
                return CGLIB$deliverGoods$0$Proxy;
            }
            break;
        case -508378822:
            if (var10000.equals("clone()Ljava/lang/Object;")) {
                return CGLIB$clone$4$Proxy;
            }
            break;
        case 1826985398:
            if (var10000.equals("equals(Ljava/lang/Object;)Z")) {
                return CGLIB$equals$1$Proxy;
            }
            break;
        case 1913648695:
            if (var10000.equals("toString()Ljava/lang/String;")) {
                return CGLIB$toString$2$Proxy;
            }
            break;
        case 1984935277:
            if (var10000.equals("hashCode()I")) {
                return CGLIB$hashCode$3$Proxy;
            }
        }
        return null;
    }
    final void CGLIB$deliverGoods$0() {
        super.deliverGoods();
    }
    private static final void CGLIB$BIND_CALLBACKS(Object var0) {
        SuperMarket$$EnhancerByCGLIB$$cef7fc40 var1 = (SuperMarket$$EnhancerByCGLIB$$cef7fc40)var0;
        if (!var1.CGLIB$BOUND) {
            var1.CGLIB$BOUND = true;
            Object var10000 = CGLIB$THREAD_CALLBACKS.get();
            if (var10000 == null) {
                var10000 = CGLIB$STATIC_CALLBACKS;
                if (var10000 == null) {
                    return;
                }
            }
            var1.CGLIB$CALLBACK_0 = (MethodInterceptor)((Callback[])var10000)[0];
        }
    }
    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        Class var0 = Class.forName("com.chenys.cglibproxy.SuperMarket$$EnhancerByCGLIB$$cef7fc40");
        Class var1;
        Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals", "(Ljava/lang/Object;)Z", "toString", "()Ljava/lang/String;", "hashCode", "()I", "clone", "()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());
        CGLIB$equals$1$Method = var10000[0];
        CGLIB$equals$1$Proxy = MethodProxy.create(var1, var0, "(Ljava/lang/Object;)Z", "equals", "CGLIB$equals$1");
        CGLIB$toString$2$Method = var10000[1];
        CGLIB$toString$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "toString", "CGLIB$toString$2");
        CGLIB$hashCode$3$Method = var10000[2];
        CGLIB$hashCode$3$Proxy = MethodProxy.create(var1, var0, "()I", "hashCode", "CGLIB$hashCode$3");
        CGLIB$clone$4$Method = var10000[3];
        CGLIB$clone$4$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/Object;", "clone", "CGLIB$clone$4");
        CGLIB$deliverGoods$0$Method = ReflectUtils.findMethods(new String[]{"deliverGoods", "()V"}, (var1 = Class.forName("com.chenys.cglibproxy.SuperMarket")).getDeclaredMethods())[0];
        CGLIB$deliverGoods$0$Proxy = MethodProxy.create(var1, var0, "()V", "deliverGoods", "CGLIB$deliverGoods$0");
    }
    final Object CGLIB$clone$4() throws CloneNotSupportedException {
        return super.clone();
    }
    final int CGLIB$hashCode$3() {
        return super.hashCode();
    }
    final boolean CGLIB$equals$1(Object var1) {
        return super.equals(var1);
    }
    final String CGLIB$toString$2() {
        return super.toString();
    }
}

也就是生成子类,然后通过子类继承原有类进行增强调用。

2-3、JDK动态代理和CGLib动态代理的不同

      JDK动态代理只能对实现了接口的类生成代理,而不能针对类无接口的类,动态的生成代理对象,该代理对象继承Proxty,实现被代理对象的接口。
      CGLib是针对类实现代理,对被代理类继承生成一个子类,覆盖其中的方法,使用ASM在内存中动态的生成被代理类的子类,即使代理类没有实现任何接口也可以实现动态代理功能。

三、反射

      JDK动态代理生成的代理类里,就使用到了反射。反射就是把Java类映射成一个个的Java对象,在运行状态中,对于任意一个类,就能知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性。这种动态获取信息及动态调用对象方法的功能叫Java的反射机制。
      Java中主要由以下的类来实现Java反射机制(这些类都位于java.lang.reflect包中):
• Class类:代表一个类。 Field类:代表类的成员变量(成员变量也称为类的属性)。
• Method类:代表类的方法。
• Constructor类:代表类的构造方法。
• Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
举个例子

package com.chenys.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class JavaReflect {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class cls = Class.forName(SuperMarket.class.getName());
        // 获取定义的所有字段。getFields()为获取定义的public字段
        Field[] declaredFields = cls.getDeclaredFields();
        StringBuffer fieldBuffer = new StringBuffer();
        for (Field field : declaredFields) {
            fieldBuffer.append(field.getName()).append(", ");
        }
        System.out.println("SuperMarket的字段为:" + fieldBuffer.toString());
        // 获取所有的method
        Method[] declaredMethods = cls.getDeclaredMethods();
        StringBuffer methodBuffer = new StringBuffer();
        for (Method method : declaredMethods) {
            methodBuffer.append(method.getName()).append(", ");
        }
        System.out.println("SuperMarket的方法为:" + methodBuffer.toString());
        // 无参构造函数
        Constructor constructor = cls.getConstructor();
        SuperMarket superMarket = (SuperMarket) constructor.newInstance();
        superMarket.setName("张三的超市");
        System.out.println(superMarket.getName());
        superMarket.deliverGoods();
        System.out.println("-------------");
        // 有参构造函数
        Constructor constructor1 = cls.getConstructor(java.lang.Long.class,java.lang.String.class,java.lang.String.class);
        SuperMarket superMarket1 = (SuperMarket) constructor1.newInstance(10L, "李四的超市","广东省");
        System.out.println(superMarket1.getName());
        superMarket1.deliverGoods();
        System.out.println("------------");
        //通过反射调用方法
        //获得和属性对应的getXXX()方法
        Method setNameMethod = cls.getMethod("setName",java.lang.String.class);
        // 非共有方法,需要设置可访问权限
        // setNameMethod.setAccessible(true);
        setNameMethod.invoke(superMarket,"王五的超市");
        Method getNameMethod = cls.getMethod("getName");
        String name = (String) getNameMethod.invoke(superMarket,null);
        System.out.println(name);
        Method deliverGoodsMethod = cls.getMethod("deliverGoods",null);
        deliverGoodsMethod.invoke(superMarket);
    }
}

运行结果如下:

SuperMarket的字段为:id, name, location, 
SuperMarket的方法为:getName, getLocation, getId, setName, setId, setLocation, deliverGoods, 
张三的超市
SuperMarket.deliverGoods()
-------------
李四的超市
SuperMarket.deliverGoods()
------------
王五的超市
SuperMarket.deliverGoods()

四、使用

1、springMVC中,也是使用了代理方式,通过DispatcherServlet.class的doDispatch方法可知,在做完一系列工作后,包括Multipart检查,mappedHandler查找对应适配器,以及各种Resolver解析器后,就会进行调用invoke,去调用我们声明的@RequestMapping的方法。

 protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        this.checkRequest(request);
        ModelAndView mav;
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized(mutex) {
                    mav = this.invokeHandlerMethod(request, response, handlerMethod);
                }
            } else {
                mav = this.invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            mav = this.invokeHandlerMethod(request, response, handlerMethod);
        }
        if (!response.containsHeader("Cache-Control")) {
            if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            } else {
                this.prepareResponse(response);
            }
        }
        return mav;
    }

2、mybatis mapper也是使用了动态代理,mapper中只声明了接口,没有实现类,调用 JDBC 等操作都是在 Mybatis InvocationHandler 实现的。
3、aop
4、日志
5、rpc

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值