Spring框架里核心是IOC和AOP。其作用就是“简化开发”。
AOP面向切面编程,其核心就是“解耦”。
Spring中哪些地方使用了AOP?
1.日志管理
2.事务管理
3.权限认证
4.Lazy Loading懒加载
5.Context Process上下文处理
6.Error Handler 错误跟踪(异常捕获机制)
7.缓存处理
为了理解AOP,先来了解很重要的设计模式:代理模式;
代理模式目前有jdk动态代理,cglib动态代理。
代理模式的必要条件
简单来说,满足以下三个条件即可:
1.执行者和被代理人;
2.对于被代理人来说,这件事情一定要做,但是被代理人不想自己去做,需要请人代做
3.需要获取被代理人的个人信息
在日常生活中哪些场景使用了代理模式?
媒婆,租房中介,黄牛,经纪人
带着解决问题的三部曲来窥探动态代理
1.是什么
2.为什么
3.怎么做
下面以相亲(媒婆,小明)为例,写代码之前先来简单分析一下:
1.执行者和被代理人——>媒婆和小明
2.对于被代理人来说,这件事情一定要做,但是被代理人不想自己去做,需要请人代做——>小明需要找女朋友,但苦于没有资源,于是找媒婆牵线搭桥
3.需要获取被代理人的个人信息——>小明,男,28岁
jdk动态代理
首先我们定义了一个Person类型的接口,为其声明一个方法
package test.fn.proxy.eg3;
public interface Person {
//寻找真爱
void findLove();
}
接着,定义了一个类来实现这个接口,这个类就是我们的真实对象,XiaoMing类:
package test.fn.proxy.eg3;
public class XiaoMing implements Person{
@Override
public void findLove() {
System.out.println("寻找白富美!!!");
}
}
下一步,我们就要定义一个动态代理类了,每一个动态代理类都必须要实现 InvocationHandler 这个接口,因此我们这个动态代理类也不例外
package test.fn.proxy.eg3;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Meipo implements InvocationHandler{
//需要代理的真实对象
private Person target;
//我们要代理哪个真实对象,就将该对象传进去
public Object getInstance(Person target){
this.target = target;
Class clazz = target.getClass();
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 clazz.getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数clazz.getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数this, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("我是媒婆");
System.out.println("开始海选...");
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(this.target, args);
//在代理真实对象后我们也可以添加一些自己的操作
System.out.println("结束海选...");
return null;
}
}
最后,来看看我们的Client类:
package test.fn.proxy.eg3;
public class Test {
public static void main(String[] args) {
Person person = (Person) new Meipo().getInstance(new XiaoMing());
System.out.println("代理对象:" + person.getClass().getName());
person.findLove();
}
}
我们先来看看控制台的输出:
代理对象:com.sun.proxy.$Proxy0
我是媒婆
开始海选...
寻找白富美!!!
结束海选...
到这里,jdk动态代理的代码完成了,有没有疑惑,Meipo类的invoke方法如何被调用?在控制台里可以看出代理对象是重新生成的$Proxy0
类,$
表示JVM内存生成,Proxy表示代理类,数字0表示第一个,生成从0开始算起。具体还是想了解$Proxy0
类究竟是个什么,那先生成$Proxy0.class
字节码:
package test.fn.proxy.eg3;
import java.io.FileOutputStream;
import java.io.IOException;
import sun.misc.ProxyGenerator;
public class Test {
public static void main(String[] args) throws IOException {
Person person = (Person) new Meipo().getInstance(new XiaoMing());
System.out.println("代理对象:" + person.getClass().getName());
person.findLove();
/*原理:
1.拿到被代理对象的引用,然后获取它的接口
2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
3.把被代理对象的引用也拿到了
4.重新动态生成一个class字节码
5.然后编译*/
//获取字节码
byte[] data = ProxyGenerator.generateProxyClass("$Porxy0", new Class[]{person.getClass()});
FileOutputStream os = new FileOutputStream("F:/fn/$Porxy0.class");
os.write(data);
os.close();
}
}
接下来我们去看看生成的$Proxy0.class
文件。使用Java Decompiler反编译后内容如下:
import com.sun.proxy..Proxy0;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Porxy0
extends Proxy
implements .Proxy0
{
private static Method m9;
private static Method m7;
private static Method m4;
private static Method m10;
private static Method m13;
private static Method m8;
private static Method m3;
private static Method m2;
private static Method m1;
private static Method m6;
private static Method m11;
private static Method m5;
private static Method m0;
private static Method m12;
public $Porxy0(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
public final void wait(long paramLong)
throws InterruptedException
{
try
{
this.h.invoke(this, m9, new Object[] { Long.valueOf(paramLong) });
return;
}
catch (Error|RuntimeException|InterruptedException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final Object newProxyInstance(ClassLoader paramClassLoader, Class[] paramArrayOfClass, InvocationHandler paramInvocationHandler)
throws IllegalArgumentException
{
try
{
return (Object)this.h.invoke(this, m7, new Object[] { paramClassLoader, paramArrayOfClass, paramInvocationHandler });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final boolean isProxyClass(Class paramClass)
{
try
{
return ((Boolean)this.h.invoke(this, m4, new Object[] { paramClass })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void wait()
throws InterruptedException
{
try
{
this.h.invoke(this, m10, null);
return;
}
catch (Error|RuntimeException|InterruptedException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void notifyAll()
{
try
{
this.h.invoke(this, m13, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void wait(long paramLong, int paramInt)
throws InterruptedException
{
try
{
this.h.invoke(this, m8, new Object[] { Long.valueOf(paramLong), Integer.valueOf(paramInt) });
return;
}
catch (Error|RuntimeException|InterruptedException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void findLove()
{
try
{
this.h.invoke(this, m3, null);
return;
}
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 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 Class getProxyClass(ClassLoader paramClassLoader, Class[] paramArrayOfClass)
throws IllegalArgumentException
{
try
{
return (Class)this.h.invoke(this, m6, new Object[] { paramClassLoader, paramArrayOfClass });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final Class getClass()
{
try
{
return (Class)this.h.invoke(this, m11, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final InvocationHandler getInvocationHandler(Object paramObject)
throws IllegalArgumentException
{
try
{
return (InvocationHandler)this.h.invoke(this, m5, new Object[] { paramObject });
}
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 notify()
{
try
{
this.h.invoke(this, m12, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m9 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", new Class[] { Long.TYPE });
m7 = Class.forName("com.sun.proxy.$Proxy0").getMethod("newProxyInstance", new Class[] { Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;"), Class.forName("java.lang.reflect.InvocationHandler") });
m4 = Class.forName("com.sun.proxy.$Proxy0").getMethod("isProxyClass", new Class[] { Class.forName("java.lang.Class") });
m10 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", new Class[0]);
m13 = Class.forName("com.sun.proxy.$Proxy0").getMethod("notifyAll", new Class[0]);
m8 = Class.forName("com.sun.proxy.$Proxy0").getMethod("wait", new Class[] { Long.TYPE, Integer.TYPE });
m3 = Class.forName("com.sun.proxy.$Proxy0").getMethod("findLove", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m6 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getProxyClass", new Class[] { Class.forName("java.lang.ClassLoader"), Class.forName("[Ljava.lang.Class;") });
m11 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getClass", new Class[0]);
m5 = Class.forName("com.sun.proxy.$Proxy0").getMethod("getInvocationHandler", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m12 = Class.forName("com.sun.proxy.$Proxy0").getMethod("notify", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
$Proxy0
继承的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() {
}
}
执行findLove()
方法的整个流程,如下:
1.执行Test.findLove()
方法
2.调用了$Proxy0.findLove()
方法,相关代码如下:
public final void findLove()
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
m3 = Class.forName("com.sun.proxy.$Proxy0").getMethod("findLove", new Class[0]);
3.this.h具体指什么,关键代码如下:
this.h.invoke(this, m3, null);
Proxy类源码如下:protected InvocationHandler h;
4.因为$Proxy0
继承Proxy
,所以这里的h就是InvocationHandler
5.如何调用Meipo的invoke,看看Meipo类的相关代码可以解释,代码如下:
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
这里传入this就是Meipo本身,也是InvocationHandler接口的实现类的引用,也解释了通了调用Meipo的invoke方法。
6.最后看看invoke方法:
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//在代理真实对象前我们可以添加一些自己的操作
System.out.println("我是媒婆");
System.out.println("开始海选...");
//当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(this.target, args);
//在代理真实对象后我们也可以添加一些自己的操作
System.out.println("结束海选...");
return null;
}
可能唯一不理解的代码就是method.invoke(this.target, args);
Object proxy ——>代理对象$Proxy0
Method method ——>代理对象findLove()
Object[] args ——> 代理对象findLove()方法入参
这里可以看见,this.target就是真实对象XiaoMing,由于findLove()没有入参,因此args为空,通过反射机制执行了XiaoMing.findLove()
方法。