本篇介绍一下Spring的AOP模块中关于面向切面的概念。AOP全称Aspect Oriented Programming,即面向切面编程。第一次听说面向切面编程可能会比较陌生,或者心里堵得慌。这到底是个什么鬼。但是,不要紧,我们不要太去抠字眼,想通过这几个字就想搞明白什么是面向切面,是不太可能的。所以,先不管什么是面向切面,先把这个概念抛掷脑后。先看看下面这个例子:
我有个朋友,自己在家做点蛋糕,然后通过朋友圈卖。送货都是他自己亲自送货。模型如下图:
后来发现这样亲自送货,根本赚不到钱,而且时间都耗费在车上了,因此没有时间去做蛋糕了。这样导致,做得少不敢接太多单,利润都给城市交通了,根本赚不到钱。要解决问题,就需要找一个快递公司专门送货。如是,就有了如下模型了:
看到这里,可能有人会发现,这不就是代理模式吗。确实,这就是代理模式,将原来自己做的事情,交给代理(快递公司)来做,省时省力省钱。
那这代理模式跟AOP有什么关系?代理模式就是AOP的核心原理。面向切面编程可以简单说是面向代理模式编程。所以搞明白什么事代理模式,基本就清楚面向切面是怎么回事了:
接下来,我们通过代码的形式来实现上面的案例:
1、卖家Seller类:
package com.androidxx.proxy;
/**
* 卖家
* @author yangjw
*
*/
public class Seller {
/**
* 卖蛋糕
*/
public void sell() {
System.out.println("做蛋糕");
}
}
2、快递代理ExpressProxy类:
package com.androidxx.proxy;
public class ExpressProxy {
Seller seller = new Seller();
public void transport() {
System.out.println("上门收快递");
seller.sell();
System.out.println("快递送达");
}
}
3、买家Buyer类:
package com.androidxx.proxy;
/**
* 买家
* @author yangjw
*/
public class Buyer {
ExpressProxy express = new ExpressProxy();
public void buy() {
express.transport();
}
}
4、测试类:
package com.androidxx.proxy;
import static org.junit.Assert.*;
import org.junit.Test;
public class BuyerTest {
@Test
public void test() {
Buyer buyer = new Buyer();
buyer.buy();
}
}
以上就是一个静态代理的例子,代理模式就是由一个人代表另一个人完成一项任务。以上例子中就是由快递(ExpressProxy)代表卖家(Seller)去送货给买家(Buyer)。但是,看上面的例子,ExpressProxy为了代理Seller,需要在ExpressProxy类中创建一个Seller对象(被代理的对象);在现实生活中,一个快递公司往往都是可以给任何公司或者组织或者个人送快递的,也就是说现实生活中的快递公司可以是所有人或者组织的代理者。那这样我们岂不是要在ExpressProxy类中创建成千上万个被代理的对象?当然不需要,于是Java推出的动态代理的概念。动态代理就是可以在不修改代理类(ExpressProxy)的情况下,可以给所有对象进行代理。
动态代理
实现动态代理需要了解2个类,分别是InvocationHandler和Proxy,其中InvocationHandler是一个接口,是代理需要实现的接口;Proxy是帮助产生代理实例的一个类。接下来,使用动态代理优化以上案例中的代理模式。
1、首先要定义一个接口SuperSeller:
package com.androidxx.proxy;
public interface SuperSeller {
public void sell();
}
2、创建Seller类,并实现SuperSeller接口:
package com.androidxx.proxy;
/**
* 卖家
* @author yangjw
*
*/
public class Seller implements SuperSeller {
/**
* 卖蛋糕
*/
public void sell() {
System.out.println("做蛋糕");
}
}
3、创建动态代理类:
package com.androidxx.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicExpressProxy implements InvocationHandler{
private Object seller;
public DynamicExpressProxy(Object seller) {
super();
this.seller = seller;
}
/**
* 参数1:proxy是代理类的一个对象,但是并不是指代当前的DynamicExpressProxy对象。
* 参数2:需要执行的被代理对象的方法
* 参数3:需要执行方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("上门收快递");
//反射原理,执行方法
//Obj是method方法的返回值
Object obj = method.invoke(this.seller, args);
System.out.println("送达快递");
return obj;
}
}
4、买家类Buyer:
package com.androidxx.proxy;
import java.lang.reflect.Proxy;
/**
* 买家
* @author yangjw
*/
public class Buyer {
public void buy() {
//被代理的对象
Object obj = new Seller();
//被代理对象的Class对象
Class clss = obj.getClass();
//通过Proxy产生代理类的实例,此处的proxy对象是代理。
//动态代理的关键就是此句,动态的创建代理类对象
SuperSeller proxy = (SuperSeller) Proxy.newProxyInstance(clss.getClassLoader(), clss.getInterfaces(), new DynamicExpressProxy(obj));
//通过代理执行sell方法
proxy.sell();
}
}
5、测试类:
package com.androidxx.proxy;
import static org.junit.Assert.*;
import java.lang.reflect.Proxy;
import org.junit.Test;
public class BuyerTest {
@Test
public void test() {
Buyer buyer = new Buyer();
buyer.buy();
}
}
以上就是使用动态代理的方式来处理卖家--快递--买家的关系。动态代理,顾名思义就是动态的去创建代理。如上代码中Proxy.newProxyInstance就是用于动态创建代理的方法。关于动态代理中的InvocationHandler和Proxy其实很简单,InvocationHandler用于定义一个动态代理的类,Proxy用于产生代理类的实例。
说了半天的代理模式,它跟AOP面向切面有什么关系呢?在开头的时候,已经说了,AOP的核心其实就是代理模式。明白代理模式,在接下来的AOP学习过程中,就容易理解了。大家在学习AOP的时候,其实可以理解为在学习动态代理模式。
Spring 的AOP其实就是一种动态代理模式的实现。
此篇博客为了尽量简化代理模式的说明,有些概念写的可能比较简单,也是为了便于去理解。如果有错误的地方,也欢迎指正。