目录
基于 XML
方式实现
使用 xml
配置文件(不使用注解)
Maven
依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
目标接口
public interface IUserManagerService {
// 查找用户
public String findUser();
// 添加用户
public void addUser();
}
目标实现类
public class UserManagerServiceImpl implements IUserManagerService{
private String name;
public void setName(String name){
this.name=name;
}
public String getName(){
return this.name;
}
public String findUser(){
System.out.println("============执行业务方法findUser,查找的用户是:"+name+"=============");
return name;
}
public void addUser(){
System.out.println("============执行业务方法addUser=============");
//throw new RuntimeException();
}
}
通知切面类
public class AopAspect {
/**
* 前置通知:目标方法调用之前执行的代码
*/
public void doBefore(JoinPoint jp){
System.out.println("===========执行前置通知============");
}
/**
* 最终通知:目标方法调用之后执行的代码(无论目标方法是否出现异常均执行)
* 因为方法可能会出现异常,所以不能获取方法的返回值
*/
public void doAfter(JoinPoint jp){
System.out.println("===========执行最终通知============");
}
/**
* 后置通知:目标方法正常结束后执行的代码
* 后置通知是可以获取到目标方法的返回值的
*/
public void doAfterReturning(JoinPoint jp,String result){
System.out.println("===========执行后置返回通知============");
System.out.println("返回值result==================="+result);
}
/**
* 异常通知:目标方法抛出异常时执行的代码
* 可以访问到异常对象
*/
public void doAfterThrowing(JoinPoint jp,Exception ex){
System.out.println("===========执行异常通知============");
}
/**
* 环绕通知:目标方法调用前后执行的代码,可以在方法调用前后完成自定义的行为。
* 包围一个连接点(join point)的通知。它会在切入点方法执行前执行同时方法结束也会执行对应的部分。
* 主要是调用proceed()方法来执行切入点方法,来作为环绕通知前后方法的分水岭。
* 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
* 而且环绕通知必须有返回值,返回值即为目标方法的返回值
*/
public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("======执行环绕通知开始=========");
// 调用方法的参数
Object[] args = pjp.getArgs();
// 调用的方法名
String method = pjp.getSignature().getName();
// 获取目标对象
Object target = pjp.getTarget();
// 执行完方法的返回值
// 调用proceed()方法,就会触发切入点方法执行
Object result=pjp.proceed();
System.out.println("输出,方法名:" + method + ";目标对象:" + target + ";返回值:" + result);
System.out.println("======执行环绕通知结束=========");
return result;
}
}
spring
的配置文件
<bean id="userManager" class="com.spring.service.impl.UserManagerServiceImpl">
<property name="name" value="lixiaoxi"></property>
</bean>
<!-- 通知类 -->
<bean id="aspectBean" class="com.spring.aop.AopAspect" />
<aop:config>
<aop:aspect ref="aspectBean">
<!-- 配置切点 -->
<aop:pointcut id="pointcut" expression="execution(* com.spring.service.impl.UserManagerServiceImpl..*(..))"/>
<!-- 前置通知 -->
<aop:before method="doBefore" pointcut-ref="pointcut"/>
<!-- 后置返回通知 -->
<aop:after-returning method="doAfterReturning" pointcut-ref="pointcut" returning="result"/>
<!-- 后置通知 -->
<aop:after method="doAfter" pointcut-ref="pointcut" />
<!-- 环绕通知 -->
<aop:around method="doAround" pointcut-ref="pointcut"/>
<!-- 异常通知 -->
<aop:after-throwing method="doAfterThrowing" pointcut-ref="pointcut" throwing="ex"/>
</aop:aspect>
</aop:config>
<aop:pointcut>
如果位于<aop:aspect>
元素中,则命名切点只能被当前<aop:aspect>
内定义的元素访问到,为了能被整个<aop:config>
元素中定义的所有增强访问,则必须在<aop:config>
下定义切点- 如果在
<aop:config>
元素下直接定义<aop:pointcut>
,必须保证<aop:pointcut>
在<aop:aspect>
之前定义。<aop:config>
下还可以定义<aop:advisor>
,三者在<aop:config>
中的配置有先后顺序的要求:首先必须是<aop:pointcut>
,然后是<aop:advisor>
,最后是<aop:aspect>
。而在<aop:aspect>
中定义的<aop:pointcut>
则没有先后顺序的要求,可以在任何位置定义 <aop:pointcut>
:用来定义切入点,该切入点可以重用;<aop:advisor>
用来定义只有一个通知和一个切入点的切面;<aop:aspect>
:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor
的区别就在此,advisor
只包含一个通知和一个切入点
测试
public class TestAop {
public static void main(String[] args) throws Exception{
ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext3.xml");
IUserManagerService userManager = (IUserManagerService)act.getBean("userManager");
userManager.findUser();
System.out.println("\n");
userManager.addUser();
}
}
测试结果
使用注解的方式
采用注解来做 aop
,主要是将写在 spring
配置文件中的连接点写到注解里面
业务接口和业务实现与上边一样,具体切面类如下
@Aspect
public class AopAspectJ {
/**
* 切点表达式
*/
@Pointcut("execution(* com.spring.service.impl.UserManagerServiceImpl..*(..))")
public void myPointcut() {
}
/**
* 前置通知:即方法执行前拦截到的方法
* 在目标方法执行之前的通知
*/
@Before("myPointcut()")
public void doBefore(JoinPoint jp){
System.out.println("=========执行前置通知==========");
}
/**
* 最终通知:目标方法调用之后执行的通知(无论目标方法是否出现异常均执行)
* 因为方法可能会出现异常,所以不能获取方法的返回值
*/
@After(value="myPointcut()")
public void doAfter(JoinPoint jp){
System.out.println("===========执行最终通知============");
}
/**
* 后置通知:在方法正常执行通过之后执行的通知叫做返回通知
* 可以获取到目标方法的返回值
*/
@AfterReturning(value="myPointcut()",returning="result")
public void doAfterReturning(JoinPoint jp,String result){
System.out.println("===========执行后置通知============");
}
/**
* 环绕通知:目标方法调用前后执行的通知,可以在方法调用前后完成自定义的行为。
*/
@Around("myPointcut()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("======执行环绕通知开始=========");
// 调用方法的参数
Object[] args = pjp.getArgs();
// 调用的方法名
String method = pjp.getSignature().getName();
// 获取目标对象
Object target = pjp.getTarget();
// 执行完方法的返回值
// 调用proceed()方法,就会触发切入点方法执行
Object result=pjp.proceed();
System.out.println("输出,方法名:" + method + ";目标对象:" + target + ";返回值:" + result);
System.out.println("======执行环绕通知结束=========");
return result;
}
/**
* 异常通知:在目标方法非正常执行完成, 抛出异常的时候会走此方法
*/
@AfterThrowing(value="myPointcut()",throwing="ex")
public void doAfterThrowing(JoinPoint jp,Exception ex) {
System.out.println("===========执行异常通知============");
}
}
spring
的配置文件
<!-- spring 对 @AspectJ 的支持 -->
<aop:aspectj-autoproxy/>
<!-- 业务类 -->
<bean id="userManager" class="com.spring.service.impl.UserManagerServiceImpl">
<property name="name" value="lixiaoxi"></property>
</bean>
<!-- 通知类 -->
<bean id="aspectBean" class="com.spring.aop.AopAspectJ" />
springboot
实现 AOP
Maven
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
通知类
@Component
@Aspect
public class Demo16 {
// 前置通知:在目标方法执行之前的通知
@Before("execution (* com.zsg.demo..*.*(..))")
public void beforeMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().toString();
Object result = Arrays.asList(joinPoint.getArgs());
System.out.println("The method name:" + methodName + "--value:" + result);
}
// 最终通知:目标方法调用之后执行的通知(无论目标方法是否出现异常均执行)
// 因为方法可能会出现异常,所以不能获取方法的返回值
@After("execution (* com.xxx.demo..*.*(..))")
public void afterMethod(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The method name:" + methodName + " ends");
}
// 后置通知:在方法正常执行通过之后执行的通知叫做返回通知,可以获取到目标方法的返回值
@AfterReturning(value = "execution (* com.xxx.demo..*.*(..))", returning = "result")
public void afterReturningMethod(JoinPoint joinPoint, Object result) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The method name:" + methodName + " ends and result=" + result);
}
// @AfterThrowing: 异常通知
@AfterThrowing(value = "execution (* com.xxx.demo..*.*(..))", throwing = "e")
public void afterReturningMethod(JoinPoint joinPoint, Exception e) {
String methodName = joinPoint.getSignature().getName();
System.out.println("The method name:" + methodName + " ends and result=" + e);
}
}