博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring AOP用法详解
阅读量:4031 次
发布时间:2019-05-24

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

什么是AOP

AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需 要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。报告代码往往分散在各个级别,不与该对象的基本功能有关,其他类型的代码也同样适用,例如安全、不寻常的处理和持续的透明度。这种 散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

而AOP技术则恰恰相反,它使用一种称为横切的技术来分解封装的对象,并将影响多个类的常见行为封装到一个可重用模块中,并将其名为 “Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,它易于减少系统的重复代码,降低模块之间的耦合度,有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果对象是中空圆柱体,则它封装对象的属性和行为。因此,面向方面的编程就像一个锋利的边缘,将这些空心圆柱体切割开来获得它们的内部信息。而切割表面就是所谓的“面”。然后,它恢复了切割表面没有留下任何痕迹与熟练的手。

AOP的术语

1.Join point(连接点)

Spring 官方文档的描述:

程序执行过程中的点,如方法的执行或异常的处理。在Spring AOP中,连接点总是表示方法执行。

2.Pointcut(切入点)

切入点是与连接点匹配的表达式,用于确定是否需要执行通知。Pointcut使用与连接点匹配的不同种类的表达式,Spring框架使用AspectJ切入点表达式语言

3.Advice(增强/通知)

通知指的是在拦截Joinpoint之后要做什么。通知分为事前通知、事后通知、异常通知、最终通知和环绕通知。

4.Aspect(切面)

Aspect切面表示Pointcut(切入点)和Advice(增强/通知)的结合

Spring AOP用法

示例代码:

/** * 设置登录用户名 */public class CurrentUserHolder {    private static final ThreadLocal
holder = new ThreadLocal<>(); public static String get() { return holder.get(); } public static void set(String user) { holder.set(user); }}/** * 校验用户权限 */@Service("authService")public class AuthServiceImpl implements AuthService { @Override public void checkAccess() { String user = CurrentUserHolder.get(); if(!"admin".equals(user)) { throw new RuntimeException("该用户无此权限!"); } }}/** * 业务逻辑类 */@Service("productService")public class ProductServiceImpl implements ProductService { @Autowired private AuthService authService; @Override public Long deleteProductById(Long id) { System.out.println("删除商品id为" + id + "的商品成功!"); return id; } @Override public void deleteProductByName(String name) { System.out.println("删除商品名称为" + name + "的商品成功!"); } @Override public void selectProduct(Long id) { if("100".equals(id.toString())) { System.out.println("查询商品成功!"); } else { System.out.println("查询商品失败!"); throw new RuntimeException("该商品不存在!"); } }}

1.使用within表达式匹配包类型

2.使用this、target、bean表达式匹配对象类型

//匹配AOP对象的目标对象为指定类型的方法,即ProductServiceImpl的aop代理对象的方法@Pointcut("this(com.aop.service.impl.ProductServiceImpl)")public void matchThis() {}//匹配实现ProductService接口的目标对象@Pointcut("target(com.aop.service.ProductService)")public void matchTarget() {}//匹配所有以Service结尾的bean里面的方法@Pointcut("bean(*Service)")public void matchBean() {}

3.使用args表达式匹配参数

//匹配第一个参数为Long类型的方法@Pointcut("args(Long, ..) ")public void matchArgs() {}

4.使用@annotation、@within、@target、@args匹配注解

5.使用execution表达式

执行表达式是我们开发过程中最常用的表达式。它的语法如下:

execution表达式
modifier-pattern:用于匹配访问修饰符,如public、private等。
ret-type-pattern:用于匹配返回值类型,不省略
declaring-type-pattern:用于匹配包类型
modifier-pattern(param-pattern):在匹配类中使用的方法不能被省略
throws-pattern:用于匹配抛出异常的方法

代码示例:

@Component@Aspectpublic class SecurityAspect {    @Autowired    private AuthService authService;    //匹配com.aop.service.impl.ProductServiceImpl类下的方法名以delete开头、参数类型为Long的public方法    @Pointcut("execution(public * com.aop.service.impl.ProductServiceImpl.delete*(Long))")    public void matchCondition() {}    //使用matchCondition这个切入点进行增强    @Before("matchCondition()")    public void before() {        System.out.println("before 前置通知......");        authService.checkAccess();    }}

单元测试:

运行结果(只有deleteProductById方法拦截成功):

查询商品成功!删除商品名称为衣服的商品成功!before 前置通知......java.lang.RuntimeException: 该用户无此权限!    at com.aop.service.impl.AuthServiceImpl.checkAccess(AuthServiceImpl.java:15)    at com.aop.security.SecurityAspect.before(SecurityAspect.java:50)

可以在多个表达式之间使用连接符匹配多个条件, 如使用||表示“或”,使用 &&表示“且”

//匹配com.aop.service.impl.ProductServiceImpl类下方法名以select或delete开头的所有方法@Pointcut("execution(* com.aop.service.impl.ProductServiceImpl.select*(..)) || " +            "execution(* com.aop.service.impl.ProductServiceImpl.delete*(..))")public void matchCondition() {}//使用matchCondition这个切入点进行增强@Before("matchCondition()")public void before() {   System.out.println("before 前置通知......");   authService.checkAccess();}

单元测试:

运行结果(所有方法均拦截成功):

before 前置通知......查询商品成功!before 前置通知......删除商品名称为衣服的商品成功!before 前置通知......删除商品id为100的商品成功!

6.Advice注解

Advice注解一共有5种,分别是:

①. @Before前置通知

前置通知在切入点运行前执行,不会影响切入点的逻辑

②. @After后置通知

在切入点的正常操作之后执行后通知。如果切入点引发异常,则在引发异常之前执行该异常。

③. @AfterThrowing异常通知

异常通知在切入点抛出异常前执行,如果切入点正常运行(未抛出异常),则不执行

④. @AfterReturning返回通知

返回通知在入口点正确运行之后执行,如果入口点抛出异常,则不执行。

⑤. @Around环绕通知

圆周通知是最强大的通知,您可以在执行入口点之前和之后自定义一些操作。环绕通知负责决定是继续处理连接点(调用ProceedingJoinPoint的.方法)还是中断执行

示例代码:

//匹配com.aop.service.impl.ProductServiceImpl类下面的所有方法    @Pointcut("execution(* com.aop.service.impl.ProductServiceImpl.*(..))")    public void matchAll() {}    @Around("matchAll()")    public Object around(ProceedingJoinPoint joinPoint) {        Object result = null;        authService.checkAccess();        System.out.println("befor 在切入点执行前运行");        try{            result = joinPoint.proceed(joinPoint.getArgs());//获取参数            System.out.println("after 在切入点执行后运行,result = " + result);        } catch (Throwable e) {            System.out.println("after 在切入点执行后抛出exception运行");            e.printStackTrace();        } finally {            System.out.println("finally......");        }       return result;    }

单元测试:

@Test    public void contextLoads() {        CurrentUserHolder.set("admin");        productService.deleteProductById(100L);        productService.selectProduct(10L);    }

运行结果:

在执行ProceedingJoinPoint对象的.方法之前,它等同于事前通知;在执行.方法之后,它等同于运行切入点(并且可以获得参数);在执行该方法之后,它等同于事后通知;如果通过运行切入点引发异常catch中的内容等效于AfterThrowing异常通知;不管切入点是否引发异常,final中的内容等效于AfterThrowing异常通知。通常,它将被执行。

转载地址:http://tzgbi.baihongyu.com/

你可能感兴趣的文章
Flex动态获取flash资源库文件
查看>>
flex中设置Label标签文字的自动换行
查看>>
Flex 中的元数据标签
查看>>
flex4 中创建自定义弹出窗口
查看>>
01Java基础语法-11. 数据类型之间的转换
查看>>
01Java基础语法-13. if分支语句的灵活使用
查看>>
01Java基础语法-15.for循环结构
查看>>
01Java基础语法-16. while循环结构
查看>>
01Java基础语法-17. do..while循环结构
查看>>
01Java基础语法-18. 各种循环语句的区别和应用场景
查看>>
01Java基础语法-19. 循环跳转控制语句
查看>>
Django框架全面讲解 -- Form
查看>>
socket,accept函数解析
查看>>
今日互联网关注(写在清明节后):每天都有值得关注的大变化
查看>>
”舍得“大法:把自己的优点当缺点倒出去
查看>>
[今日关注]鼓吹“互联网泡沫,到底为了什么”
查看>>
[互联网学习]如何提高网站的GooglePR值
查看>>
[关注大学生]求职不可不知——怎样的大学生不受欢迎
查看>>
[关注大学生]读“贫困大学生的自白”
查看>>
[互联网关注]李开复教大学生回答如何学好编程
查看>>