1.背景知识
在Sping中使用AOP的主要工作是配置织入关系,使用<aop:config>标签代表这一段是织入关系的配置
首先,用<aop:aspect>标签声明一个切面,这里要引用我们之前编写好的切面类极其在配置文件中注册的id(myAspect)
然后,通过<aop:[aopMethod]>标签对各种类型的增强进行配置,前置增强用before,后置增强用after
切面=增强+切点,所以在对应的增强类型中我们还要指定具体的增强方法和切点,配置切点就需要切点表达式
<!--配置织入关系:告诉Spring,哪些切点(目标方法)需要进行哪些增强(前置、后置等等...)-->
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面=增强+切点-->
<aop:before method="beforeEnhance" pointcut="execution(public void com.lxl.aop.Target.service())"/>
<aop:after method="afterEnhance" pointcut="execution(public void com.lxl.aop.Target.service())"/>
</aop:aspect>
</aop:config>
2.切点表达式的写法
切点表达式的语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
,其中
- 修饰符可以省略
- 返回值类型、包名、类名、方法名可以用*代替
- 包名与类名之前一个点.代表当前包写的类,两个点…代表当前包极其子包下的所有类
- 参数列表可以用两个点…代表任意类型、任意个数的参数
1.最明确也是范围最小的一种声明:所有的地方都不省略,但是这样只能声明一个方法,不方便
excecution(public void com.lxl.aop.Target.service())
2.代表Target类下的所有方法都要声明成切点,不过返回值必须都是void
excecution( void com.lxl.aop.Target.*(..))
3.这种声明方法最常用,代表aop当前包下的所有类的任何方法都声明成切点,需要被增强
excecution( * com.lxl.aop.*.*(..))
4.拓展了上面的方法,把aop包极其子包下的所有类也声明成了切点
excecution( * com.lxl.aop..*.*(..))
3.切点表达式的抽取
首先,我们在applicationContext.xml中有一个织入的配置,但是发现所有的增强都是用的同一个切点表达式:
<!--配置织入关系:告诉Spring,哪些切点(目标方法)需要进行哪些增强(前置、后置等等...)-->
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面=增强+切点-->
<aop:before method="beforeEnhance" pointcut="execution( * com.lxl.aop.Target.*(..))"/>
<aop:after-returning method="afterReturningEnhance" pointcut="execution( * com.lxl.aop.Target.*(..))"/>
<aop:after method="afterEnhance" pointcut="execution( * com.lxl.aop.Target.*(..))"/>
<aop:around method="aroundEnhance" pointcut="execution( * com.lxl.aop.Target.*(..))"/>
<aop:after-throwing method="throwingEnhance" pointcut="execution( * com.lxl.aop.Target.*(..))"/>
</aop:aspect>
</aop:config>
抽点表达式都是相同的,但是重复去写很麻烦,而且也不利于后期的维护,所有可以把他们抽取出来:
<aop:pointcut id="myPointcut" expression="execution( * com.lxl.aop.Target.*(..))"/>
所以原先的织入配置就可以改为:
<!--配置织入关系:告诉Spring,哪些切点(目标方法)需要进行哪些增强(前置、后置等等...)-->
<aop:config>
<!--声明切面-->
<aop:aspect ref="myAspect">
<!--切面=增强+切点-->
<!--抽取切点表达式-->
<aop:pointcut id="myPointcut" expression="execution( * com.lxl.aop.Target.*(..))"/>
<aop:before method="beforeEnhance" pointcut-ref="myPointcut"/>
<aop:after-returning method="afterReturningEnhance" pointcut-ref="myPointcut"/>
<aop:after method="afterEnhance" pointcut-ref="myPointcut"/>
<aop:around method="aroundEnhance" pointcut-ref="myPointcut"/>
<aop:after-throwing method="throwingEnhance" pointcut-ref="myPointcut"/>
</aop:aspect>
</aop:config>
补充:注解配置中切点表达式的抽取方法
在切面类中自定义一个方法,然后在方法上加上 @Pointcut(“excecution(…)”)注解,在增强方法中使用时直接进行引用即可:
@Component("myAspect")
@Aspect // 告知Spring容器当前MyAspect类是一个切面类
public class MyAspect {
@Pointcut("execution(* com.lxl.aopAnnotation.Target.*(..))")
public void myPoint(){}
@Before("MyAspect.myPoint()")
public void beforeEnhance(){
System.out.println("前置增强,在切点的前面执行.......");
}
}