Spring框架分析(二)AOP应用原理分析

        上次对Spring中的IOC容器做了一个简单的分析,本篇文章,我在大概说一下我对Spring AOP的理解。

什么是AOP?

        首先说一说什么是AOP,我们知道OOP是面向对象编程,而AOP叫做面向切面编程,它是对面向对象编程的补充和完善,通过面向对象编程,我们可以再对象运行过程中,可以为对象动态织入一些扩展功能,比如,日志记录,权限控制,事务管理等。

AOP可以解决哪些问题?

        AOP目前被广泛应用于项目开发中,我们在一个项目中,一般会把项目分为几个功能模块,这些功能有核心功能,也有一些扩展功能,这些扩展功能的代码实现有可能是重复的,因此, 我们可以将重复代码抽离出来,对其进行封装,然后再需要的地方调用,这样的编程方式属于硬编码的方式,甚至还有可能需要修改原来的代码,这样就违反了开闭原则。这个时候我们就用到了AOP。
        我们可以利用面向切面编程的方式,在遵循开闭原则的基础上,为原有的系统添加一些扩展功能,并且可以控制对象的行为。

AOP底层原理分析

        AOP的底层是使用代理机制来实现功能扩展,主要使用的两种代理模式为:jdk动态代理和cglib代理。
        二者区别:jdk动态代理需要代理对象和被代理对象实现相同的接口,而cglib代理则是集成被代理对象来实现AOP的功能扩展。二者代理机制不同,但是在AOP中的应用是相同的,只要产生代理对象即可。
        我们知道,之前我们在Controller层注入Service接口的实现类,当请求过来时,Controller先找到Service接口,然后找到接口的实现类,在我们使用代理之后,我们的Service接口不会再直接去找他的实现类,而是去找实现类的代理对象。由代理对象来代替被代理对象来执行相应的操作。在执行相应操作之前,会先执行我们定义的切面类中的方法,也即是我们的扩展功能,以此来达到不修改原有代码而为系统添加扩展功能的目的。
        如下图:是jdk动态代理和cglib代理
在这里插入图片描述在这里插入图片描述

AOP编程的基本步骤

第一步导入依赖:
     <dependency>
       		 <groupId>org.springframework.boot</groupId>
      		 <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>

        我这里是在Springboot中引入依赖,这是Spring整合AOP的依赖。如果不是SpringBoot项目需要导入以下依赖:
        1.org.springframework.aop-3.1.1.RELEASE 这个是spring的 AOP编程必备包
        2.cglib-nodep-2.1_3
        3.aspectjweaver-1.6.2
        4.aspectj-1.6.12
        5.aopalliance-1.0
        这是Maven仓库的网站 https://mvnrepository.com/

第二步创建切面处理类

        切面处理类有两部分构成,一个是切入点,使用注解@Pointcut注解来标识,一个是扩展方法使用@Around,@Before等注解来标识。代码如下:

@Aspect
@Component
@Slf4j
public class SysLogAspect {
	 /**
	  * @Pointcut注解用于定义切入点
	  * bean表达式为切入点表达式,
	  * bean表达式内部指定的bean对象中
	    *   所有方法为切入点(进行功能扩展的点)
	  */
	 @Pointcut("bean(sysUserServiceImpl)")
	 public void logPointCut() {}
	 /**
	  * @Around 描述的方法为环绕通知,用于功能增强
	    *   环绕通知(目标方法执行之前和之后都可以执行)
	  * @param jp 连接点 (封装了要执行的目标方法信息)
	  * @return 目标方法的执行结果
	  * @throws Throwable
	  */
	 @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(e.getMessage());
		   throw e;
		 }
	 }
}

        其中:
        @Aspect 注解用于标识此类为一个AOP横切面对象
        @Component是把此切面类交给Spring管理
        @Pointcut 注解用于定义本类中的切入点,本案例中切入点表达式用的是        bean表达式,这个表达式以bean开头,bean括号中的内容为一个spring管理的某个bean对象的id。指定了为哪一个类添加扩展功能
        @Around用于定义一个环绕通知(满足切入点表达式的核心业务方法执行之前和之后执行的一个操作)
        @Slf4j是我使用了log4j实现日志输出,于AOP无关。因为我做的是一个日志功能增强,所以用到了这个。
        切面术语:用于封装扩展业务的一个类的对象。
        通知术语:切面扩展业务中的一个操作(方法)。
        这样一个AOP切面功能增强就完成了。上边代码,我为SysUserServiceImpl添加了一个日志处理功能,输出SysUserServiceImpl中方法的执行时间。这样就在不修改原来代码的基础上添加了扩展功能,这就是AOP面向切面编程。

AOP中的切入点表达式

        在Spring中通过切入点表达式定义具体切入点,为指定位置添加扩展功能。一下是Sprng中的几个切入点表达式:

指示符作用
bean用于匹配指定bean id的的方法执行
within用于匹配指定包名下类型内的方法执行
execution用于进行细粒度方法匹配执行具体业务
@annotation用于匹配指定注解修饰的方法执行
Bean表达式应用

bean表达式应用于类级别,实现粗粒度的切入点定义

形式作用
bean(“userServiceImpl”))指定一个类中所有方法
bean("*ServiceImpl")指定所有的后缀为serviceImpl的类

        说明:bean表达式内部的对象是由spring容器管理的一个bean对象,表达式内部的内部的名字应该时spring容器中某个bean的key.

within表达式应用

        within表达式应用于类级别,实现粗粒度的切入点表达式定义:

形式作用
within(“aop.service.UserServiceImpl”)指定类,只能指定一个类
within(“aop.service.*”)只包括当前目录下的类
within(“aop.service . .*”)指定当前目录包含所有子目录中的类
execution 表达式应用

        execution表达式应用于方法级别,细粒度的切入点表达式定义
        语法:execution(返回值类型 包名.类名.方法名(参数列表))

形式作用
execution(void aop.service.UserServiceImpl.addUser())匹配方法
execution(void aop.service.PersonServiceImpl.addUser(String))方法参数必须为字符串
within(“aop.service. * . *”)万能配置
@annotation表达式应用

@annotaion表达式应用于方法级别,实现细粒度的切入点表达式定义:

形式作用
@annotation(com.jt.common.anno.RequestLog)指定一个需要实现增强功能的方法

其中:RequestLog为我们自己定义的注解,当我们使用@RequestLog注解修饰业务层方法时,系统底层会在执行此方法时进行扩展操作.它只能指定被注解修饰的方法。

AOP中的通知类型

        在AOP编程中有五种类型的通知:
        1)前置通知 (@Before) 方法执行之前执行
        2)返回通知 (@AfterReturning) 方法return之后执行
        3)异常通知 (@AfterThrowing) 方法出现异常之后执行
        4)后置通知 (@After) : 又称之为最终通知(finally)
        5)环绕通知 (@Around)
        其中环绕通知@Around的优先级最高的通知,被@Around通知修饰的方法会优先执行,然后依次是:@Before、@AfterReturning@AfterThrowing、@After。
        另外还有一个注解是@Order,当有多个切面类时可能会用到这个注解,这个注解中可以配置一个Vauel属性值,int类型,数值越小,切面的优先级为越高,优先级高的切面会优先执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值