Spring的AOP(面向切面编程、或者叫面向方面编程)一直以来是初学Spring程序员的一个挥之不去的梗,想想当年自己刚开始接触AOP的时候也是一头雾水。我当初的学习方式就是先不管是否理解,既然大家都说好,就先用,用着用着就明白了为什么。本篇文章我也是想尽可能的让大家在学习之初就能明白什么是AOP。AOP的核心其实就是动态代理,这个在第一篇文章【
Spring框架AOP之代理模式】中有讲解,并且此篇文章也会延用上一篇文章的例子,所以如果是初学Spring AOP,可以先去看看【
Spring框架AOP之代理模式】和【
Spring框架之依赖注入】。
我们还是使用上一篇文章的案例,我朋友自己在家做蛋糕,然后再朋友圈卖,一开始都是自己亲自送货。模型如下:
为了节省时间和成本,需要请一个快递公司进行送货,但是又不能破坏现有的商家和买家的关系结构,就需要以面向切面编程(AOP)方式,将快递公司插入卖家和买家中间,如下图:
这样快递公司的加入,并不影响卖家进行蛋糕制作,也不影响买家正常收到货物。卖家和买家不需要修改任何的代码。具体的实现代码如下。
1、首先需要配置Spring的AOP所需的Jar包。将如下jar包导入工程中:
以上Jar文件的下载,可以自行在网上搜索一下。或者在我的“下载资源”中可以
免费下载。
2、创建卖家Seller类:
package com.androidxx.proxy;
/**
* 卖家
* @author yangjw
*
*/
public class Seller implements SuperSeller {
public Seller() {
super();
// TODO Auto-generated constructor stub
}
/**
* 卖蛋糕
*/
public void sell() {
System.out.println("做蛋糕");
}
}
3、创建买家Buyer类:
package com.androidxx.proxy;
import java.lang.reflect.Proxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 买家
* @author yangjw
*/
//Component注解表示当前类是交由Spring框架管理的一个组件
@Component
public class Buyer {
private SuperSeller seller;
//Autowired注解表示此方法中的参数seller,需要交由Spring注入。这在Spring的IOC一篇文章中讲过。
@Autowired
public void setSeller(SuperSeller seller) {
this.seller = seller;
}
public void buy() {
seller.sell();
}
}
以上代码中的注解是
Spring框架IOC中讲到过。不明白的可以先看看【
Spring框架依赖注入】。并且在以上代码中我也写有简单的注释,有点基础的猿,看起来应该并不难理解。
4、创建快递ExpressProxy类:
package com.androidxx.proxy;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
//Aspect注解表示当前类是作为一个"切面"
@Aspect
//Component注解表示将当前类交由Spring进行初始化(管理)
@Component
public class ExpressProxy {
//Before注解表示在切入点之前执行
//execution(....)是一种表达式,表示编入点就是sell方法,表示在执行sell方法前,先执行begin方法
@Before("execution(public void com.androidxx.proxy.Seller.sell())")
public void begin() {
System.out.println("上门收快递");
}
//After注解表示在切入点之后执行
@After("execution(public void com.androidxx.proxy.Seller.sell())")
public void end() {
System.out.println("快递送达");
}
}
以上代码中有几个注解是在AOP中特有的,其含义分别如下:
@Aspect:表示此类就是一个切面。换一个说法就是当前类将会被植入某一个切入点之前或者之后,而切入点可能就是一个方法而已。
@Before,@After:定义切入点,分别表示切入点前和后。execution中是一个表达式,写作的形式很多,甚至可以使用通配符。这一点的知识也比较多,此处不做讲解。以上代码的含义可以用一句话说明:
ExpressProxy作为一个切面,切面中有2个切入点,分别是在Seller.sell()方法之前和之后。也就是在执行sell方法之前会先执行begin方法,在执行sell方法之后会执行end方法。
5、创建Spring的配置类:
package com.androidxx.proxy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
/**
* 此类是Spring的初始化的入口类,同时也是一个Bean工厂类,提供IOC所需的注入对象
* @author yangjw
*
*/
@Configuration //表示此类是一个配置类,作为初始化入口类存在
@EnableAspectJAutoProxy //表示允许使用Aspectj进行AOP的操作
@ComponentScan //表示此类就是一个Bean工厂,在此类中寻找需要的Component
public class BeanFactory {
@Bean //Bean注解表示此方法提供Bean对象,用于IOC的依赖注入
public SuperSeller provideSeller() {
return new Seller();
}
}
6、使用JUnit测试:
package com.androidxx.proxy;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class BuyerTest {
@Test
public void test() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanFactory.class);
Buyer buyer = ctx.getBean(Buyer.class);
buyer.buy();
}
}
测试结果如下:
上门收快递
做蛋糕
快递送达
AOP的出现的用意就是在不影响原有逻辑的情况下,可以在需要的位置加入一段逻辑。可以看到以上的例子中,没有修改Buyer和Seller的前提下,在sell方法前后加入了一段逻辑代码,这就是AOP的简单运用。
做蛋糕
快递送达
AOP的出现的用意就是在不影响原有逻辑的情况下,可以在需要的位置加入一段逻辑。可以看到以上的例子中,没有修改Buyer和Seller的前提下,在sell方法前后加入了一段逻辑代码,这就是AOP的简单运用。
说明:
Spring的核心就是对现有对象的管理,AOP是建立Spring对对象管理的基础之上,要使用Spring的AOP,必须将对象交由Spring管理。所以,本案例中需要建立在IOC的基础上来使用AOP。如果不明白Spring的组织结构的,可以先看看【
Spring的简单介绍】.
【成功是一点点的积累,而积累是需要时间的,不要想着一步登天,抓紧埋头敲代码】