首页 技术 正文
技术 2022年11月20日
0 收藏 648 点赞 2,648 浏览 4053 个字

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

  

  输出内容如下:

Java动态代理学习【Spring AOP基础之一】

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

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

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

  Java动态代理学习【Spring AOP基础之一】

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

/**
* 代理类产生并且测试
*/
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文件

Java动态代理学习【Spring AOP基础之一】

  反编译(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中会有额外添加的一些逻辑,

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:8,985
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,501
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,345
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,128
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,763
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,839