码迷,mamicode.com
首页 > 编程语言 > 详细

Spring AOP的基石--Java动态代理

时间:2018-04-07 18:52:52      阅读:190      评论:0      收藏:0      [点我收藏+]

标签:declare   设置代理   声明   面向接口   接口编程   equals   技术分享   sed   ace   

一、代理模式简介以及静态代理动态代理区别

 1. 关系图

技术分享图片

 

可以看出有一接口Sourceable,两个实现类Source,Proxy,Client调用的Proxy。理解一下就是Client通过Proxy来调用这个method,而不是直接通过Source来调用。

这就像我们的电脑开代理的时候,通过代理上网,而不是直连网络。

从这张类图中也可以看出实现代理模式的两个要点:

  ① 代理类和被代理类必须要实现同一接口 (看下面代码好理解,就是为了面向接口编程)

  ② 代理类的核心是做功能的增强,真正的method还是被代理类提供

public class ProxyDemo {
    public static void main(String args[]){
        RealSubject subject = new RealSubject();
        Proxy p = new Proxy(subject);
        p.request();
    }
}

interface Subject{
    void request();
}

class RealSubject implements Subject{
    public void request(){
        System.out.println("request");
    }
}

// 面向接口在这里有体现,subject
class Proxy implements Subject{ private Subject subject; public Proxy(Subject subject){ this.subject = subject; } public void request(){ System.out.println("PreProcess"); subject.request(); System.out.println("PostProcess"); } }

2. 动态代理和静态代理区别

  • 静态代理:代理类是在编译时就实现好的。也就是说 Java 编译完成后代理类是一个实际的 class 文件。
  • 动态代理:代理类是在运行时生成的。也就是说 Java 编译完之后并没有实际的 class 文件,而是在运行时动态生成字节码,并加载到JVM中。

动态代理生成代理类类名以及字节码过程:

技术分享图片
            /*
             * Choose a name for the proxy class to generate.
             */
            long num = nextUniqueNumber.getAndIncrement();
            String proxyName = proxyPkg + proxyClassNamePrefix + num;

            /*
             * Generate the specified proxy class.
             */
            byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                proxyName, interfaces, accessFlags);
            try {
                return defineClass0(loader, proxyName,
                                    proxyClassFile, 0, proxyClassFile.length);
            } catch (ClassFormatError e) {
                /*
                 * A ClassFormatError here means that (barring bugs in the
                 * proxy class generation code) there was some other
                 * invalid aspect of the arguments supplied to the proxy
                 * class creation (such as virtual machine limitations
                 * exceeded).
                 */
                throw new IllegalArgumentException(e.toString());
            }
View Code

二、动态代理的实现以及实现原理

1. 声明共同接口

public interface Subject {
    void dating();
    void sing();
}

2. 设置被代理类,也叫委托类

技术分享图片
public class WeiTuoLei implements Subject{
    @Override
    public void dating() {
        System.out.println("Time0");
    }

    @Override
    public void sing() {
        System.out.println("Sing a Song");
    }
}

class WeiTuoLei1 implements Subject{

    @Override
    public void dating() {
        System.out.println("Time1");
    }

    @Override
    public void sing() {
        System.out.println("Dance");
    }
}
View Code

3. 设置代理类的调用处理器(需实现InvocationHandler接口)

技术分享图片
class ProxyHandler implements InvocationHandler{
    // 真正被代理的对象也叫做委托对象
    Subject subject;
    public ProxyHandler(Subject subject){
        this.subject = subject;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        dosomethingbefore();
        Object invoke = method.invoke(subject, args);
        dosomethingafter();
        return invoke;
    }

    private void dosomethingbefore() {
        System.out.println("==========before=======");
    }

    private void dosomethingafter() {
        System.out.println("==========after=======");
    }
}
View Code

4. 测试

public class Main {
    public static void main(String[] args) {
        WeiTuoLei realSubject = new WeiTuoLei();  //1.创建委托对象
        ProxyHandler handler = new ProxyHandler(realSubject); //2.创建调用处理器对象
        //3.动态生成代理对象
        Subject o = (Subject)Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler);
     //JDK内部就是通过这个方法生成的代理对象,我把它拿出来,咱们就可以看到动态生成了一个什么样的代理对象。 ProxyUtils.generateClassFile(WeiTuoLei.
class,o.getClass().getName()); /** * Proxy.newProxyInstance等于如下动作 * //1. 根据类加载器和接口创建代理类 Class clazz = Proxy.getProxyClass(loader, interfaces); //2. 获得代理类的带参数的构造函数 Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class }); //3. 创建代理对象,并制定调用处理器实例为参数传入 Interface Proxy = (Interface)constructor.newInstance(new Object[] {handler}); */ //4.通过代理对象调用方法 o.sing(); } }

我的ProxyUtils(可以通过这个工具类看到动态生成的代理对象,其实就是把字节码保存了一下)

技术分享图片
public class ProxyUtils {

    public static void generateClassFile(Class clazz, String proxyName) {
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                clazz.getName(), new Class[]{clazz});

        String path = clazz.getResource(".").getPath() + proxyName + ".class";
        File file = new File(path);
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(path);

        FileOutputStream out = null;

        try {
            out = new FileOutputStream(path);
            out.write(proxyClassFile);
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
View Code

好,接下来我们来解剖一下它生成的这个代理类(字节码文件),用反编译工具看一下具体内容。

技术分享图片
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class WeiTuoLei extends Proxy implements WeiTuoLei {
    private static Method m1;
    private static Method m3;
    private static Method m9;
    private static Method m2;
    private static Method m4;
    private static Method m7;
    private static Method m6;
    private static Method m8;
    private static Method m10;
    private static Method m0;
    private static Method m5;

    public WeiTuoLei(InvocationHandler var1) throws  {
        super(var1);
    }

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

    public final void dating() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void notify() throws  {
        try {
            super.h.invoke(this, m9, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

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

    public final void sing() throws  {
        try {
            super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void wait(long var1) throws InterruptedException {
        try {
            super.h.invoke(this, m7, new Object[]{var1});
        } catch (RuntimeException | InterruptedException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }

    public final void wait(long var1, int var3) throws InterruptedException {
        try {
            super.h.invoke(this, m6, new Object[]{var1, var3});
        } catch (RuntimeException | InterruptedException | Error var5) {
            throw var5;
        } catch (Throwable var6) {
            throw new UndeclaredThrowableException(var6);
        }
    }

    public final Class getClass() throws  {
        try {
            return (Class)super.h.invoke(this, m8, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void notifyAll() throws  {
        try {
            super.h.invoke(this, m10, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

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

    public final void wait() throws InterruptedException {
        try {
            super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | InterruptedException | 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("DealDynamicProxy.WeiTuoLei").getMethod("dating");
            m9 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("notify");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("sing");
            m7 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("wait", Long.TYPE);
            m6 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("wait", Long.TYPE, Integer.TYPE);
            m8 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("getClass");
            m10 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("notifyAll");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m5 = Class.forName("DealDynamicProxy.WeiTuoLei").getMethod("wait");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
View Code

看着代码很多,实际上就是把一个类里的各个方法通过反射拿了出来,我这里看不到代理类的两个方法,因为我没法传参,但是大致思想就是这样。

Spring AOP的基石--Java动态代理

标签:declare   设置代理   声明   面向接口   接口编程   equals   技术分享   sed   ace   

原文地址:https://www.cnblogs.com/NoYone/p/8733868.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!