AOP @Aspecj使用过程
1、pom.xml加入依赖关系 spring-context aspectj spring-aop
注:去掉aspectjweaver运行时状态
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.19</version>
<!--<scope>runtime</scope>-->
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.25</version>
</dependency>
</dependencies>
2、创建切面类
package com.kdy.aspects;
import com.kdy.annotation.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect //标记切面
@Component //标记为bean组件
public class LogAspect {
@Pointcut("execution(* com.kdy.service.impl.*.*(..))")
public void pp(){}
//前置通知
//@Before("execution(* com.kdy.service.impl.*.*(..))")
// @Before("execution(public * com.kdy.service.impl.*.add(..))")
//@Before("within(com.kdy.service..*)")
// @Before("!@annotation(com.kdy.annotation.Logger)")
//@Before("execution(* com.kdy.service.impl.*.*(..))")
//@Before("@annotation(com.kdy.annotation.Logger)")
//@Before("pp() && @annotation(logger)")
public void before(JoinPoint joinPoint, Logger logger) {
// public void before(JoinPoint joinPoint) {
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println("注解信息"+logger.doname());
System.out.println(name+"方法运行了,参数是"+Arrays.asList(args));
System.out.println("前置通知1");
}
//后置通知
// @After("execution(* com.kdy.service.impl.*.*(..))")
@After("pp()")
public void after(JoinPoint joinPoint) {
String name = joinPoint.getSignature().getName();
System.out.println(name);
Object[] args = joinPoint.getArgs();
System.out.println(Arrays.asList(args));
System.out.println("后置通知");
}
//后置异常通知
@AfterThrowing(value = "execution(* com.kdy.service.impl.*.*(..))",throwing = "ex")
public void afterThrow(JoinPoint joinPoint,Exception ex) {
System.out.println(ex);
System.out.println("后置异常通知");
}
//后置返回通知
@AfterReturning(value = "execution(* com.kdy.service.impl.*.*(..))",returning = "returnValue")
public void afterReturning(JoinPoint joinPoint,Object returnValue ) {
String name = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
System.out.println(returnValue);
System.out.println("后置返回通知");
}
//环绕通知
@Around("pp()")
public Object arround(ProceedingJoinPoint proceedingJoinPoint){
String name = proceedingJoinPoint.getSignature().getName();
Object[] args = proceedingJoinPoint.getArgs();
Object proceed=null;
try {
System.out.println("环绕前通知"+name+"方法,参数是"+Arrays.asList(args));
//利用反射调用目标方法 就是method.invoke()
proceed = proceedingJoinPoint.proceed(args);
System.out.println("环绕返回通知"+name+"方法 返回值是"+proceed);
}catch (Throwable e){
System.out.println("环绕异常通知"+name+"方法 异常是"+e);
}finally {
System.out.println("环绕通知 "+name+"方法的后置通知");
}
//返回值
return proceed;
}
}
3、spring xml配置加入aop
<context:component-scan base-package="com.kdy"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、添加相关业务代码及测试代码
package com.kdy.tests;
import com.kdy.entity.User;
import com.kdy.service.IUserService;
import com.kdy.service.impl.UserServiceImpl;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void test01() throws Exception {
ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("classpath:/spring_aop.xml");
//UserServiceImpl bean = ioc.getBean(UserServiceImpl.class);
// IUserService bean = ioc.getBean(IUserService.class);
//Object bean = ioc.getBean("userServiceImpl");
//System.out.println(bean.getClass());
//class jdk.proxy2.$Proxy21 JDK动态代理类
//class com.kdy.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$9ae7e6fc
//没有代理使用cglib代理类
IUserService bean = ioc.getBean(IUserService.class);
bean.select(1);
System.out.println("#################");
bean.add(null);
}
}
AOP切点表达式
execultion(modifiter-pattern? ret-type-pattern decaaring-type-pattern? name-pattern(param-pattern) throw-pattern?)
切入点修饰符
execution: 切入点修饰符
还可以用 within 通过类名匹配,粗粒度的切入点表达式
@annotation() 匹配注解的切入点表达式
例子: @Before("within(com.kdy.service..)")
@annotation(java.lang.Override) //这个是错误的 因为Override 只在源码阶段存在 在class编译文件中可以看到没有@Override注解
访问修饰符
modifiter-pattern?
不写代表可以匹配任何访问修饰符
方法返回值
ret-type-pattern
如果切入点的方法返回值不一样可以用 * 代表任意返回值
自定义的要写完整的限定名
包名类名
decaaring-type-pattern?
* 代表任何包名 但是只能匹配一级
.. 代表子孙都可以匹配
类名可以写* 也可以写成*Impl进行部分匹配
方法名
name-pattern *代表任意方法
参数
自带可以写最后的限定名 自定义的要写完整限定名
如果匹配任意使用..
切入点表达式运算
支持 && || !三种常用运算关系
AOP 通知参数
JoinPoint joinPoint (连接点)
获取方法名 joinPoint.getSingnature().getName();
获取参数名 joinPoint.getArgs();
获取返回值 在注解中使用 returning = "returnValue" 指定 returnValue 为返回值
获取异常
在注解中使用 throwing="ex" 参数为 Excetion ex 捕获异常
简化切入点表达式
@PonitCut("execultion(......)") public void pointCut(){ }
@Before("pointCut()")
获取注解值
@Before("ponitCut() && @annotation(logger)") public void before(JoinPoint joinPoint,Logger logger){ ....... logger.注解参数名();//获取注解值 ...... }
环绕通知
1、proceeding 语义 一系列行动 2、包含了前置通知 后置返回通知 后置异常通知 后置通知 3、 proceed = proceedingJoinPoint.proceed(args); 实际调用执行方法 4、ProceedingJoinPoint 是 JoinPoint 的子类
@Around("pp()")
public Object arround(ProceedingJoinPoint proceedingJoinPoint){
String name = proceedingJoinPoint.getSignature().getName();
Object[] args = proceedingJoinPoint.getArgs();
Object proceed=null;
try {
System.out.println("环绕前通知"+name+"方法,参数是"+Arrays.asList(args));
//利用反射调用目标方法 就是method.invoke()
proceed = proceedingJoinPoint.proceed(args);
System.out.println("环绕返回通知"+name+"方法 返回值是"+proceed);
}catch (Throwable e){
System.out.println("环绕异常通知"+name+"方法 异常是"+e);
}finally {
System.out.println("环绕通知 "+name+"方法的后置通知");
}
//返回值
return proceed;
}