思路:
使用springaop实现
至于为什么要定义一个切入点到service包下面的所以方法,感兴趣的可以研究一下springAop的源码,里面有个postProcessBeforeInstantiation方法,会返回代理对象,如果没有则不会返回代理对象。
当然还有一种思路,就是在动态添加切入点的时候把spring容器中的对象替换成自己的代理对象(没有实验过,在非单例模式的时候有问题,这里不深入研究)。
引入aop的starter:
第一步:
第二步:
jar包怎么写?只需要实现对应的切面方法就行了
通常有方法前拦截,方法后拦截,以及异常拦截。通过在这些拦截中编写自己的业务处理,可以达到特定的需求。
execution表达式
20200401:添加注入applicationContext到jar里面
https://github.com/cdInit/aopHotPlugin
AOP配置,@EnableAspectJAutoProxy,@Before,@After,@AfterReturning,@AfterThrowingAOP:【动态代理】
指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式
1.导入aop模块Spring AOP:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.定义一个业务逻辑类(CalculateController)在业务逻辑运行的时候将日志进行打印(方法之前、方法运行结束、方法出现异常,xxx)
3.定义一个日志切面类(LogAop):切面类里面的方法需要动态感知CalculateController.calculateNum运行到哪里然后执行
通知方法:
前置通知(@Before):logStart:在目标方法(calculateNum)运行之前运行
后置通知(@After):logEnd:在目标方法(calculateNum)运行结束之后运行(无论方法正常结束还是异常结束)
返回通知(@AfterReturning):logReturn:在目标方法(calculateNum)正常返回之后运行
异常通知(@AfterThrowing):logException:在目标方法(calculateNum)出现异常以后运行
环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint.procced())
4.给切面类的目标方法标注何时何地运行(通知注解)
5.将切面类和业务逻辑类(目标方法所在类)都加入到容器中
6.必须告诉Spring哪个类是切面类(给切面类上加一个注解:@Aspect)
7.给配置类中加 @EnableAspectJAutoProxy 【开启基于注解的aop模式】
在Spring中很多的 @EnableXXX
三步:
1)将业务逻辑组件和切面类都加入到容器中告诉Spring哪个是切面类(@Aspect)
2)在切面类上的每一个通知方法上标注通知注解,告诉Spring何时何地运行(切入点表达式)
3)开启基于注解的aop模式@EnableAspectJAutoProxy
配置
// @EnableAspectJAutoProxy 开启基于注解的aop模式
@EnableAspectJAutoProxy
@Configuration
public class MyAopConfig {
@Bean
public CalculateController calculateController(){
return new CalculateController()
}
@Bean
public LogAop logAop(){
return new LogAop()
}
}
/**
* 切面类
*/
// @Aspect: 告诉Spring当前类是一个切面类
@Aspect
public class LogAop {
//抽取公共的切入点表达式
//1、本类引用
//2、其他的切面引用
@Pointcut("execution(public int com.example.studywork.work.controller.CalculateController.*(..))")
public void pointCut(){}
@Before(value ="pointCut()")
public void logStart(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName()+"方法运行前。。。参数列表是:{"+ Arrays.asList(joinPoint.getArgs())+"}")
}
// 外部切面类引用可以用全类名
@After("com.example.studywork.work.aop.LogAop.pointCut()")
public void logEnd(JoinPoint joinPoint){
System.out.println(joinPoint.getSignature().getName()+"方法结束。。。")
}
//JoinPoint一定要出现在参数表的第一位
@AfterReturning(value = "pointCut()",returning = "obj")
public void logReturn(JoinPoint joinPoint,Object obj){
System.out.println(joinPoint.getSignature().getName()+"方法正常返回。。。运行结果是:{"+obj+"}")
}
@AfterThrowing(value = "pointCut()",throwing = "e")
public void logxception(JoinPoint joinPoint,Exception e){
System.out.println(joinPoint.getSignature().getName()+"方法异常返回。。。异常结果是:{"+e+"}")
}
}
// 业务
public class CalculateController {
public int calculateNum(int i, int j){
System.out.println("CalculateController类的calculateNum方法正在运行")
return i/j
}
}
输出
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyAopConfig.class)
CalculateController bean = applicationContext.getBean(CalculateController.class)
bean.calculateNum(1,1)
}
输出结果
异常输出
@Test
public void test() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyAopConfig.class)
CalculateController bean = applicationContext.getBean(CalculateController.class)
bean.calculateNum(1,0)
}
输出结果
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)