一、基于XML的声明式AspectJ
基于XML声明式AspectJ是指通过XML文件来定义切面、切入点及通知,所有的切面切入点通知都必须是定义在aop:config元素内。
1.配置切面
在Spring的哦欸之文件中,配置切面使用的是aop:aspect元素,该元素会将一个定义好事务Spring Bean转换成切面Bean,所以要在配置文件中先定义一个普通的Spring Bean。aop:aspect元素的属性及其描述如下表:
属性名称 | 描述 |
---|---|
id | 用于定义该切面的唯一标识 |
ref | 用于引用普通的Spring Bean |
2.配置切入点
切入点是通过aop:pointcut元素来定义的。当aop:pointcut元素作为aop:config元素的子元素定义时,标识切入点是全局切入点。它可以被多个切面所共享;当aop:pointcut元素作为aop:aspect元素的子元素定义时,表示该切入点值对当前切面有效。aop:pointcut元素的属性及其描述如下:
属性名称 | 描述 |
---|---|
id | 用于指定切入点的唯一标识 |
ref | 用于指定切入点关联的切入点表达式 |
3.配置通知
分别使用aop:aspect的子元素配置5中常用通知,这5个子元素不支持子元素,使用时可以指定一些属性。
属性名称 | 描述 |
---|---|
pointcut | 该属性用于指定一个切入点,Spring将在匹配该表达式的连接点时织入该通知 |
pointcut-ref | 该属性用于指定一个已经存在的切入点名称,如配置该代码中myPointCut。通常pointcut和pointcut-ref两个属性只需要使用其中之一 |
method | 该属性指定一个方法名,指定将切面Bean中的该方法转换为增强 |
throwing | 该属性只对 元素有效,它用与指定一个形象名,异常通知方法可以通过该形参访问目标方法所抛出的异常 |
returning | 该属性只对元素有效,它用于指定一个形参名,后置通知方法可以该形参访问目标方法的返回值 |
MyAspect_1.java
package com.itheima.aspect.xml;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* @ClassName: MyAspect
* @Description: 切面类,在此类中编写通知
*/
public class MyAspect {
/**
* @Title: myBerore
* @Description: 前置通知
* @Parameters: @param joinpoint
* @Return void
* @Throws
*/
public void myBerore(JoinPoint joinpoint) {
System.out.println("前置通知:模拟执行权限检查 ...,");
System.out.println("目标类是:" +joinpoint.getTarget());
System.out.println(",被植入增强处理的目标方法为:"+joinpoint.getSignature().getName());
}
/**
* @Title: myAfterreturning
* @Description: 后置通知
* @Parameters: @param joinPoint
* @Return void
* @Throws
*/
public void myAfterreturning(JoinPoint joinPoint) {
System.out.println("后置通知:模拟记入日志 . . . , ");
System.out.println("被植入增强处理的目标方法为: " +joinPoint.getSignature().getName());
}
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// 开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务 . . .");
//执行当前目标方法
Object object = proceedingJoinPoint.proceed();
//结束
System.out.println("环绕结束: 执行目标方法之后,模拟关闭事务 . . .");
return object;
}
/**
* @Title: myAfterThrowing
* @Description: 异常通知
* @Parameters: @param joinPoint
* @Parameters: @param throwable
* @Return void
* @Throws
*/
public void myAfterThrowing(JoinPoint joinPoint, Throwable throwable) {
System.out.println("异常通知: " + "出错了" + throwable.getMessage());
}
/**
* @Title: myAfter
* @Description: 最终通知
* @Parameters:
* @Return void
* @Throws
*/
public void myAfter() {
System.out.println("最终通知: 模拟方法结束后释放资源 . . .");
}
}
applicationContext.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: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/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 1 目标类 -->
<bean id="userDao" class="com.itheima.jdk.UserDaoImpl" />
<!-- 2 切面 -->
<bean id="myAspect" class="com.itheima.aspect.xml.MyAspect" />
<!-- 3 aop编程 -->
<aop:config>
<!-- 配置切面 -->
<aop:aspect ref="myAspect">
<!-- 3.1 配置切入点,通知最后增强哪些方法 -->
<aop:pointcut expression="excution(* com.itheima.jdk.*.*(..))" id="myPointCut"/>
<!-- 3.2 关联通知Advice和切入点pointCut -->
<!-- 3.2.1 前置通知 -->
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
<!-- 3.2.2 后置通知,在方法返回之后执行,就可以获得返回值
returning 属性:用于设值后置通知的第二个参数的名称,类型是Object -->
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="returnVal"/>
<!-- 3.2.3 环绕通知 -->
<aop:around method="myAround" pointcut-ref="myPointCut" />
<!-- 3.2.4 抛出通知:用于处理程序发生异常
* 注意:如果程序没有发生异常,将不会执行增强
* throwing属性:用于设值第二个参数的名称,类型Throwable -->
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="throwable"/>
<!-- 3.2.5 最终通知:无论程序发生任何事情,都将无法执行 -->
<aop:after method="myAfter" pointcut-ref="myPointCut" />
</aop:aspect>
</aop:config>
</beans>
<!-- 3.1 配置切入点,通知最后增强哪些方法 -->
<aop:pointcut expression="excution(* com.itheima.jdk.*.*(..))" id="myPointCut"/>
定义了切入点表达式,该切入点的意思是匹配 com.itheima.jdk 包中任意类的任意方法执行。其中excution()是表达式主体,第一个 * 表示的是返回类型,使用 “ * ”代表所有的类型。com.itheima.jdk 需要拦截的包名,后面第2个 * 表示类名,使用 * 代表所有类; 第3个*表示的是方法名,使用 * 表示所有方法;后面(…) 表示的是方法的参数,其中的“…” 表示任意参数。
TestXmlAspect.java
package com.itheima.aspect.xml;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.itheima.jdk.UserDao;
public class TestXmlAspectj {
public static void main(String args[]) {
String XmlPath="com/itheima/aspect/xml/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(XmlPath);
/*从Spring容器获得内容*/
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.addUser();
}
}
二、基于注解的声明式AspectJ
使用注解取代Spring配置文件中为实现aop功能的代理解析,便于实现AOP功能配置臃肿。
注解名称 | 描述 |
---|---|
@Aspect | 用于定义一个切面 |
@PointCut | 用于定义切入点表达式。在使用时还需要定义一个包含名字和任意参数的方法签名来表示切入点名称。实际上,这个方法签名就是返回一个void值,且方法体为空的普通方法 |
@Before | 用于定义前置通知,相当于BeforeAdivce。在使用时,通常需要指定一个value属性的值,该属性用于指定一个切入点表达式(可以时已有的切入点,也可以是直接定义的切入点) |
@AfterReturning | 用于定义后置通知,相当于AfterReturningAdvice。在使用时可以指定pointcut/value和returning属性,其中pointcut/value这两个属性的作用一样,都用于指定切入点表达式。returning属性用于表示Advice方法中可定义与此同名的形参,该形参可用于访问目标方法的返回值 |
@Around | 用于定义环绕通知,相当于MethodInterceptor。在使用时需要指定一个value属性,该属性用于指定该通知被植入的切入点 |
@AfterThrowing | 用于定义异常通知来处理程序未处理的异常,相当于ThrowAdvice。在使用时,可以指定pointcut/value和throwing属性。其中pointcut/value用于指定切入点表达式,而throwing属性用于指定一个形参名来表示Advice 方法中可定义与此同名的形参,该形参可以用于访问目标方法抛出的异常 |
@After | 用于定义最终final通知,不管是否异常,该通知都会执行。使用时需要指定一个value属性,该属性用于指定该通知被植入的切入点 |
@DeclareParents | 用于定义引介通知,相当于IntroductionInterceptor |