Spring基础使用六
基于注解的AOP
使用AspectJ注解层
具体实现层:
- 动态代理:有接口情况
- cglib:没接口情况
- 动态代理:JDK原生的实现方式,需要被代理的目标类必须实现接口。因为这个技术要求代理对象和目标对象实现同样的接口。
- cglib:通过继承被代理的目标类实现代理,所以不需要目标类实现接口。
- AspectJ:本质上是静态代理,将代理逻辑“织入”被代理的目标类编译得到的字节码文件,所以最终效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。
Aspect
-
- 在切面中,需要通过指定的注解将方法标识为通知方法
- @Before:前置通知,在目标对象方法执行之前执行
- @After:后置通知,在目标对象的方法执行之后执行
- @AfterReturning:返回通知,在目标对象方法返回值返回之后执行
- @AfterThrowing:异常通知,在目标对象方法的catch字句中执行
- @Around:环绕通知
-
- 切入点表达式:
- @Before("execution(public int com.wfy.aop.annotation.CalculatorImpl.add(int, int))")
- 简写表达式:
- @Before("execution(* com.wfy.aop.annotation.CalculatorImpl.*(..))")
- 第一个*表示任意的访问修饰符和返回值类型
- 第二个*表示类中任意的方法
- ..表示任意的参数列表
- 类的地方也可以使用*,表示包下所有的类
-
- 重用切入点表达式
- //@Pointcut就是用来声明一个公共的切入点表达式
- @Pointcut("execution(* com.wfy.aop.annotation.CalculatorImpl.*(..))")
-
public void pointCut(){}
- 使用方式: @Before("pointCut()")
-
- 获取连接点信息
- 在通知方法的参数位置,设置JoinPoint类型的参数,就可以获取连接点所对应方法的信息
- //获取连接点所对应方法的签名信息
- Signature signature = joinPoint.getSignature();
- //获取连接点所对应方法的参数
- Object[] args = joinPoint.getArgs();
- 5.切面的优先级
- 可以通过@Order注解的value属性设置优先级,默认值Integer的最大值
- @Order注解的value属性值越小,优先级越高
导入项目依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wfy</groupId>
<artifactId>spring-05-aop</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--基于Maven依赖传递性,导入spring-context依赖即可导入当前所需所有jar包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
<!--junit测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- spring-aspects会帮我们传递过来aspectjweaver-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.23</version>
</dependency>
</dependencies>
</project>
映射文件
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--
AOP的注意事项:
切面类和目标类都需要交给IOC容器进行管理
切面类必须通过@Aspect注解标识为一个切面
在Spring的配置文件中设置<aop:aspectj-autoproxy/>开启基于注解的aop
-->
<context:component-scan base-package="com.wfy.aop.annotation"></context:component-scan>
<!--开启基于注解的aop功能-->
<aop:aspectj-autoproxy/>
</beans>
接口
package com.wfy.aop.annotation;
public interface Calculator {
int add(int i , int j);
int sub(int i,int j);
int mul(int i , int j);
int div(int i , int j);
}
实现类
package com.wfy.aop.annotation;
import org.springframework.stereotype.Component;
@Component
public class CalculatorImpl implements Calculator {
@Override
public int add(int i, int j) {
int result = i + j;
System.out.println("方法内部 , result: "+result);
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
System.out.println("方法内部 , result: "+result);
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
System.out.println("方法内部 , result: "+result);
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
System.out.println("方法内部 , result: "+result);
return result;
}
}
LoggerAspect代理切面
package com.wfy.aop.annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Component
@Aspect //将当前组件标识为切面
public class LoggerAspect {
@Pointcut("execution(* com.wfy.aop.annotation.CalculatorImpl.*(..))")
public void pointCut(){}
@Before("pointCut()")
// @Before("execution(public int com.wfy.aop.annotation.CalculatorImpl.add(int, int))")
public void beforeAdviceMethod(JoinPoint joinPoint){
//获取连接点所对应方法的签名信息
Signature signature = joinPoint.getSignature();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("LoggerAspect , 方法:"+signature.getName()+", 参数类型: "+ Arrays.toString(args));
}
@After("pointCut()")
public void afterAdviceMethod(JoinPoint joinPoint){
//获取连接点所对应方法的签名信息
Signature signature = joinPoint.getSignature();
//获取连接点所对应方法的参数
Object[] args = joinPoint.getArgs();
System.out.println("LoggerAspect, 后置 , 方法: "+signature.getName()+", 参数类型: "+Arrays.toString(args));
}
/*
* 在返回通知中若要获取目标对象方法的返回值
* 只需要通过@AfterReturning注解中的returning属性
* 就可以将通知方法的某个参数指定为接收目标对象方法的返回值的参数
* */
@AfterReturning( value = "pointCut()", returning = "result")
public void afterReturningAdviceMethod( Object result){
System.out.println("LoggerAspect , 返回通知 , 结果: "+result);
}
/*
* 在异常通知中若要获取目标对象方法的异常
* 只需要通过@AfterThrowing注解中的throwing属性
* 就可以将通知方法的某个参数指定为接收目标对象方法出现的异常的参数
* */
@AfterThrowing(value = "pointCut()" , throwing = "ex")
public void afterThrowingAdviceMethod( JoinPoint joinPoint , Throwable ex){
//获取连接点对应方法的签名信息
Signature signature = joinPoint.getSignature();
System.out.println("LoggerAspect, 方法:"+signature.getName()+",异常通知 , 异常:"+ex);
}
@Around("pointCut()")
//环绕通知的方法的返回值一定要和目标对象方法的返回值一致
public Object aroundAdviceMethod(ProceedingJoinPoint proceedingJoinPoint){
Object result = null;
try {
System.out.println("环绕通知-----前置通知");
//表示目标对象方法的执行
result= proceedingJoinPoint.proceed();
System.out.println("环绕通知-----返回通知");
} catch (Throwable e ) {
e.printStackTrace();
System.out.println("环绕通知-----异常通知");
}finally {
System.out.println("环绕通知-----后置通知");
}
return result;
}
}
测试
package com.wfy.spring.annotation;
import com.wfy.aop.annotation.Calculator;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AOPTest {
@Test
public void AopByAnnotationTest(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("aop-annotation.xml");
Calculator bean = ioc.getBean(Calculator.class);
bean.add(1,1);
}
}
切面优先级
package com.wfy.aop.annotation;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect//标识为一个切面
@Order(1)//设置切面的优先级,数字越小优先级越高
public class ValidateAspect {
@Before("com.wfy.aop.annotation.LoggerAspect.pointCut()")
public void beforeMethod(){
System.out.println("ValidateAspect ---- 前置通知");
}
}
标签:int,Spring,org,基础,annotation,result,使用,import,public
From: https://www.cnblogs.com/wfy-studying/p/16838717.html