Spring 中的通知按照在目标类方法的连接点位置,可以分为以下 5 种类型:
org. aopalliance.intercept.MethodInterceptor
(环绕通知) 在目标方法执行前后实施增强,可以应用于曰志、事务管理等功能。org.springframework.aop.MethodBeforeAdvice
(前置通知) 在目标方法执行前实施增强,可以应用于权限管理等功能。org.springframework.aop.AfterReturningAdvice
(后置通知) 在目标方法执行后实施增强,可以应用于关闭流、上传文件、删除临时文件等功能。org.springframework.aop.ThrowsAdvice (
异常通知) 在方法抛出异常后实施增强,可以应用于处理异常记录曰志等功能。org .springframework.aop.IntroductionInterceptor
(引介通知) 在目标类中添加一些新的方法和属性,可以应用于修改老版本程序(增强类)。
AspectJ 是一个基于Java语言的AOP框架,它提供了强大的 AOP 功能Spring 2.0 以后, Spring AOP 引入了对 AspectJ 的支持,并允许直接使用 AspectJ 进行编程,而 Spring 自身的 AOPAPI 也尽量与 AspectJ保持一致。新版本的 Spring 框架,也建议使用 AspectJ 来开发 AOP。 使用 AspectJ 实现 AOP 有两种方式:一种是基于 XML 的声明式 AspectJ ,另一种是基于注解的声明式 AspectJ
基于 XML 的声明式 AspectJ
基于 XML 的声明式 AspectJ 是指通过 XML 文件来定义切面、切入点及通知,所有的切面、 切入点和通知都必须定义在<aop:config>
元素内。<aop:config>
元素及其子元素如图所示:
首先我们需要开发的包:aopalliance包的下载 和 AspectJ包下载
首先创建切面类 MyAspect;
package com.itheima.aspectj.xml;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//切面类,在此类中编写通知
public class MyAspect {
//前置通知
public void myBefore(JoinPoint joinPoint) {
System.out.print("前置通知:模拟执行权限检查. .. , ");
System.out.print(" 目标类是: " + joinPoint.getTarget());
System.out.println(",被植入增强处理的目标方法为: " + joinPoint.getSignature().getName());
}
// 后置通知
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("后置通知:模拟记录日志. . . ,");
System.out.println("被植入增强处理的目标方法为: " + joinPoint.getSignature().getName());
}
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕开始:执行目标方法之前,模拟开启事务. . . ");
Object obj = proceedingJoinPoint.proceed();
System.out.println("环绕结束: 执行门标方法之后, 模拟关闭事务 ");
return obj;
}
// 异常通知
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("异常通知: " + "出错了" + e.getMessage());
}// 址终通知
public void myAfter() {
System.out.println("最终通知: 模拟方法结束后的释放资源 . . . ");
}
}
再创建一个配置文件:使用到了jdk动态代理当中的接口以及类:博文链接地址
- 1.0 配置切面
在 Spring 的配置文件中 ,配置切面使用 的是<aop:aspect>
元素 , 该元素会将一个已定 义好的 Spring Bean 转换成切面 Bean,所以要在配置文件中先定义一个普通的 Spring Bean , 定义完成后,通过<aop:aspect>
元素的 ref 属性即可引用该 Bean。 配置<aop:asect>
元素时,通常会指定id
和ref
两个属性,
- 2.0配置切面点
在 Spring 的配置文件中 ,切入点是通过<aop:pointcut>
元素来定义的。 当<aop:pointcut>
元素作为<aop:config>
元素的子元素定义时,表示该切入点是全局切入点,它可被多个切面所 共享 ; 当<aop:pointcut>
元素作为<aop:aspect>
元素的子元素时,表示该切入点只对当前切面有效。在定义<aop:poíntcut>
元素时,通常会指定id
和expresslon
两个属性
- 3.0切入点表达式
execution(* jdk动态代理.*.*( .. ) )
该切入点表达式的意思是匹配jdk动态代理包中任意类的任意方法的执行。
切入点表达式一共有六个参数execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
从左到右分别表示的是:定义的目标方法的访问修饰、定义的目标方法的返回值类型、定义的目标方法的类路径、具体需要被代理的目标方法、需要被代理的目标方法包含的参数、需要被代理的目标方法抛出的异常类型。
其中带问号的表示可选项,其余都为必选项。 - 4.0 配置通知
在配置代码中,分别使用<aop:aspect>
的子元素配置了 5 种常用通知,这5个子元素不支 持使用子元素,但在使用时可以指定一些属性
<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.spr![在这里插入图片描述](https://img-blog.csdnimg.cn/20200318105243871.png)ingframework.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.xsd">
<!-- 目标类 -->
<bean id="userDao" class="jdk动态代理.UserDaolmpl" />
<!--切面类 -->
<bean id="myAspect" class="com.itheima.aspectj.xml.MyAspect" />
<!-- AOP编程 -->
<aop:config>
<!--配置切面 -->
<aop:aspect ref="myAspect">
<!--3.1 配置切入点,通知最后增强哪些方法 -->
<aop:pointcut
expression="execution(* jdk动态代理.*.*( .. ) ) " id="myPointCut" />
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
<aop:after-returning method="myAfterReturning"
pointcut-ref="myPointCut" returning="returnVal" />
<aop:around method="myAround" pointcut-ref="myPointCut" />
<aop:after-throwing method="myAfterThrowing"
pointcut-ref="myPointCut" throwing="e" />
<aop:after method="myAfter" pointcut-ref="myPointCut" />
</aop:aspect>
</aop:config>
</beans>
最后创建一个测试类:
package com.itheima.aspectj.xml;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import jdk动态代理.UserDao;
public class TestXmlAspectj {
public static void main(String[] args) {
String xmlPath = "com/itheima/aspectj/xml/applicationContext.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(xmlPath);
// 从 spring 容器获得内
UserDao userDao = (UserDao) ac.getBean("userDao");
// 执行方法
userDao.addUser();
}
}