0
点赞
收藏
分享

微信扫一扫

Spring Aop

Go_Viola 2022-02-05 阅读 69
spring aop与aspectJ的关系
1. Eclipse AspectJ,一种基于Java平台的面向切面编程语言
2. Spring Aop使用AspectJWeaver实现类与方法的匹配
3. Spring Aop利用代理模式实现对象运行时功能拓展

关键概念
1. Aspect 切面,去提的可插拔组件功能类,通常一个切面只实现一个通用功能
2. Target Class/Method 目标类、目标方法,指真正要执行与业务相关的方法
3. PointCut 切入点,使用execution表达式说明切面要作用在系统的那些类上
4. JoinPoint 连接点,切面运行过程中是包含了目标类/方法元数据的对象
5. Advice 通知,说明具体的切面的执行时机,Spring包含了五种不同类型通知

aop配置过程
1. 依赖AspectJ
        <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.13</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
</dependency>
2. 实现切面类/方法
package pers.thc.aop.aspect;

import org.aspectj.lang.JoinPoint;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Aspect {

public void printExecutionTime(JoinPoint joinPoint){
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
String dateStr = format.format(date);
String className = joinPoint.getTarget().getClass().getName();//获取目标类的名称
String methodName = joinPoint.getSignature().getName();//获取目标方法名称
System.out.println("--->执行时间:"+dateStr+" 执行类:"+className+" 执行方法:"+methodName);
Object[] args = joinPoint.getArgs();
System.out.println("--->参数个数:" + args.length);
for (Object arg : args) {
System.out.println("--->参数:" + arg);
}
}

public void doAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("<---返回后通知,返回值:"+ret);
}

public void doAfterThrowing(JoinPoint joinPoint, Throwable throwable) {
System.out.println("<---异常通知:"+throwable);
}
public void doAfter(JoinPoint joinPoint) {
System.out.println("<---触发后置通知");
}
}
3. 配置Aspect Bean
<bean id="aspect" class="pers.thc.aop.aspect.Aspect"/>
4. 定义PointCut
    <aop:config>
<!--PointCut切点,用execution来描述切面作用范围-->
<!--<aop:pointcut id="pointcut" expression="execution(public * pers.thc..*.*(..))"/>-->
<aop:pointcut id="pointcut" expression="execution(* pers.thc..*Service.*(..))"/>
<!--public可去-->

</aop:config>
5. 配置Advice
    <aop:config>
<!--PointCut切点,用execution来描述切面作用范围-->
<!--<aop:pointcut id="pointcut" expression="execution(public * pers.thc..*.*(..))"/>-->
<aop:pointcut id="pointcut" expression="execution(* pers.thc..*Service.*(..))"/>
<!--public可去-->
<!--定义切面-->
<aop:aspect ref="aspect">
<!--before通知(Advice),代表目标方法运行前执行切面类的切面方法-->
<aop:before method="printExecutionTime" pointcut-ref="pointcut"/>
<aop:after method="doAfter" pointcut-ref="pointcut"/>
<aop:after-returning method="doAfterReturning" returning="ret" pointcut-ref="pointcut"/>
<aop:after-throwing method="doAfterThrowing" throwing="throwable" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
JoinPoint核心方法
1. Objet getTarget():获取IoC容器内的目标对象
2. Signature getSignature():获取目标方法
3. Object[] getArgs():获取目标方法参数

PointCut切点表达式
1. 例子:      public void pers.thc.aop.service.UserService.generateRandomPassword(形参1,形参2,...)
2. execution(public   *     pers.thc ..           *      .         *             (   ..        ))
3. * -通配符 .. -包通配符 (..) -参数通配符
    
五种通知类型
1. Before Advice:前置通知,目标方法运行前执行
2. After Returning Advice:返回后通知,目标方法返回数据后执行
3. After Throwing Advice:异常通知,目标方法抛出异常后执行
4. After Advice:后置通知,目标方法运行后执行
5. Around Advice:最强大通知,自定义通知执行事迹,可决定目标方法是否运行

特殊的“通知”--引介增强
1. 引介增强(IntroductionInterceptor)是对类的增强,而非方法
2. 引介增强允许再运行时为目标类增加新属性或方法
3. 引介增强允许再运行时改变类的行为,让类随运行环境动态变更
Spring AOP 环绕通知实现步骤
1. 引入AspectJ依赖
2. 实现切面类:切面类引入ProceedingJoinPoint类对象,调用proceed()方法执行目标方法并获取Object类返回对象,return 返回对象,利用try-catch块环绕,catch块中将异常上抛
package pers.thc.aop.aspect;

import org.aspectj.lang.ProceedingJoinPoint;

import java.text.SimpleDateFormat;
import java.util.Date;

public class MethodChecker {
//ProceedingJoinPoint是JoinPoint的升级版,在原有功能外,还可以控制目标方法是否执行
public Object check(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
try {
long startTime = new Date().getTime();
Object ret = proceedingJoinPoint.proceed();//执行目标方法
long endTime = new Date().getTime();
long duration = endTime - startTime;
if (duration >= 1000) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String methodName = proceedingJoinPoint.getSignature().getName();
String className = proceedingJoinPoint.getTarget().getClass().getName();
String now = format.format(new Date());
System.out.println("========"+now+":"+className+"."+methodName+"("+duration+" ms)");
}
return ret;
} catch (Throwable throwable) {
System.out.println("Exception message:" + throwable.getMessage());
throw throwable;
}
}
}
3. 配置Aspect Bean
4. 定义pointcut
5. 配置Advice:选择环绕通知类型,例子:<aop:around method="check" pointcut-ref="pointcut"/>
     <bean id="methodChecker" class="pers.thc.aop.aspect.MethodChecker"/>
<aop:config>
<aop:pointcut id="pointcut" expression="execution(* pers.thc..*.*(..))"/>
<aop:aspect ref="methodChecker">
<!--环绕通知-->
<aop:around method="check" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
Spring Aop注解开发
1. 引入spring-context、aspectjweaver依赖
2. 在spring配置文件中添加组件扫描配置与aspectj自动代理配置
<?xml version="1.0" encoding="UTF-8"?>
<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"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
>

<context:component-scan base-package="pers.thc"/>
<!--启用Spring Aop注解模式-->
<aop:aspectj-autoproxy/>
</beans>
3. 在切面类上添加@Component与@Aspect注解
4. 在切面类方法上添加advice注解,并在其中填写切点表达式(如@Around(execution(......)))
package pers.thc.aop.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
@Component//标记当前类为组件
@Aspect//说明当前类是切面类
public class MethodChecker {
@Around("execution(public * pers.thc..*Service.*(..))")
public Object check(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
try {
long startTime = new Date().getTime();
Object ret = proceedingJoinPoint.proceed();
long endTime=new Date().getTime();
long duration=endTime-startTime;
if(duration>1000){
String className=proceedingJoinPoint.getTarget().getClass().getName();
String methodName=proceedingJoinPoint.getSignature().getName();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String now = format.format(new Date());
System.out.println("==========" + now + ":" + className + "." + methodName);
}
return ret;
} catch (Throwable throwable) {
System.out.println("Exception message:" + throwable.getMessage());
throw throwable;
}
}
}
 

 

举报

相关推荐

0 条评论