一、概述
AOP编程,简称面向切面的编程,是spring框架的一个重要特征,也是日常编程中常用的编程方式,本次冲着对spring打破砂锅问到底的心里,决心弄懂工作中经常出现的一些编程方式和知识点,以前都是在这字面上大大擦边球,希望通过这次学习的机会,把相应的笔记写下来,能够更深一层的了解这些原理,背后的逻辑。在这里介绍AOP的相关概念之前,我们先介绍一种AOP中非常重要的技术:JDK的动态代理技术,AOP编程原理也是使用动态代理技术来实现的,因此我们先了解一下JDK的动态代理技术的原理。
二、JDK动态代理技术
首先看一下基本概念,当然这些概念笔者也是参考网上的大牛的写文章,代理是一种常用的设计模式,目的就是为其他对象提供一个代理以控制某个对象的访问,消息的处理等。JDK中也提供了相应代理技术,位于java.lang.reflect包下面,这里能了解动态代理技术之前,需要先了解java的反射技术。
2.1 java的反射技术
java的类是通过被虚拟机加载到内存这当中,才能运行,一般是通过类加载器来加载,而类加载器通常分为3种。一般的流程如下,java源程序文件.java经过java编译器编译之后被转换成java的字节码文件.class文件,通过类加载器加载到内存当中,并实例化成对象,然后才能使用。java的类加载器分为3类:bootstrap class loader (启动类加载器),extensions class loader (扩展类加载器),system class loader (系统类加载器)当然你也可以通过继承ClassLoader类的方式来实现自己的类加载器,同时具体的方式请大家参考网上的博文,说的非常详细。一般java虚拟机启动的时候就会加载很多的字节码文件,这个时候可以直接使用这些类,是因为都事先被类加载器加载到内存当中,然而很多的类并不需要事先被加载,而只需要程序运行的时候才加载,这个时候就需要用到java的反射技术。java的反射技术的特点就是在编译期并没有这个类,并不知道这个类是啥类,直到运行的时候才清楚。举个例子来说,两个程序员同时写代码,A在写程序需要用到B所写的类,此时B并没有完成编写,那么A的代码是不能通过编译的,而通过反射机制,就可以很好的解决这个问题。
在java的反射API中有几个非常重要的类:
Class: java中所有的类型都对应一个Class对象,不论一个类产生了多少个对象,但是他们的Class始终只有一个,该Class中包含了该类的所有信息(属性、方法、包等)
该对象不能通过new的方式来获得,但是可以通过以下三种方式来获得
1. new 一个对象之后,然后通过getClass()方法
Person p = new Person();
Class clazz = p.getClass();
2. 通过Class.forName()的方式获得
Class.forName("com.org.Person");
3. 直接通过类的.class
Class clazz = Person.class;
Class对象包含了这个类的所有信息,包括构造函数,方法等,具体的使用方法,接下来往下看。
Field: 代表类中的属性,可以获得其属性,并且修改相应的值,通过Class提供的方法,可以获得方法的所有参数,返回值、作用域、属性等
Field[] fields = clazz.getFields();
for(Field field:fields){
System.out.println(field.getName()+"-"+field.getType());
}
以上的方法只能获取到共有权限的属性,如果想要获取私有的属性的话,还需要打开对应的权限检查开关
Field[] fds=clazz.getDeclaredFields(); //这个方式可以获取到private属性
for(Field f:fds){
System.out.println(f.getName()+"-"+f.getType());
f.setAccessible(true); //..打开开关之后才能进行相应的设置值
}
Method: 代表类中方法,通过反射类可以获取这个类的所有方法,同时,调用Method的invoke()方法可以执行该方法,这也是动态代理经常调用的方法,同样也可以获得方法的所有属性
Class<?> clazz= Class.forName("com.jdk.proxy.ConstructorDemo");
Method[] methods = clazz.getMethods();
methods[0].invoke();
Constructor:类的构造函数,java的反射包中提供了多种方法来回去构造函数,通过构造函数可以直接构造该,通过newInstance()方法来构造实例,这里可以传一些参数类型
Class<?> clazz= Class.forName("com.jdk.proxy.ConstructorDemo");
//获取默认的构造函数
Constructor const1 = clazz.getConstructor(new Class[]{});
const1.newInstance();
基本上如果使用反射来获取一个类以及其属性,均要用到上面几个一些概念和方法。相对于直接使用一个类,反射使用起来会比较复杂,但是具有非常大的灵活性,被很多的框架中使用。以上就是java反射的一些基本的知识。本文主要讲解的是Spring AOP的概念,而Spring AOP中首先要用到的就是JDK的动态代理技术,而动态代理技术中,需要用到java反射机制,这里先补充一下基本知识。
2.2 JDK的动态代理技术
介绍完了java的反射技术之后,下面就可以去学习JDK的动态代理技术了,在这里我们首先看一个例子。
1. 首先定义一个接口FomService和接口的实现类FormServcieImpl(因为jdk的动态代理技术必须要实现接口,后面会说这个问题),这个接口提供了两个方法,根据topic和formId分别进行删除操作,具体的代码如下:
public interface FormService {
public abstract void remove(int topic);
public abstract void removeForm(int formid);
}
下面看它的实现类
public class FormServiceImpl implements FormService{
@Override
public void remove(int topic) {
System.out.println("remove form by topic:"+topic);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void removeForm(int formid) {
System.out.println("remove form by from Id "+formid);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
这里,如果我们要去调用这个方法,同时输出结果,我们看下具体的操作:
FormService formService = new FormServiceImpl();
formService.remove(1);
formService.remove(100);
而输出的结果为:
remove form by topic:1
remove form by topic:100
这个结果符合我们的期望,一般也是如此使用,如果现在有个要求,在执行remove的方法之前,需要增加两项功能,1. 打印日志,2.做权限验证,此时方法就变成如下:
public class FormServiceImpl implements FormService{
@Override
public void remove(int topic) {
System.out.println(" 增加权限认证....");
System.out.println("remove form by topic:"+topic);
System.out.println("打印日志....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void removeForm(int formid) {
System.out.println(" 增加权限认证....");
System.out.println("remove form by from Id "+formid);
System.out.println("打印日志....");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
此时如果采用new的方式来实例化对象,那么所有的方法中都必须增加这么两项1.权限校验,2.打印日志,随着业务越来越膨胀,方法越来越多,添加的逻辑越来越多,整个方法变的越来臃肿,代码越来越复杂,其实验证权限和打印日志属于公共模块,采用一个类来解决即可?那么问题来了,这么去在调用方法前后去调用这两个公用模块呢?,此时就要用到java的动态代理技术。
先来看个例子
FormService obj = new FormServiceImpl();
PerformanceHandler handler = new PerformanceHandler(obj);
FormService proxy = (FormService) Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
proxy.remove(1);
System.out.println("---------method--------------");
proxy.removeForm(100);
查看输出的结果:
增加权限认证....
remove form by topic:1
打印日志....
---------method--------------
增加权限认证....
remove form by from Id 100
打印日志....
很奇怪,原来的方法里面什么都没有加,但是此时两个方法中都在执行之前先进行了权限认证,和之后进行了日志打印操作,这其中到底发生了什么呢?
其实就是把采用了jdk的动态代理技术,把公共模块抽取了出来,下面先看增加的一个类PerformanceHandler,具体代码如下:
public class PerformanceHandler implements InvocationHandler{
Object obj;
public PerformanceHandler(Object obj){
this.obj=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" 增加权限认证....");
Object o = method.invoke(obj,args);
System.out.println("打印日志....");
return o;
}
}
这个类也是非常的简单,只有一个方法invoke,可以看到这个方法中添加了两个功能,就是权限认证和日志打印,这其中到底发生了什么呢?能提供一个这样一个方法,然后改成上面的那种写法,就让两个方法都实现了同样的功能....
下面我们来分析一下,首先看到本次操作增加了PerformanceHandler类,并且实现了一个接口Invocationhandler接口,这个接口查看jdk的源码发现只有一个方法:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
其中第一个参数代表代理对象,二哥参数代是调用的方法,第三个参数是调用的参数的方法参数,这就可以看出来,在调用这个方法之前,加上需要处理的逻辑,比如权限认证,或者日志打印,都会被执行,因此不管哪儿个方法来调用这个方法,都会被执行的。那么这个invoke方法啥时候被调用呢?源码中的注释说明,在代理对象上调用方法时候,关联在这个代理对象的上的invokeHandler对象会调用自己的invoke方法,这个在后面的源码中也能看到。
接下来,我们看下对FormService这个类如何实例化的,可以看到上面的方法中有个非常重要的类Proxy,这是jdk反射包中提供个代理类,提供了一个静态的newProxyInstance(...)方法如下:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)throws IllegalArgumentException
这个方法需要传入3个参数,第一个参数是Classloader ,这个是定义这个代理类的Classloader,一般传入的classloader 是创建接口的class loader,保证生产的代理类能够转换成接口被我们使用,第二个是interface,需要代理类实现的接口,这就是为啥一定要先写个接口了,因为这个方法需要传入接口作为参数,第三个参数是InvocationHandler,这就是后来增加的实现类,具体实现看下文。这里通过代理类,返回了一个实体类,然后执行这个实体类,即可触发对应的方法,同时织入我们的handler方法编写的逻辑。
小结: 这里通过java的反射机制,利用代理的方式,得到了一个FormService的代理类,在执行对应的remove方法的时候会自动触发handler的invoke方法,那么此时,卸载该方法的中的一些逻辑就会被执行,包括权限认证和日志打印,因此整个程序中只需在handler中写一个这样的逻辑,所有的方法都可以调用他,这就是AOP的概念了。
--------分割线--------------
Java的动态代理技术使用起来很简单,就是简单的Proxy类InvocationHandler接口,然后实例化一个代理类即可,那么究竟Proxy.newInstance()方法是如何获取一个代理类,同时调用对应的方法的呢?下面我们来阅读以下 jdk的这部分源码,感兴趣的同学可以继续往下阅读,不感兴趣的,可以忽略这部分内容....
首先看下Proxy.newInstance()方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)throws IllegalArgumentException
{
Objects.requireNonNull(h); //判断是否为空
final Class<?>[] intfs = interfaces.clone(); //拷贝参数传进来的接口
final SecurityManager sm = System.getSecurityManager(); //一些安全权限检查
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
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}); //返回实例化对象
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
上面这个方法还是比较简单的,其中主要的流程如下
1. 生成代理类的Proxy的Class对象,这是整个方法中最核心的地方
Class<?> cl = getProxyClass0(loader, intfs);
2. 获取相应的构造函数,如果该函数的作用域为私有域,则通过setAccessible方法来支持访问
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;
}
});
}
这里就是前面用到的反射技术,通过获取到的Class对象,来得到对应的构造方法,和作用域等。
3. 获取Proxy Class的构造函数,创建Proxy的代理实例,整个过程就此结束
cons.newInstance(new Object[]{h});
以上三步中,可以看出最核心的地方就是生成Class对象,这里我们看一下该方法:
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
return proxyClassCache.get(loader, interfaces);
}
这个方法相对比较简单,就是做了一个判断,接口的数量不能超过65535,然后调用了proxyClassCache.get方法,这个proxyClassCached这里主要用作缓存的,下面看下他的get方法
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
下面我们来详解说明一下这个方法
首先,这个方法咋一看,挺负责的,很多变量,一看就花眼了,那么我们反过来看,看这个方法的返回值,return value,这个value也是个泛型,通过如下方法得到:
V value = supplier.get();
而这个supplier的类型是一个接口,并且只有一个方法get:
public interface Supplier<T> {
T get();
}
而得到这个supplier则是通过一个map来获取的,而此时用到一个key subKey,接下来看看这个subKey是啥时候put进去呢?
Supplier<V> supplier = valuesMap.get(subKey);
这就清晰了,要想获得supplier,就需要从根据subKey从valueMap中获取对应的值:
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
其实这个supplier也是一个factory,实现了supplier接口,内部报错了下面重点分析一下subKeyFactory.apply(key,paramter)这个方法,其实这个subKeyFactory也是个工厂类,这里我们看下apply方法
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
可以看到这个方法接收了两个参数,一个是classloader,第二个是接口,首先便利了所有接口,同时通过Class.forName(),去得到这些接口的Class对象,接着验证Class对象是不是接口,如下代码:
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
如果不是,则抛出异常,接着验证接口是否重复,
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
接下来验证你的接口中是否有非public的接口,只要有一个接口是非public,那么些这些接口都必须在同一个包中,如果验证通过,所有接口都是public,那么生成的代理类的包名为默认的com.sun.proxy,接下面做一些基本的处理,比如生成的类名,第一个生成的类名$Proxy0.class,在接下来,得到一个非常重要的方法ProxyGenerator.generateProxyCLass(...)来生成字节码文件。
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
在接下来,返回生成的对象,下面我们来看下这个生成字节码的方法,该方法返回了一个byte[]字节数组,那么这个数组里面到底是啥,待会在细节看一下
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile(); //这里是动态生成字代理类的字节码
if(saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if(var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar), new String[0]);
Files.createDirectories(var3, new FileAttribute[0]);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class", new String[0]);
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
可以看到上面的参数,saveGeneratedFiles=true,来把字节码写入到磁盘当中,生成.calss文件,那么这个属性是如何得到的呢,
private static final boolean saveGeneratedFiles = ((Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"))).booleanValue();
这个getBooleanAction实际上是调用Boolean.getBoolean(this.theProp) 方法来获得的,实际上,我们可以通过设置com.misc.ProxyGnerator.saveGeneratedFiles这个系统属性为true来进行保存,当然不止这一种方法了,也可以通过获取得到byte[]数组,然后通过文件的fileoutStream来写入到磁盘中。
Boolean.valueOf(Boolean.getBoolean(this.theProp)
接下来,通过下面一段代码,把获得到的代理类写入到磁盘上:
byte[] clazzByte= ProxyGenerator.generateProxyClass("FormService",new Class[]{FormService.class});
try {
FileOutputStream out = new FileOutputStream(new File("/tmp/FormService.class"));
out.write(clazzByte);
out.flush();;
System.out.println("finished@");
} catch (Exception e) {
e.printStackTrace();
}
下面通过反编译工具JD-GUI来反编译一下源码,
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class FormService
extends Proxy
implements com.jdk.proxy.FormService
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
private static Method m4;
public FormService(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
{
try
{
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 String toString()
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void remove(int paramInt)
{
try
{
this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void removeForm(int paramInt)
{
try
{
this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.jdk.proxy.FormService").getMethod("remove", new Class[] { Integer.TYPE });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m4 = Class.forName("com.jdk.proxy.FormService").getMethod("removeForm", new Class[] { Integer.TYPE });
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
这个类中有几个要注意的地方,首先生成的这个类名是实现了FormService接口,同时继承了Proxy这个类
public final class FormService extends Proxy implements com.jdk.proxy.FormService
同时它有5个变量
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
private static Method m4;
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.alibaba.jdk.proxy.FormService").getMethod("remove", new Class[] { Integer.TYPE });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m4 = Class.forName("com.alibaba.jdk.proxy.FormService").getMethod("removeForm", new Class[] { Integer.TYPE });
return;
}
可以看到这个5方法中,有3个方式Object的方法,这里重新实现了equals,toString和hashCode这个几个方法,还有两个方法分别是接口中的方法remove和removeForm这两个方法。接下来看下这两个方法
public final void remove(int paramInt)
{
try
{
this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
这里代理类实现了接口中的方法,可以看到出来调用这个方法的时候,有是h.invoke()方法执行的,那么这个h是啥呢?
public FormService(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
看下该类的构造函数,给了一个参数Invocationhandler,然调用了父类的构造函数
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
那么很明显这个this.h其实就是我们自定义的InvocationHandler,在回过头来看下Performancehandler这个类,其中只有个invoke方法,那么调用这个方法我们看下参数
this.h.invoke(this, m3, new Object[] { Integer.valueOf(paramInt) });
m3 = Class.forName("com.alibaba.jdk.proxy.FormService").getMethod("remove", new Class[] { Integer.TYPE });
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" 增加权限认证....");
Object o = method.invoke(obj,args);
System.out.println("打印日志....");
return o;
}
这很清楚了,先调用了权限认证,然后在调用了method.invode(),最后调用了打印日志这个方法,最后返回结果,整个流程到这里就结束了,这下就很清楚了,这个invoke方法的执行流程。
三、总结
1. 代理类基础了Proxy,实现了代理的接口,由于java不能多继承,这里已经继承了Proxy类,不能在继承其他类,所以jdk的动态代理不支持对已实现类的代理,只能支持接口的代理
3. 生成静态方法Method,已经重新覆盖了toString,hashcode和equals方法
jdk动态代理是AOP编程的基础,同时也是各大框架中使用非常频繁的技术,本次在学习的过程中做一个小结,下一篇,将详细介绍一下spring AOP的编程实现原理...