首先介绍,什么是Aop,通俗来讲就是我们要对一个类的方法进行一些增强(例如在方法执行之前或者之后执行一些操作),我们不是采用修改源代码或者继承对方法再修改这种纵向抽取机制(要写大量重复代码),而是采用代理模式来增强。因此Aop就是使用代理实现的。
(1)基本概念的介绍
连接点JointPoint:被增强类里面的所有可用方法(这个概念基本没用)
切入点PointCut:类中需要被增强的方法。(重要概念,即连接点不一定是切入点,但是切入点一定是连接点)
通知Adviser:增强的方法,即需要切入点额外执行的方法(重要概念:分为前置(在切入点之前指向)、后置(切入点之后执行)、异常(切入点发生异常执行)、最终(在finally语句中执行)、环绕通知(切入点前后都有))
目标对象Target:被代理的对象,也就是要被增强的类
织入Weaving:把通知应用到目标对象来创建新的代理对象的过程
代理Proxy:产生的代理对象
切面Aspect:切入点与通知结合的过程(重要概念)
(2)基于XML的aop实现
首先引入约束和aop等jar包不提。首先要确定谁是目标对象,即被增强的类以及切入点,即被增强的方法。
public class Student {
public void eat() {
System.out.println("吃饭");
}
}
例如当前例子,希望在eat()吃饭之前,能够进行“洗手”操作。则Student类就是目标对象,而eat()方法是切入点
既然要进行“洗手”操作,那么就要定义洗手操作:(因为方法不能单独存在,所以存在一个增强类中,washHand()就是通知
public class Adviser {
public void washHand() {
System.out.println("洗手");
}
}
接下来才是配置的重点,也是Aop的难点。首先Student类和Adviser类都应该交给Spring来管理,即<bean>
使用<aop:config>标签进行配置,之后的标签都是其子标签。现在我们有了增强方法、有了目标类和切入点,那么就需要指定增强到底是在何时执行,即切面的配置。因此使用子标签<aop:aspect>进行配置。有两个属性,id是给这个切面起个id值,ref是重点,是增强方法所在类的id。(切入点表达式一般为:execution(* 包名.*.*(..)) )
接下来就需要指定到底是什么增强方式了,那就使用增强方式对应的子标签(例如前置增强对应<before>)属性method表示父标签中ref属性对应的增强类中的哪一个方法是增强方法。还有两个属性:pointcut是切入点表达式,但是这个切入点只能使用一次,因此,为了服用,会在<aop:config>下有一个子标签<aop:pointcut>第一个属性是expression,即切入点表达式,id属性为切入点id值。这样在<before>等标签中,可以使用pointcut-ref来使用该切入点。例子代码如下:
<bean id="Student" class="Test.Student"></bean>
<bean id="Adviser" class="Test.Adviser"></bean>
<aop:config>
<aop:pointcut expression="execution(* Test.*.*(..))" id="pc1"/>
<aop:aspect id="aspect" ref="Adviser">
<aop:before method="washHand" pointcut-ref="pc1"/>
</aop:aspect>
</aop:config>
原理方面系统产生一个代理对象
Proxy proxy = ...;//通过代理获得代理对象
try {
before();//前置通知
proxy.doThing();//业务
after();//后置通知
} catch (Exception e) {
after_throwing();//异常通知
} finally {
after_returning();//最终通知
}
再客户端,使用getBean()获得Student对象,然后调用其eat()方法,输出表示成功
洗手
吃饭
(3)基于注解的aop
在Aop方面,使用纯注解与使用XML+注解的区别不大。二者区别在于如何开启基于注解的Aop。
基于xml+注解:xml中使用<aop:aspectj-autoproxy/>来开启
基于纯注解:在配置类中使用@EnableAspectJAutoProxy来进行开启
在增强类的增强方法上面添加@Aspect表面此类是增强类,建立切面。然后再增强方法上使用@Before("切入点表达式或者某一个方法名()") 。为了切入点复用,可以建立一个方法,上面使用@Pointcut("切入点表达式"),这样使用切入点表达式的地方都可以使用方法名()来代替
@Aspect
public class Adviser {
@Before(value = "execution(* Test.*.*(..))")
public void washHand() {
System.out.println("洗手");
}
}
或者
@Aspect
public class Adviser {
@Pointcut(value = "execution(* Test.*.*(..))")
public void m() {}
@Before(value = "m()")
public void washHand() {
System.out.println("洗手");
}
}
与xml配置aop相同,创建目标对象,然后调用其方法就可以实现aop操作了。
总结:了解Aop概念和相关术语,使用xml配置和注解完成aop操作