静态代理与jdk动态代理学习

静态代理以及jdk动态代理

近期接触了一个项目里面用到了动态代理,自己发现对动态代理的理解还不够深入,于是重新对代理进行了学习。
学习自https://blog.csdn.net/luanlouis/article/details/24589193
动态代理的一部分代码引用自某博客,当时未保存博客地址,故无法给出引用。

静态代理

静态代理的使用场景

public interface TicketService {

    //售票
    public void sellTicket();

    //问询
    public void inquire();

    //退票
    public void withdraw();

}

定义一个接口

public class Station implements TicketService {
    @Override
    public void sellTicket() {
        System.out.println("\n\t售票.....\n");
    }

    @Override
    public void inquire() {
        System.out.println("\n\t问询。。。。\n");
    }

    @Override
    public void withdraw() {
        System.out.println("\n\t退票......\n");
    }
}

实现了这个接口

这时如果需要在售票前显示一下金额,直观的解决方式是直接在sellTicket加入一个显示金额的语句

public class Station implements TicketService {
    @Override
    public void sellTicket() {
        System.out.println("\n\t显示金额.....\n");
        System.out.println("\n\t售票.....\n");
    }

    @Override
    public void inquire() {
        System.out.println("\n\t问询。。。。\n");
    }

    @Override
    public void withdraw() {
        System.out.println("\n\t退票......\n");
    }
}

但是这种方式并不合理,因为这个实现类并不是仅仅在此被调用,还会被其他地方使用,直接修改会影响其他程序调用。

静态代理的实现

这时可以使用静态代理方法
方法的核心是生成一个静态代理类,将原对象通过构造方法传递给代理类,代理对象调用代理类的方法实际上是通过原对象调用原方法。
da代理类通过原始类的对象,调用原始类的方法

public class Client {

    private static final Logger LOGGER = LoggerFactory.getLogger(Client.class);

    //静态代理 将原对象 通过构造方法 传入到 代理类中,代理对象调用方法 实际是原对象去调用
    public static void main(String[] args) {

        LOGGER.trace("请求参数:content:{}", "1111");
        StationProxy stationProxy=new StationProxy(new Station());
        stationProxy.sellTicket();
    }
}

新建一个原始类对象,通过构造方法将原始变量赋值给代理类里的Station station属性。代理对象调用代理类中的sellTicket方法。

public class StationProxy implements TicketService {

    private Station station;

    public StationProxy(Station station) {
        this.station = station;
    }

    @Override
    public void sellTicket() {

        // 1.做真正业务前,提示信息
        System.out.println("××××您正在使用车票代售点进行购票,每张票将会收取5元手续费!××××");
        // 2.调用真实业务逻辑
        station.sellTicket();
        // 3.后处理
        System.out.println("××××欢迎您的光临,再见!××××\n");
    }

    @Override
    public void inquire() {
        station.inquire();
    }

    @Override
    public void withdraw() {
        station.withdraw();
    }
}

代理类方法中 通过原始类的对象调用原始类的方法

JDK动态代理

由上面静态代理可知,实现代理是通过代理类中的原始对象调用原始方法实现的。而JDK动态代理时通过InvocationHandler,由反射实现的。
在这里插入图片描述

JDK动态代理的实现

public interface Subject
{
    public void rent();

    public void hello(String str);
}

定义一个接口

public class RealSubject implements Subject {

    @Override
    public void rent()
    {
        System.out.println("I want to rent my house");
    }

    @Override
    public void hello(String str)
    {
        System.out.println("hello: " + str);
    }
}

实现这个接口

public class InvocationHandlerImpl implements InvocationHandler {

    // 这个就是我们要代理的真实对象
    private Object subject;

    //    构造方法,给我们要代理的真实对象赋初值
    public InvocationHandlerImpl(Object subject)
    {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object object, Method method, Object[] args)
            throws Throwable
    {
        //  在代理真实对象前我们可以添加一些自己的操作
        System.out.println("before rent house");

        System.out.println("Method:" + method);

        //    当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(subject, args);

        //  在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("after rent house");

        return null;
    }
}

实现了InvocationHandler接口,并重写invoke方法。

public class ClienDynamic {

    public static void main(String[] args)
    {
        //    我们要代理的真实对象
        Subject realSubject = new RealSubject();

        //    我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
        InvocationHandler handler = new InvocationHandlerImpl(realSubject);

        /*
         * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
         * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
         * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
         * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
         */
        Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
                .getClass().getInterfaces(), handler);

