面向切面编程 c语言,SpringBoot之AOP面向切面编程实例(普通类方法和自定义注解方法)...

在进入实例之前,可以先看我引用的另一篇文章:

一.   SpringBoot引入AOP依赖

引入依赖:

org.springframework.boot

spring-boot-starter-aop

二.    创建AOP切面类,直接上代码

这里为了简单明了,我将切面类分为普通类方法切面和自定义注解方法切面

1.    普通类方法切面类

package com.example.demo.aop;

import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.*;

import org.springframework.stereotype.Component;

import java.util.Arrays;

import java.util.List;

/**

* @program: demo

* @description: 描述UserService切面类

* @author: guoxu

* @create: 2019-12-23 14:22

*/

@Slf4j

@Aspect

@Component

public class AopUserServiceAspect {

/**

* 1.通配符

* [*] 匹配任意字符,但只能匹配一个元素

* [..] 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用

* [+] 必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类

* 切点表达式分为 修饰符 返回类型 包路径 方法名 参数

* 2.切点表达式

* 3.逻辑运算符

* 表达式可由多个切点函数通过逻辑运算组成

* && 与操作,求交集,也可以写成and

* 例如 execution(* chop(..)) && target(Horseman) 表示Horseman及其子类的chop方法

* || 或操作,任一表达式成立即为true,也可以写成 or

* 例如 execution(* chop(..)) || args(String) 表示名称为chop的方法或者有一个String型参数的方法

* ! 非操作,表达式为false则结果为true,也可以写成 not

* 例如 execution(* chop(..)) and !args(String) 表示名称为chop的方法但是不能是只有一个String型参数的方法

*/

/**

* 切点为UserServiceImpl类下的queryUser方法

* "execution(* com.example.demo.service.impl.UserServiceImpl.queryUser())"

*

* 切点为UserServiceImpl类下的所有带任意参数的方法

*/

@Pointcut("execution(* com.example.demo.service.impl.UserServiceImpl.*(..))")

public void userServicePoc(){

}

/**

* 环绕通知在 target 开始和结束执行

* 如果在环绕通知方法中有异常捕获,则会直接捕获异常,不会再向外抛出

* @param point

* @return

*/

// @Around(value = "userServicePoc()")

// public Object around(ProceedingJoinPoint point) {

// long start = System.currentTimeMillis();

// //获取切点执行的方法

// String methodName = point.getSignature().getName();

// log.info("around method name: {} params: {}", methodName, Arrays.asList(point.getArgs()));

// try {

// log.info("around end time: {}", (System.currentTimeMillis() - start) + " ms!");

// return point.proceed();

// } catch (Throwable e) {

// log.error("message: {}", e.getMessage());

// }

// return null;

// }

/**

* * 前置通知在 target 前执行

* @param joinPoint

*/

// @Before("@annotation(com.leone.boot.aop.anno.AopBefore)")

// @Before("within(com.leone.boot.aop.controller.*)")

// @Before("@within(org.springframework.web.bind.annotation.RestController)")

// @Before("target(com.leone.boot.aop.controller.UserController)")

@Before(value = "userServicePoc()")

public void beforeMethod(JoinPoint joinPoint) {

String methodName = joinPoint.getSignature().getName();

List args = Arrays.asList(joinPoint.getArgs());

log.info("before inform method name: {} param: {}", methodName, args);

}

/**

* 后置通知在target后执行

*

* @param joinPoint

*/

//@After("@args(org.springframework.stereotype.Component) &&execution(* com.leone.boot.aop.controller.*.*(..))")

@After(value = "userServicePoc()")

public void afterMethod(JoinPoint joinPoint) {

String methodName = joinPoint.getSignature().getName();

List args = Arrays.asList(joinPoint.getArgs());

log.info("after inform method name : {} param: {}", methodName, args);

}

/**

* 在target执行成功返回后执行

*

* @param joinPoint

* @param result

*/

//@AfterReturning(value = "within(com.leone.boot.aop.controller.*)", returning = "result")

@AfterReturning(value = "userServicePoc()",returning = "result")

public void afterReturning(JoinPoint joinPoint, Object result) {

String methodName = joinPoint.getSignature().getName();

log.info("afterReturning inform method name: {} return value: {}", methodName, result);

}

/**

* 在target抛出异常后执行

*

* @param joinPoint

* @param ex

*/

//@AfterThrowing(value = "args(com.leone.boot.common.entity.User) &&execution(* com.leone.boot.aop.controller.*.*(..))", throwing = "ex")

@AfterThrowing(value = "userServicePoc()",throwing = "ex")

public void afterThrowing(JoinPoint joinPoint, Exception ex) {

String methodName = joinPoint.getSignature().getName();

log.info("afterThrowing inform method name: {} exceptions: {}",methodName, ex);

}

}

