??AOP的全称是 Aspect-Oriented Programming,即面向切面编程(也称面向方面编程,它是面向对象编程(OOP)的一种补充,目前已成为一种比较成熟的编程方式。
??AOP采取横向抽取机制,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。虽然AOP是一种新的编程思想,但却不是OOP的替代品,它只是OOP的延伸和补充。
??AspectJ是一个基于Java语言的AOP框架,它提供了强大的AOP功能。Spring2.0以后,Spring AOP引入了对AspectJ的支持,并允许直接使用AspectJ进行编程,而Spring自身的AOP API也尽量与AspectJ保持一致。新版本的Spring框架也建议使用AspectJ来开发AOP。
使用AspectJ实现AOP有两种方式:一种是基于XML的声明式AspectJ,另一种是基于注解的声明式AspectJ。
??基于XML的声明式 AspectJ是指通过XML文件来定义切面、切入点及通知,所有的切面、切入点和通知都必须定义在< aop: config>元素内。Spring配置文件中的< beans>元素下可以包含多个< aop: config>元素,一个<aop: config>元素中又可以包含属性和子元素,其子元素包括< aop: pointcut>、<aop: advisor>和< aop: aspect>。在配置时,这3个子元素必须按照此顺序来定义。在<aop: aspect>元素下,同样包含了属性和多个子元素,通过使用<aop: aspect>元素及其子元素就可以在XML文件中配置切面、切入点和通知。常用元素的配置代码如下所示。
<!-- 定义切面Bean -->
<bean id="myAspect" class="com. smm. aspectj.xmI.MyAspect />
<aop:config>
<!-- 1.配置切面 -->
<aop:aspect id="aspect" ref="myAspect">
<!-- 2.配置切入点 -->
<aop:pointcut expression="execution(* com.ssm.aspectj.*.*(..))" id="myPointCut" />
<!-- 3.配置通知 -->
<!-- 前置通知 -->
<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>
在配置代码中,分别使用<aop: aspect>的子元素配置了5种常用通知,这5个子元素不支持使用子元素,但在使用时可以指定一些属性
AspectJ框架相关的JAR包
spring- aspects-4.3.6. RELEASE. Jar:Spring为AspectJ提供的实现, Spring的包中已经提供。
aspectjweaver-1.8.10.jar:是 AspectJ框架所提供的规范
package com.ssm.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());
}
/**
* 环绕通知
* ProceedingJoinPoint是JoinPoint的子接口,表示可执行目标方法
* 1.必须是Object类型的返回值
* 2.必须接收一个参数,类型为ProceedingJoinPoint
* 3.必须throws Throwable
*/
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("最终通知:模拟方法结束后释放资源...");
}
}
<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-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 1 目标类 -->
<bean id="userDao" class="com.ssm.aspectj.UserDaoImpl" />
<!-- 2 切面 -->
<bean id="myAspect" class="com.ssm.aspectj.xml.MyAspect" />
<!-- 3 aop编程 -->
<aop:config>
<!-- 1.配置切面 -->
<aop:aspect id="aspect" ref="myAspect">
<!-- 2.配置切入点 -->
<aop:pointcut expression="execution(* com.ssm.aspectj.*.*(..))" id="myPointCut" />
<!-- 3.配置通知 -->
<!-- 前置通知 -->
<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>
??基于XML的声明式AspectJ实现AOP编程虽然便捷,但是它也存在着一些缺点,那就是要在Spring文件中配置大量的代码信息。为了解决这个问题,AspectJ框架为AOP的实现提供了一套注解,用以取代 Spring配置文件中为实现AOP功能所配置的臃肿代码。
package com.ssm.aspectj.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 切面类,在此类中编写通知
*/
@Aspect
@Component
public class MyAspect {
//定义切入点表达式
@Pointcut("execution(* com.ssm.aspectj.*.*(..))")
//使用一个返回值为void、方法体为空的方法来命名切入点
public void myPointCut(){}
//前置通知
@Before("myPointCut()")
public void myBefore(JoinPoint joinPoint){
System.out.print("前置通知:模拟执行权限检查..,");
System.out.print("目标类是:"+joinPoint.getTarget());
System.out.println(",被植入增强处理的目标方法为:"+
joinPoint.getSignature().getName());
}
//后置通知
@AfterReturning(value="myPointCut()")
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("后置通知:模拟记录日志..,");
System.out.println("被植入增强处理的目标方法为:" +
joinPoint.getSignature().getName());
}
/**
* 环绕通知
* ProceedingJoinPoint是JoinPoint的子接口,表示可执行目标方法
* 1.必须是Object类型的返回值
* 2.必须接收一个参数,类型为ProceedingJoinPoint
* 3.必须throws Throwable
*/
@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
//开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务..,");
//执行当前目标方法
Object obj=proceedingJoinPoint.proceed();
//结束
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务..,");
return obj;
}
//异常通知
@AfterThrowing(value="myPointCut()",throwing="e")
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("异常通知:出错了"+e.getMessage());
}
//最终通知
@After("myPointCut()")
public void myAfter(){
System.out.println("最终通知:模拟方法结束后释放资源..");
}
}
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 指定需要扫描的包,使注解生效 -->
<context:component-scan base-package="com.ssm" />
<!-- 启动基于注解的声明式AspectJ支持 -->
<aop:aspectj-autoproxy />
</beans>
原文:https://www.cnblogs.com/zq98/p/13182669.html