博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java动态代理学习【Spring AOP基础之一】
阅读量:6326 次
发布时间:2019-06-22

本文共 5060 字,大约阅读时间需要 16 分钟。

 

  Spring AOP使用的其中一个底层技术就是Java的动态代理技术。Java的动态代理技术主要围绕两个类进行的 

  java.lang.reflect.InvocationHandler
  java.lang.reflect.Proxy

  首先从代码层面说明Java动态代理是如何实现的,

  业务逻辑接口:

  

/** * 创建一个人的接口,其中有一个吃的方法 */public interface Person {    public void eat();}

  创建一个实现该业务接口的类:

/** * 人接口的实现,实现吃饭的方法 */public class PersonImpl implements Person {    @Override    public void eat() {        System.out.println("吃主食、吃菜、喝汤...");    }}

  此时,如果正常情况如果想要调用Person这个接口,直接new它的实现类然后调用eat方法即可,但是如果想要实现一个Person的代理,并且在eat方法前后进行一些工作就需要使用Proxy和InvovationHandler;

  InvocationHandler接口的实现类,(代理类中额外逻辑的实现就需要在这里进行)

/** * 代理类的额外逻辑实现类 */public class InvocationHandlerImpl implements InvocationHandler {    Person person;    public InvocationHandlerImpl(Person person) {        this.person = person;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        if(method.getName().equalsIgnoreCase("eat")) {            System.out.println("洗手...");            method.invoke(person, args);            System.out.println("刷牙");        }        return person;    }}

  

  接下来就是使用Proxy生成代理类,Proxy需要业务逻辑接口,代理类额外实现逻辑InvocationHandler实现类

/** * 代理类产生并且测试 */public class ProxyGenerate {    @Test    public void proxyTest() {        Person person = new PersonImpl();        InvocationHandler invocationHandler = new InvocationHandlerImpl(person);        Person personProxy = (Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, invocationHandler);        personProxy.eat();    }    }

  

  输出内容如下:

  代理类已经成功的完成代理。

 

  AOP的功能就是在一个方法前、后、异常抛出等地方添加逻辑,与上面的过程是一样的,所以这个技术就被用来实现Spring AOP的一个技术,但是这个只针对接口实现,如果想要给一个类添加AOP的逻辑,这个Proxy动态代理的技术暂时无法适用,Spring AOP适用了CGLIB,支持类的动态代理,但是不属于这一次的讨论范畴。

  知道怎么用了之后是不是对Proxy这个感觉很神奇,想知道是如何实现的呢,可以深入了解一下newProxyInstance这个方法:

  

 

   找到上述内容,可以看到这个是动态生成代理类字节数组的方法,所以我们可以通过这个方法了解到动态生成的代理类的结构:

/** * 代理类产生并且测试 */public class ProxyGenerate {    @Test    public void proxyWatch() {        byte[] classByte = ProxyGenerator.generateProxyClass("PersonDynamicProxy", new Class[]{Person.class});        try {            FileOutputStream var1 = new FileOutputStream("PersonDynamicProxy" + ".class");            var1.write(classByte);            var1.close();        } catch (IOException var2) {            throw new InternalError("I/O exception saving generated file: " + var2);        }    }}

  执行上述代码会生成动态代理对象的.class文件

  反编译(jd-gui,idea)之后就可以看到动态代理类的结构:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//import com.smart.beanfactory.Person;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.lang.reflect.UndeclaredThrowableException;public final class PersonDynamicProxy extends Proxy implements Person {    private static Method m1;    private static Method m3;    private static Method m0;    private static Method m2;    public PersonDynamicProxy(InvocationHandler var1) throws  {        super(var1);    }    public final boolean equals(Object var1) throws  {        try {            return ((Boolean)super.h.invoke(this, m1, new Object[]{var1})).booleanValue();        } catch (RuntimeException | Error var3) {            throw var3;        } catch (Throwable var4) {            throw new UndeclaredThrowableException(var4);        }    }    public final void eat() throws  {        try {            super.h.invoke(this, m3, (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)).intValue();        } 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);        }    }    static {        try {            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});            m3 = Class.forName("com.smart.beanfactory.Person").getMethod("eat", 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]);        } catch (NoSuchMethodException var2) {            throw new NoSuchMethodError(var2.getMessage());        } catch (ClassNotFoundException var3) {            throw new NoClassDefFoundError(var3.getMessage());        }    }}

  可以看出来,动态代理类首先通过反射的技术,将源接口中的方法均设置为其静态属性(Method),然后针对每个方法进行重写。

  重写的逻辑是使用invocationHandler接口的invoke方法实现,每个invoke方法在绑定相应的反射出来的静态属性即可。

  举例,比如上面Person接口的eat被反射未m3的静态属性中,重写eat()方法是调用方法为invoke(this, m3, args),其中invoke中会有额外添加的一些逻辑,

 

转载地址:http://skwoa.baihongyu.com/

你可能感兴趣的文章
PO,VO,BO,DTO,POJO(POCO),DAO的区别(转载)
查看>>
linq中join的用法
查看>>
【CRC校验】学习笔记
查看>>
bzoj千题计划153:bzoj2431: [HAOI2009]逆序对数列
查看>>
bzoj千题计划323:bzoj1951: [Sdoi2010]古代猪文(Lucas+CRT+欧拉定理)
查看>>
Linux基础入门
查看>>
Jenkins performance插件生成性能测试报告【待完成】
查看>>
Maven学习总结
查看>>
补第二阶段冲刺站立会议5(原6月7日)
查看>>
Cookie application session
查看>>
MVC最佳实践
查看>>
【集成学习】sklearn中xgboot模块中fit函数参数详解(fit model for train data)
查看>>
【剑指offer】顺时针打印矩阵,C++实现
查看>>
【pandas】pandas.to_datatime()---时间格式转换
查看>>
LINUX 硬链接与软链接的区别
查看>>
Etcd和ZooKeeper,究竟谁在watch的功能表现更好?
查看>>
这个可以用于字库描边曲线处理,比bez简单多了
查看>>
Bzoj 2726 SDOI 任务安排
查看>>
PHP整理--MySQL--DOS命令操作数据库
查看>>
生成随机码
查看>>