2.    自定义注解方法切面类

1.    自定义注解

package com.example.demo.aop;

import java.lang.annotation.*;

/**

* 自定义注解,拦截service

* 注解@Target说明了Annotation所修饰的对象范围

*

* 注解@Retention定义了该Annotation被保留的时间长短:

* 1.SOURCE:在源文件中有效(即源文件保留)

* 2.CLASS:在class文件中有效(即class保留)

* 3.RUNTIME:在运行时有效(即运行时保留)

*

* 注解@Documented 定义注解会被javadoc或者其他类似工具文档化

* @author guoxu

*/

//自定义注解描述方法

@Target({ElementType.PARAMETER, ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface SystemServiceLog {

/**

* 自定义注解参数

*/

String description() default "";

}

2.    自定义切面类

package com.example.demo.aop;

import com.example.demo.controller.UserController;

import com.example.demo.service.impl.UserServiceImpl;

import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

import org.springframework.stereotype.Component;

import java.util.Arrays;

import java.util.List;

/**

* @program: demo

* @description: 描述自定义注解切面类

* @author: guoxu

* @create: 2019-12-23 14:22

*/

@Slf4j

@Aspect

@Component

public class AopAnnotationAspect {

private static String userService = UserServiceImpl.class.getName();

private static String userController = UserController.class.getName();

/**

* 自定义注解Controller层切点

*/

@Pointcut("@annotation(SystemControllerLog)")

public void annoControllerPointCut() {}

/**

* 自定义注解Service层切点

*/

@Pointcut("@annotation(SystemServiceLog)")

public void annoServicePointCut() {}

@After("annoServicePointCut()")

public void afterServiceMethod(JoinPoint joinPoint){

//获取拦截到执行的方法名称

String methodName = joinPoint.getSignature().getName();

// 获取拦截到操作的service类名

String targetName = joinPoint.getTarget().getClass().getName();

//获取切点方法的参数列表

List args = Arrays.asList(joinPoint.getArgs());

log.info("自定义注解SystemServiceLog切点方法->{},方法参数->{}",methodName,args);

if (targetName.equals(userService)){

log.info("UserServiceImpl切点方法->{},方法参数->{}",methodName,args);

}

}

@After("annoControllerPointCut()")

public void afterControllerMethod(JoinPoint joinPoint){

//获取拦截到执行的方法名称

String methodName = joinPoint.getSignature().getName();

// 获取拦截到操作的service类名

String targetName = joinPoint.getTarget().getClass().getName();

//获取切点方法的参数列表

List args = Arrays.asList(joinPoint.getArgs());

if (targetName.equals(userController)){

log.info("自定义注解SystemControllerLog切点方法->{},方法参数->{}",methodName,args);

}

}

}

调用自定义注解的方法,即进入相应切点,执行切点方法内容。

三.    注意事项

1.    自定义方法注解,不能放在Interface中,即注解接口方法不生效。

如:

public interface IUserService {

/**

* 查询用户列表

* @return

* @throws Exception

*/

@SystemServiceLog(description = "用户列表") //此自定义注解不生效,不进入切点

List queryUsers() throws Exception;

}

2.    自定义方法注解只能作用于直接调用的方法,继承父类的自定义注解不生效。

如:

public class UserServiceImpl extends BaseServiceImpl implements IUserService {

@Override

public List queryUsers() throws Exception {

return query();

}

}

public class BaseServiceImpl implements IBaseService{

...

@Override

@SystemServiceLog(description = "查询对象列表")

public List query() {

return nutzDao.query(entityClass, null);

}

}

//因直接调用 UserServiceImpl 类中的queryUsers方法,故其父类中的 query自定义注解不生效。

//正确的自定义注解方式

public class UserServiceImpl extends BaseServiceImpl implements IUserService {

@Override

@SystemServiceLog(description = "查询对象列表")

public List queryUsers() throws Exception {

return query();

}

}

参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值