- Spring Aop 应用
常用的场景包括记录日志、异常处理、性能监控、安全控制(例如拦截器)等,总结起来就是,凡是想对当前功能做变更,但是又不想修改源代码的情况下,都可以考虑是否可以用 AOP 实现。
-
总体设计原理
参考 1 -
java 动态代理机制详解
java字节码
-
JdkDynamicAopProxy源码分析
参考2 -
动态代理
在java的动态代理机制中有两个重要的类或者接口,InvocationHandler(Interface)、另一个则是 Proxy(Class)。
InvocationHandler: 每一个动态代理类都必须要实现该接口,并且每个代理类的实例都关联到了一个handler,当最后通过代理对象调用一个方法的时候,这个方法的调用最终会被转发为InvocationHandler的invoke方法
// proxy: 我们所代理的真实对象 method:我们所要调用的真实对象的方法
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
Proxy: 这个类的作用就是用来动态的创建一个代理对象的类,其中用的最多的方法就是newProxyInstance 方法。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
loader: 一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces: 一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
下来会展示一个实例,具体参见 5
Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(), handler);
具体对这个代码做一个解释:该方法调用Proxy.newProxyInstance 方法,传入handler的类加载器、真实目标访问对象的接口、handler。返回的是一个com.sun.proxy.$Proxy0, 这个对象是JVM 在运行时生成的代理对象,该对象实现Subject的接口,但是该对象是一个新的类的实例。反编译(如何获取查看参考4)后类内容如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import test.annotation.aspect.Subject;
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(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 rent() throws {
try {
super.h.invoke(this, m4, (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 hello(String var1) throws {
try {
super.h.invoke(this, m3, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m4 = Class.forName("test.annotation.aspect.Subject").getMethod("rent", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("test.annotation.aspect.Subject").getMethod("hello", new Class[]{Class.forName("java.lang.String")});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看到,该类是Proxy的子类,并且实现Subject接口,并且实现了Subject中的方法。***在调用$Proxy0类的方法时,实际上调用的还是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;
/**
* Prohibits instantiation.
*/
private Proxy() {
}
/**
* Constructs a new {@code Proxy} instance from a subclass
* (typically, a dynamic proxy class) with the specified value
* for its invocation handler.
*
* @param h the invocation handler for this proxy instance
*
* @throws NullPointerException if the given invocation handler, {@code h},
* is {@code null}.
*/
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
![](https://img.haomeiwen.com/i9613667/db2cb3f87ec441af.png)
- JDK动态代理小结
比如现在想为RealSubject这个类创建一个动态代理对象,JDK主要会做以下工作:
1 获取 RealSubject上的所有接口列表;
2 确定要生成的代理类的类名,默认为:com.sun.proxy.$ProxyXXXX ;
3 根据需要实现的接口信息,在代码中动态创建 该Proxy类的字节码;
4 将对应的字节码转换为对应的class 对象;
5 创建InvocationHandler 实例handler,用来处理Proxy所有方法调用;
6 Proxy 的class对象 以创建的handler对象为参数,实例化一个proxy对象
-
cglib 生成动态代理类的机制----通过类继承
具体参见 6 -
Spring Aop 和动态代理的关系
参考7 -
关于Spring Aop拦截器的回调
参考 8
参考:
1 Spring AOP设计原理
2 JdkDynamicAopProxy 源码分析
3 java如何查看jvm中动态代理class类内容
4 JDK动态代理文件$Proxy0.class的生成和查看
5 深入理解Java反射+动态代理
6 Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
7 Spring AOP 和 动态代理技术
8 Spring AOP原理之拦截器调用的实现
网友评论