博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AOP - 2 实例(SpringBoot 注解方式)
阅读量:5084 次
发布时间:2019-06-13

本文共 6079 字,大约阅读时间需要 20 分钟。

  1、创建Spring Boot项目

  创建一个Spring Boot 项目,然后pom中引入web 模块与AOP相关依赖。

org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-aop
2.0.1.RELEASE
org.aspectj
aspectjweaver
1.8.13

其中: 

aspectjweaver是与aspectj相关的包,用来支持切面编程的; 
aspectjweaver是aspectj的织入包;

 

2、实现一个web请求,数据通过接口获取(使用POJO类传参与返回值)

@RestController@RequestMapping("/aop")public class AopController {    @Autowired    private AopService aopService;    @GetMapping(value = "getResult")    public ResultVO sayHello(ParamVO paramVO) {        ParamDTO paramDTO = new ParamDTO();        BeanUtils.copyProperties(paramVO, paramDTO);        ResultDTO resultDTO = aopService.getResult(paramDTO);        ResultVO resultVO = new ResultVO();        BeanUtils.copyProperties(resultDTO, resultVO);        return resultVO;    }}

  

列出一个POJO类,其他类似。返回给前端的统一使用VO,业务逻辑层之间的传递使用DTO,映射数据库的使用Domain:

public class ParamVO {    private String name;    private Integer age;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    @Override    public String toString() {        return "ParamVO{" +                "name='" + name + '\'' +                ", age=" + age +                '}';    }}

 

 3、web请求对应的接口

import cn.latiny.modules.aopone.model.ParamDTO;import cn.latiny.modules.aopone.model.ResultDTO;public interface AopService {    ResultDTO getResult(ParamDTO param);}
@Servicepublic class AopServiceImpl implements AopService {    @Override    public ResultDTO getResult(ParamDTO param) {        ResultDTO result = new ResultDTO();        result.setId(1001);        result.setMessage(param.toString());        result.setData(Arrays.asList("Latiny", "30", "20000"));        return result;    }}

 

  4、定义一个切面类,实现对Service方法进行切面

把一个类变成切面类,需要两步: 

① 在类上使用 @Component 注解 把切面类加入到IOC容器中 
② 在类上使用 @Aspect 注解 使之成为切面类

/** * @description AopService切面类 */@Aspect@Componentpublic class AopServiceAspect {    private final Logger logger = LoggerFactory.getLogger(AopService.class);}

 

  (1) 定义一个切入点

  这里我们对AopService的getResult() 方法进行切面编程。

/**     * 定义一个切入点     */    @Pointcut("execution(* cn.latiny.modules.aopone.service.AopService.getResult(..))")    public void pointCut() {    }

  

  (2) 定义一个前置通知

/**     * 前置通知     * @param joinPoint     * @param name     */    @Before("pointCut() && args(name)")    public void before(JoinPoint joinPoint, String name) {        Object[] parameters = joinPoint.getArgs();        String methodName = joinPoint.getSignature().getName();        System.out.println(methodName + "方法 Before通知,方法的参数: " + name);    }

我们通过注解@Before结合切入点完成对getResult() 方法的切面,在before() 方法里,我们可以在getResult() 执行前做任何想做的事。在这个方法里,我们通过JoinPoint可以得到对应切入点的目标对象的所有信息,类名,方法名,方法参数名以及传递的值。

 

  (3) 其他通知的定义

/**     * 后置通知,异常时不执行     * @param joinPoint     * @param name     */    @AfterReturning(value = "pointCut() && args(name)", returning = "result")    public void afterReturning(JoinPoint joinPoint, String result, String name) {        String methodName = joinPoint.getSignature().getName();        System.out.println(methodName + "方法 AfterReturning通知,方法的参数: " + name + ", 方法返回值:" + result);    }    /**     * 后置通知,不管对应的连接点方法是否正常执行,都会执行此通知     * @param joinPoint     * @param name     */    @After(value = "pointCut() && args(name)")    public void after(JoinPoint joinPoint, String name) {        String methodName = joinPoint.getSignature().getName();        System.out.println(methodName + "方法 After通知,方法的参数: " + name);    }    /**     * 环绕通知,在不修改原来方法的前提下,可以在方法执行前修改方法的入参,也可以在方法执行之后修改方法的返回值。     * 环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。     * 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型     * @param joinPoint     * @return     */    @Around("pointCut()")    public Object around(ProceedingJoinPoint joinPoint) {        System.out.println(joinPoint.getSignature().getName() + "方法 Around通知开始");        processInputArg(joinPoint.getArgs());        try {            Object obj = joinPoint.proceed();            processOutputObj(obj);            if(obj instanceof ResultDTO) {                ResultDTO resultDTO = (ResultDTO) obj;                System.out.println("修改后的返回值:" + resultDTO.toString());            }            System.out.println(joinPoint.getSignature().getName() + "方法 Around通知结束");            return obj;        } catch (Throwable throwable) {            throwable.printStackTrace();        }        System.out.println(joinPoint.getSignature().getName() + "方法 Around通知结束");        return null;    }    /**     * 处理输入参数     */    private void processInputArg(Object[] args) {        for(Object arg: args) {            System.out.println("参数原来的值为:" + arg.toString());            if (arg instanceof ParamDTO) {                ParamDTO param = (ParamDTO)arg;                param.setAge(18);                param.setName("Nowesiki");            }            System.out.println("参数修改的值为:" + arg.toString());        }    }    /**     * 返回值处理     * @param obj     */    private void processOutputObj(Object obj) {        if(obj instanceof ResultDTO) {            ResultDTO result = (ResultDTO) obj;            result.setId(1002);            result.setMessage(result.getMessage());            result.setData(Arrays.asList("Nowesike", "40", "1000000000"));        }    }

 

  5、测试

  这里测试一下环绕通知,其他的通知暂时注释掉,启动项目之后,直接在浏览器访问AopController接口即可。

  这里前端传的参数是,name = 马云,age = 44

  

  最后的结果是:

getResult方法 Around通知开始参数原来的值为:ParamVO{name=马云, age=44}参数修改的值为:ParamVO{name=Nowesiki, age=18}修改后的返回值:ResultDTO{id=1002, message='ParamVO{name=Nowesiki, age=18}', data=[Nowesike, 40, 1000000000]}getResult方法 Around通知结束

  环绕通知里不仅可以获取到目标对象的所有信息,还能改变目标对象的入参与返回值,功能非常强大。

 

  

转载于:https://www.cnblogs.com/Latiny/p/10703520.html

你可能感兴趣的文章
数据库链路创建方法
查看>>
Enterprise Library - Data Access Application Block 6.0.1304
查看>>
重构代码 —— 函数即变量(Replace temp with Query)
查看>>
Bootstrap栅格学习
查看>>
程序员的数学
查看>>
聚合与组合
查看>>
jQuery如何获得select选中的值?input单选radio选中的值
查看>>
设计模式 之 享元模式
查看>>
如何理解汉诺塔
查看>>
洛谷 P2089 烤鸡【DFS递归/10重枚举】
查看>>
15 FFT及其框图实现
查看>>
Linux基本操作
查看>>
osg ifc ifccolumn
查看>>
C++ STL partial_sort
查看>>
3.0.35 platform 设备资源和数据
查看>>
centos redis 安装过程,解决办法
查看>>
IOS小技巧整理
查看>>
WebDriverExtensionsByC#
查看>>
我眼中的技术地图
查看>>
lc 145. Binary Tree Postorder Traversal
查看>>