面向切面的实现
目标接口
package org.example.service.AOP.Aspectj.InterFace;
public interface SomeService {
// 前置通知的目标方法
void dosome(String name,Integer age);
//后置通知的目标方法
String doother(String nage,Integer age);
// 环绕通知
String doaround(String name,Integer age);
}
目标接口实现类
package org.example.service.AOP.Aspectj.Impl;
import org.example.service.AOP.Aspectj.InterFace.SomeService;
public class SomeServiceImpl implements SomeService {
@Override
public void dosome(String name,Integer age) {
System.out.println("---------目标方法dosome-----------");
}
@Override
public String doother(String name, Integer age) {
System.out.println("-----------doother---------方法的业务方法");
System.out.println(name);
System.out.println(age);
return "后置通知";
}
@Override
public String doaround(String name, Integer age) {
System.out.println("-----doaround方法执行---"+"name:"+name+"--age:"+age);
return "abc";
}
}
切面类
package org.example.service.AOP.Aspectj.Entry;
import com.google.inject.internal.util.$Objects;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* @Aspect: 框架中的注解,
* 作用:表示当前类是切面类(给目标方法增加功能)
*/
@Aspect
public class MyAspectj {
/**
* 定义方法:方法是实现切面功能的
* 方法要求:
* 1、公共的
* 2、没有返回值
* 3、方法名称自定义
* 4、方法可以有参数,有参数时,参数不能自定义
*/
/**
* @Before: 前置通知注解
* 属性:value:是切入点表达式,表达切面的功能执行位置
* 位置:在方法的上面
* 特点:
* 1、在目标方法之前执行
* 2、不会改变目标方法的执行结果
* 3、不会影响目标方法的执行
*/
/**
* myBefore方法是可以有参数的,
* JoinPooint:业务方法(目标方法),要加入切面功能 的业务方法
* 作用:可以再通知方法中获取目标方法的执行时的信息,例如方法名称、方法的实参
* 在切面方法中需要用到方法的信息,可以加入JoinPooint
* JoinPooint参数的值由框架赋予,必须是第一个位置的参数
*/
@Before(value = "execution(public void org.example.service.AOP.Aspectj.Impl.SomeServiceImpl.dosome(String,Integer))")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知,切面类的方法,在目标方法之前执行");
// 获取方法的信息
System.out.println("方法的签名:"+joinPoint.getSignature());
System.out.println("方法的名称:"+joinPoint.getSignature().getName());
// System.out.println("获取方法的实参:"+joinPoint.getArgs()); //这个方法会返回所有的参数
}
/**
* @AfterReturning: 后置通知
* 属性:value:切入点表达是
* returning:自定义的变量,表示目标方法的返回值,且自定义变量名必须和通知方法的形参名一样
* 位置:在方法定义的上面
* 特点:在目标方法之后执行
* 可以获取到目标方法的返回值,可以根据这个方法的返回值做不同的处理
* 可以修改这个返回值
* @param res
*/
@AfterReturning(value = "execution(public String org.example.service.AOP.Aspectj.Impl.SomeServiceImpl.doother(String,Integer))",returning = "res")
public void otherreturn(Object res){
// Object res是目标方法的返回值,可以根据这个返回值做不通的处理
if (res == null){
System.out.println("@AfterReturning: 后置通知,获取到目标方法的返回值是:"+res+"---------目标方法不为空");
}else {
System.out.println("目标方法为空");
}
}
/**
* @Around: 环绕通知
* 环绕筒子方法的定义格式
* 1、返回值类型:public
* 2、必须有一个返回值,推荐使用Object
* 3、方法名称自定义
* 4、方法有参数,固定参数;proceedingJoinPoint
*
* 作用:
* 1、在目标方法的前后增强功能
* 2、能够控制目标方法是否被执行
* 3、原来的目标方法的执行结果,影响最后的调用结果
*
* 环绕通知,等同于jdk动态代理的invoke()方法
* 参数proceedingJoinPoint的作用等同于jdk动态代理的Method,
* 返回值:就是目标方法的执行结果,可以被修改
*
*/
/**
*
* @param proceedingJoinPoint
* @return
*/
@Around(value = "execution(public String org.example.service.AOP.Aspectj.Impl.SomeServiceImpl.doaround(String,Integer))")
public Object myaround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知执行");
// 实现环绕通知
Object object = null;
// 目标方法之前的执行
System.out.println("目标方法之前");
//-------------------------------------------------------------------------
// 目标方法的调用,这段代码表示要执行的目标方法
// 控制目标方法是否执行
String name = "";
Object args[] = proceedingJoinPoint.getArgs();
if (args != null && args.length>1){
Object arg1 = args[0];
name = (String)arg1;
}
if ("刘备".equals(name)){
object = proceedingJoinPoint.proceed();
}
//-----------------------------------------------------------------------------
// 目标方法之后执行的代码
System.out.println("目标方法之后执行的代码");
return object;
}
/**
* @Pointcut:
* 定义和管理切入点,如果项目中有多个切入点表达式一样,可以进行复用,可以使用@Pointcut
* 属性:
* value:切入点表达式
* 位置:
* 在自定义方法的上方
* 特点:
* 当时用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名,其他的通知中,value属性就可以使用这个方法名称,代替切入点表达式
*/
/**
* 现在这个自定义方法就等同于切入点表达式,在其他地方的切入点表达式和这个一样,就可以直接使用 mypt() 来代替切入点表达式
*/
@Pointcut(value = "execution(public void org.example.service.AOP.Aspectj.Impl.SomeServiceImpl.dosome(String,Integer))")
public void mypt(){}
}