AspectJ
@AspectJ的风格类似纯java注解的普通java类
Spring可以使用AspectJ来做切入点解析
AOP的运行时仍旧是纯的Spring AOP,对AspectJ的编译器或者织入无依赖性
Spring中配置@AspectJ
对@AspectJ支持可以使用XML或Java风格的配置
Java注解风格:
@Configuration
@EnableAspectJAutoProxy
public class AppConfig{}
XML格式:
<aop:aspectj-autoproxy/>
两种方式都可以,但是有个前提就是确保AspectJ的aspectjweaer.jar库包含在应用程序(版本1.6.8或更高版本)的classpath中。
然后我们在我们的例子中使用xml文件配置方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.imooc.aop.aspectj"/>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
xml文件中主要就是这一句<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
。
aspect具体使用
1.@AspectJ切面使用@Aspect注解配置,拥有@Aspect的任何bean将被Spring自动识别并应用。
2.用@Aspect注解的类可以有方法和字段,他们也可能包括切入点(pointcut),通知(Advice)和引入(introduction)声明,也就是说用@Aspect注解这个类可以拥有AOP的一切特点和使用方式,和之前讲到通过xml的配置方式实现是非常接近的。
3.@Aspect注解是不能通过类路径自动检验发现的,所以需要配合使用@Component注解或者在xml配置bean。
什么是类路径自动检验?前边的代码有这一句<context:component-scan base-package="com.imooc.aop.aspectj"/>
。Spring的bean容器会自动扫描所有在com.imooc.aop.aspectj包下的类。
由于@Aspect注解是不能通过类路径自动检验发现,所以component-scan不能检测某个类上或者某个bean上是否有@Aspect这个注解,所以可以配合使用@Component注解或者在把@Aspect注解的类配置在xml中,通过这种方式把它配置成一个Spring的bean。
看一下这两种方式(只写了配置在xml文件中的方式):
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class NotVeryUsfulAspect{}
<bean id="myAspect" class="org.xyz.NotVeryUsefulAspect"?
<!-- configure properties of aspect here as normal -->
</bean>
把这个类配置到xml文件当中,当然也可以在第一段代码中上边加上@Component注解把它标注成Spring的一个Bean。
4.一个类中的@Aspect注解标识它为一个切面,并且将自己从自动代理中排除。这容易理解,如果一个切面类和业务类在同一个包下,排除自己可以避免死循环。如果@AspectJ去代理了自己,然后又去找它。
pointcut
一个切入点通过一个普通的方法定义来提供,并且切入点表达式使用@Pointcut注解,方法返回类型必须为void
定义一个名为‘anyOldTransfer’,这个切入点将匹配任何名为“transfer”的方法的执行
@Pointcut("execution(*transfer(..))") //the pointcut expression
private void anyOldTransfer(){} //the pointcut signature
@Pointcut注解的方法的返回值必须为void类型
切入点支持哪些定义方式或者哪些点可以定义
然后我们定义一下自己的切入点
@Component
@Aspect
public class MoocAspect {
@Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")
public void pointcut() {}
@Pointcut("within(com.imooc.aop.aspectj.biz.*)")
public void bizPointcut() {}
}
对于这个切入点
@Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")
public void pointcut() {}
也就是说在执行com.imooc.aop.aspectj.biz包下任何以Biz结尾的类的任何类型方法的时候,都会匹配当前切入点。
对于这个切入点
@Pointcut("within(com.imooc.aop.aspectj.biz.*)")
public void bizPointcut() {}
是说当前这个com.imooc.aop.aspectj.biz包下的任何类都会匹配到这个切入点。
组合pointcut
切入点表达式可以通过&&、||和!进行组合,也可以通过名字引用切入点表达式
通过组合,可以建立更加复杂的切入点表达式
定义良好的pointcuts
AspectJ是编译期AOP
检查代码并匹配连接点与切入点的代价是昂贵的
一个好的切入点应该包括以下几点
-选择特定类型的连接点,如execution、get、set、call、handler
-确定连接点范围,如:within、withincode
-匹配上下文信息,如:this、target、@annotation