        System.out.println(subject.getClass().getName());
        subject.rent();
        subject.hello("world");
    }
}

测试类
在这里插入图片描述
动态代理的结果

JDK动态代理的原理分析

 Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
                .getClass().getInterfaces(), handler);

        System.out.println(subject.getClass().getName());
        subject.rent();
        subject.hello("world");

上面的代码中通过这种方式创建代理对象,并通过代理对象去调用,注意调用的方法是生成的代理类里对应的方法。

try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});

Proxy.newProxyInstance()方法中有一段这个代码,先是把我们自定义的handler 赋值给了代理类,然后新建了代理类的对象返回。

这一步我目前理解是生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码(.class文件),然后用参数里的classLoader加载这个代理类。

然后通过反编译软件可以看到如下代码(以下代码来自于参考博客里的例子,方法名是不一致的)

import com.foo.proxy.Rechargable;
        import com.foo.proxy.Vehicle;
        import java.lang.reflect.InvocationHandler;
        import java.lang.reflect.Method;
        import java.lang.reflect.Proxy;
        import java.lang.reflect.UndeclaredThrowableException;
/**
 生成的动态代理类的组织模式是继承Proxy类,然后实现需要实现代理的类上的所有接口,而在实现的过程中,则是通过将所有的方法都交给了InvocationHandler来处理
 */
public final class ElectricCarProxy extends Proxy
        implements Rechargable, Vehicle
{
    private static Method m1;
    private static Method m3;
    private static Method m4;
    private static Method m0;
    private static Method m2;

    public ElectricCarProxy(InvocationHandler paramInvocationHandler)
            throws
    {
        super(paramInvocationHandler);
    }

    public final boolean equals(Object paramObject)
            throws
    {
        try
        { // 方法功能实现交给InvocationHandler处理
            return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final void rent()
            throws
    {
        try
        {

            // 方法功能实现交给InvocationHandler处理

            this.h.invoke(this, m3, null);
            return;
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final void hello()
            throws
    {
        try
        {

            // 方法功能实现交给InvocationHandler处理

            this.h.invoke(this, m4, null);
            return;
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final int hashCode()
            throws
    {
        try
        {

            // 方法功能实现交给InvocationHandler处理

            return ((Integer)this.h.invoke(this, m0, null)).intValue();
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    public final String toString()
            throws
    {
        try
        {

            // 方法功能实现交给InvocationHandler处理
            return (String)this.h.invoke(this, m2, null);
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

    static
    {
        try
        {  //为每一个需要方法对象,当调用相应的方法时,分别将方法对象作为参数传递给InvocationHandler处理
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
            m3 = Class.forName("com.foo.proxy.Rechargable").getMethod("recharge", new Class[0]);
            m4 = Class.forName("com.foo.proxy.Vehicle").getMethod("drive", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            return;
        }
        catch (NoSuchMethodException localNoSuchMethodException)
        {
            throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException localClassNotFoundException)
        {
            throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
        }
    }
}

测试类中调用对应的方法,即调用了上面代理类里对应的方法,如:

public final void rent()
            throws
    {
        try
        {

            // 方法功能实现交给InvocationHandler处理

            this.h.invoke(this, m3, null);
            return;
        }
        catch (Error|RuntimeException localError)
        {
            throw localError;
        }
        catch (Throwable localThrowable)
        {
            throw new UndeclaredThrowableException(localThrowable);
        }
    }

this.h 即由Proxy.newProxyInstance()传递进来的InvocationHandler handler = new InvocationHandlerImpl(realSubject); handler对象。
我们可以看到 代理类继承与Proxy类,ElectricCarProxy extends Proxy,handler属性定义于Proxy类中。

public class Proxy implements java.io.Serializable {

    private static final long serialVersionUID = -2222568056686623797L;

    /** parameter types of a proxy class constructor */
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };

    /**
     * a cache of proxy classes
     */
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

    /**
     * the invocation handler for this proxy instance.
     * @serial
     */
    protected InvocationHandler h;

最終this.h.invoke(this, m3, null);其实是调用了InvocationHandlerImpl中的重写的invoke方法。

    @Override
    public Object invoke(Object object, Method method, Object[] args)
            throws Throwable
    {
        //  在代理真实对象前我们可以添加一些自己的操作
        System.out.println("before rent house");

        System.out.println("Method:" + method);

        //    当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        method.invoke(subject, args);

        //  在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("after rent house");

        return null;
    }
}

方法内部再通过反射,执行原始类里的对应的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值