什么是AOP
AOP(面向切面编程)通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。
主要用于日志记录,性能统计,安全控制,事务处理,异常处理等方面。
入门实例
本实例使用springboot框架,首先我们写一个计算三角函数的接口和实现:
public interface TrigonometricFunctionCal {
public double sin(double angle);
public double cos(double angle);
public double tan(double angle);
}
@Component
public class TrigonometricFunctionCalImpl implements TrigonometricFunctionCal {
private double angleToRandian(double angle){
return angle*Math.PI/180;
}
@Override
public double sin(double angle) {
return (new BigDecimal(Math.sin(angleToRandian(angle))).setScale(6, BigDecimal.ROUND_HALF_DOWN)).doubleValue();
}
@Override
public double cos(double angle) {
return (new BigDecimal(Math.cos(angleToRandian(angle))).setScale(6, BigDecimal.ROUND_HALF_DOWN)).doubleValue();
}
@Override
public double tan(double angle) {
return (new BigDecimal(Math.tan(angleToRandian(angle))).setScale(6, BigDecimal.ROUND_HALF_DOWN)).doubleValue();
}
}
写一个切面类
@Aspect
@Component
public class TestAop {
/**
* 切入点
* 匹配com.way.inter.impl包及其子包下的所有类的所有方法
*/
@Pointcut("execution(* com.way.inter.impl..*.*(..))")
public void executePackage(){
}
/**
* 前置通知,目标方法调用前被调用
* @param joinPoint
*/
@Before("executePackage()")
public void beforeAdvice(JoinPoint joinPoint){
System.out.println("@Before这是前置通知");
Signature signature = joinPoint.getSignature();
System.out.println("方法全名:"+signature);
System.out.println("方法名称:"+signature.getName());
Object[] obj = joinPoint.getArgs();
System.out.println("方法参数:"+Arrays.asList(obj));
}
/**
* 后置最终通知,目标方法执行完执行
*/
@After("executePackage()")
public void afterAdvice(){
System.out.println("@After这是后置最终通知");
}
/**
* 后置返回通知
* 如果参数中的第一个参数为JoinPoint,则第二个参数为返回值的信息
* 如果参数中的第一个参数不为JoinPoint,则第一个参数为returning中对应的参数
* returning 只有目标方法返回值与通知方法相应参数类型时才能执行后置返回通知,否则不执行
* @param joinPoint
* @param keys
*/
@AfterReturning(value = "executePackage()",returning = "keys")
public void afterReturningAdvice(JoinPoint joinPoint,double keys){
System.out.println("@AfterReturning这是后置返回通知 返回值是"+keys);
}
/**
* 环绕通知:
* 可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
* 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
*/
@Around("execution(* com.way.inter.impl.TrigonometricFunctionCalImpl.sin(..))")
public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("@Around这是环绕通知");
System.out.println("方法名:"+proceedingJoinPoint.getSignature().getName());
try {//obj之前可以写目标方法执行前的逻辑
Object obj = proceedingJoinPoint.proceed();
return obj;
} catch (Throwable throwable) {
throwable.printStackTrace();
}finally {
System.out.println("环绕通知结束");
}
return null;
}
}
测试类:
@RunWith(SpringRunner.class)
@SpringBootTest
public class Test1 {
@Autowired
TrigonometricFunctionCal trigonometricFunctionCal;
@Test
public void MyTest() throws IOException, InterruptedException{
System.out.println(trigonometricFunctionCal.sin(30));;
}
}
运行结果: