关于java:Spring-AOP简介

44次阅读

共计 5449 个字符,预计需要花费 14 分钟才能阅读完成。

1.1 AOP 概述

1.1.1 AOP 是什么?

AOP 是一种设计思维, 是软件设计畛域的面向切面编程, 他是面向对象编程 OOP 的一种补充和欠缺. 它以通过预编译的形式和运行期动静代理形式, 实现在不批改源代码的状况下给程序动静对立增加额定性能的一种技术.

1.1.2 AOP 利用场景剖析?

理论我的项目中通常会将零碎分为两局部, 一部分是外围业务, 一部分是非核心业务. 在编程实现时咱们首先要实现的是外围业务的实现, 非核心业务咱们个别通过特定的形式切入到零碎中, 这种形式个别借助 AOP 实现.
AOP 就是要基于 OCP(开闭准则), 在不扭转原有系统核心业务代码的根底上动静增加一些扩大性能并能够管制对象执行. 例如 AOP 利用于我的项目中的日志解决, 事务处理, 权限解决, 缓存解决等等.

1.1.3 AOP 利用原理剖析

1)如果指标对象 (被代理对象) 实现接口, 则底层能够采纳 JDK 动静代理机制为指标对象创立代理对象(指标类和代理类会实现独特接口).
2)如果指标对象 (被代理对象) 没有实现接口, 则底层能够采纳 CGLIB 代理机制为指标对象创立代理对象(默认创立的代理类会继承指标对象类型).
AOP 在默认的状况下应用 CGLIB 代理, 退出应用 JDK 动静代理能够在配置文件 (application.properties) 中配置如下:
spring.aop.proxy-target-class=false

1.2AOP 相干术语剖析

切面(asprct): 横切面对象, 个别为一个具体类对象(能够借助 @Acpect 申明).
告诉(Advice): 在横切面的某个特定连接点上执行的动作(扩大性能), 例如 around,before,after 等.
连接点(joinpoint): 程序执行中的某个特定点个别指被拦挡到的办法.
切入点 (pointcut): 对多个连接点(Joinpoint) 一种定义, 个别能够了解为多个连接点的汇合.

2.Spring AOP 疾速实际

2.1 业务形容

基于我的项目中的外围业务, 简略增加日志操作, 借助 SLF4J 日志 API 输入指标办法的执行时长.(前提, 不能批改指标办法的代码 - 遵循 OCP 准则)

2.2 我的项目创立及配置

创立 maven 我的项目或在已有的我的项目根底上增加 AOP 启动依赖:
<dependency>

       <groupId>org.springframework.boot</groupId>

       <artifactId>spring-boot-starter-aop</artifactId>

</dependency>

阐明: 基于此依赖 spring 能够整合 AspectJ 框架快锁实现 AOP 的基本操作,AspectJ 是一个面向切面的框架, 它定义了 AOP 的一些语法, 有一个专门的本人吗生成器来生成恪守 java 标准的 class 文件.

2.3 扩大业务剖析及实现

2.3.1 创立日志切面类对象

将此日志切面类作为外围业务加强 (一个横切面对象) 类, 用于输入业务执行时长.
package com.cy.pj.common.aspect;

@Aspect

@Slf4j

@Component

public class SysLogAspect {@Pointcut("bean(sysUserServiceImpl)")

         public void logPointCut() {}


         @Around("logPointCut()")

         public Object around(ProceedingJoinPoint jp)

         throws Throwable{

                 try {log.info("start:{}"+System.currentTimeMillis());

                   Object result=jp.proceed();// 最终会调用指标办法

                   log.info("after:{}"+System.currentTimeMillis());

                   return result;

                 }catch(Throwable e) {log.error("after:{}",e.getMessage());

                   throw e;

                 }

         }
阐明:
@Aspect 注解用于标识或者形容 AOP 中切面类型, 基于切面类型构建的对象用于为指标对象进行性能扩大或控制目标对象的执行.
@Pointcut 注解用于形容切面中的办法, 并定义切面中的切入点,(基于特定表达式的形式进行形容).
@Around 注解用以形容切面中的办法, 这样的办法会被认为是一个盘绕告诉(外围业务办法执行之前和执行之后要执行的一个动作),@Around 注解外部 value 属性的值为一个切入点表达式或者是切入点表达式的一个援用(这个援用为 @Pointcut 注解形容的办法的办法名).
ProceedingJoinPoint 类作为一个连接点类型, 此类型的对象用于封装要执行的指标办法相干的一些信息. 只能用于 @Around 注解形容的办法参数.

2.3.1 业务切面测试实现

启动我的项目测试或者进行单元测试:
@SpringBootTest

public class AopTests {

         @Autowired

         private SysUserService userService;

         @Test

         public void testSysUserService() {

                 PageObject<SysUserDeptVo> po=

                 userService.findPageObjects("admin",1);

                 System.out.println("rowCount:"+po.getRowCount());

         }

}

2.4 扩大业务织入加强剖析

2.4.1 基于 JDK 代理形式实现

如果指标对象有实现接口, 则能够基于 JDK 为指标对象创立代理对象, 而后对指标对象进行性能扩大.

2.4.2 基于 CGLIB 代理形式实现

退出指标对象没有实现接口(当然实现了接口也是能够的), 能够基于 CGLIB 代理形式为指标对象织入性能扩大.
阐明: 指标对象实现了接口也能够基于 CGLIB 为指标对象创建对象.

3.Spring AOP 加强

3.1 切面告诉利用加强

3.1.1 告诉类型

在基于 Spring AOP 编程的过程中, 基于 AspectJ 框架规范,spring 中定义了五种类型的告诉(告诉形容是一种扩大业务), 它们别离是:
@Before
@AfterReturning
@AfterThrowing
@After
@Around 重点把握(优先级最高)
阐明: 在切面类中应用什么告诉, 由业务决定, 并不是说, 在切面中要把所有的告诉都写上.

3.1.2 告诉执行程序

阐明: 理论我的项目中可能不会在切面中定义所有告诉, 具体定义那些告诉要联合业务进行实现.

3.1.3 告诉实际过程剖析

@Component

@Aspect

public class SysTimeAspect {@Pointcut("bean(sysUserServiceImpl)")

        public void doTime(){}


        @Before("doTime()")

        public void doBefore(JoinPoint jp){System.out.println("time doBefore()");

        }

        @After("doTime()")

        public void doAfter(){System.out.println("time doAfter()");

        }

        /** 外围业务失常完结时执行 * 阐明:如果有 after,先执行 after, 再执行 returning*/

        @AfterReturning("doTime()")

        public void doAfterReturning(){System.out.println("time doAfterReturning");

        }

        /** 外围业务出现异常时执行阐明:如果有 after,先执行 after, 再执行 Throwing*/

        @AfterThrowing("doTime()")

        public void doAfterThrowing(){System.out.println("time doAfterThrowing");

        }

        @Around("doTime()")

        public Object doAround(ProceedingJoinPoint jp)

                        throws Throwable{System.out.println("doAround.before");

         try{Object obj=jp.proceed();

           System.out.println("doAround.after");

          return obj;

                 }catch(Throwable e){System.out.println(e.getMessage());

          throw e;

         }

                

        }

}
阐明: 对于 @AfterThrowing 告诉只有在呈现有异样时才会执行, 所以当做一些异样监控时可在此办法中进行代码实现.

3.2 切入点表达式加强

3.2.1bean 表达式(重点)

bean 表达式个别利用于类级别, 实现粗粒度的切入点定义, 案例剖析:
bean(“userServiceImpl”)指定一个 userServiceImpl 中的所有办法.
bean(“*ServiceImpl”)指定所有后缀为 ServiceImpl 的类中所有办法.
阐明:bean 表达式外部的对象是由 spring 容器治理的一个 bean 对象, 表达式外部的名字应该是 spring 容器中的某个 bean 的 name.

3.2.2within 表达式(理解)

within 表达式利用于类级别,实现粗粒度的切入点表达式定义,案例剖析:
within(“aop.service.UserServiceImpl”)指定以后包中这个类外部的所有办法.
within(“aop.service.*”) 指定当前目录下的所有类的所有办法.
within(“aop.service..*”) 指定当前目录以及子目录中类的所有办法.

3.2.3execution 表达式(理解)

execution 表达式利用于办法级别,实现细粒度的切入点表达式定义,案例剖析:
语法:execution(返回值类型 包名. 类名. 办法名(参数列表)).
execution(void aop.service.UserServiceImpl.addUser())匹配 addUser 办法。
execution(void aop.service.PersonServiceImpl.addUser(String)) 办法参数必须为 String 的 addUser 办法
execution( aop.service...*(..)) 万能配置.

3.2.4@annotation 表达式(重点)

@annontation(anno.RequiredLog)匹配有此注解形容的办法.
@annontation(anno.RequiredCache)匹配有此注解形容的办法.
其中:RequiredLog 为咱们自定义注解, 当咱们应用 @RequiredLog 注解润饰业务层办法时, 零碎底层会在执行此办法时进行日扩大操作.
: 定义一 Cache 相干切面, 应用注解表达式定义切入点, 并应用此注解对须要应用 cache 的业务办法进行形容, 代码剖析如下:
第一步: 定义注解 RequiredCache
package com.cy.pj.common.annotation;

/**

 * 自定义注解, 一个非凡的类, 所有注解都默认继承 Annotation 接口

 */

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface RequiredCache {//...}
第二步: 定义 SysCacheAspect 切面对象
package com.cy.pj.common.aspect;

@Aspect

@Component

public class SysCacheAspect {@Pointcut("@annotation(com.cy.pj.common.annotation.RequiredCache)")

          public void doCache() {}


          @Around("doCache()")

          public Object around(ProceedingJoinPoint jp)

    throws Throwable{System.out.println("Get data from cache");

                  Object obj=jp.proceed();

                  System.out.println("Put data to cache");

                  return obj;

          }

   

}
第三步: 应用 @RequiredCache 注解对特定业务指标对象中的查询方法进行形容.
 @RequiredCache

        @Override

        public List<Map<String, Object>> findObjects() {

                ….

                return list;

        }

3.3 切面优先级设置实现

切面的优先级须要借助 @Order 注解进行形容,数字越小优先级越高,默认优先级比拟低。例如:
定义日志切面并指定优先级
@Order(1)

@Aspect

@Component

public class SysLogAspect {…}
定义缓存切面并指定优先级
@Order(2)

@Aspect

@Component

public class SysCacheAspect {…}
阐明: 当多个切面作用于同一个指标对象办法时,这些切面会构建成一个切面链,相似过滤器链、拦截器链.

3.4 要害对象与术语总结

Spring 基于 AspectJ 框架实现 AOP 设计的要害对象概览,如图 -10 所示:

正文完
 0