Spring AOP技术

概述:

主要对Spring的AOP技术进行一些解释和自己在学习过程中遇到的一些坑。。。

AOP是什么?

AOP(Aspect Oriented Programming)就是面向切面编程。其主要是利用“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,就是所谓的“切面”。
简单来说,就是我们可以通过AOP技术来对方法进行改进管理(例如可以为方法添加一些日志或者校验之类的),之前我们学习的的OOP技术是纵向的,而我们利用横向切入的方法在不影响之前代码结构的前提下对方法进行改进扩展。

1.AOP技术的核心概念

1).横切关注点
对哪些方法进行拦截,拦截后应该怎么处理,这些关注点称之为横切关注点
简单来说就是我们要进行代理的方法

2).切点(aspect)
切面就是对横切关注点的抽象,具体实现起来我们可以将每一个切点具体化
为一个类,然后在这个类中定义后置、前置等处理的方法

3).连接点(joinpoint)
连接点就是被拦截到的点,因为Spring只支持方法类型的连接点,
所以在Spring中连接点指的就是被拦截到的方法,
具体实现时我们可以通过JoinPoint来获取拦截方法的方法名,方法参数等具体信息
实际上连接点还可以是字段或者构造器

4).切入点(pointcut)
对连接点进行拦截的定义,
具体实现时,可以通过@Pointcut注解来定义要拦截的方法的具体信息
既可以在使用前置、后置通知等时代替 execution(…)

5).通知(advice)
通知就是在拦截到连接点(要拦截的方法)后要执行的代码
主要分为前置、后置、异常、返回、环绕五类

如何实现AOP?

接下来来看以下具体的代理类的实现(切面):

1. 声明切面
首先可以把一个切面具体化为一个类,既简单来说,切面就是一个类
然后可以在这个类当中声明要切入的方法(连接点)
然后需要使用@Component注解或者其子注解把这个类交给IOC容器进行管理,
并且还需要使用@Aspect注解表示这个bean是一个切面,然后IOC容器才能自动进行识别

@Aspect
@Component
public class Logging{
	...各种通知
}

2. 声明切入点
通过注解@Pointcut一个切入点,通过设置其value属性来设置要拦截的方法的具体信息(权限、返回值、包名、类名、方法名、参数类型)
可以为后面添加通知时省略很多代码,后面的通知直接使用Pointcut注解的方法就可以了
声明的方法不需要有任何方法体,使用时直接使用declareExecution()。

	@Pointcut(value = "execution(public int AOPTest.ComImpl.*(int,int))")
    public void declareExecution(){}

3.声明前置通知
通过注解Before表示此方法在方法运行之前运行
需要指定execution属性,为要添加日志的类(全类名)的某个方法或者所有方法
注意一定要具体到类!!!因为是对类的方法进行代理

	@Before("declareExecution()")
    public void beforeLogging(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Method begins with "+methodName);
    }

4.声明后置通知
通过@After注解表示该通知在指定方法执行完之后执行,
注意此处After注解不论程序运行是否出错,都会执行此方法,在此方法中不能对代理方法的结果进行处理,因为无法预知程序是否出错。

	@After("declareExecution()")
    public void endLogging(JoinPoint joinPoint){
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("Method ends with "+args);
    }

5.后置返回通知
@AfterReturning注解
此方法在程序正常运行,即将返回结果之前调用
在该方法中可以访问目标方法的返回结果,返回的结果用returning属性获取,
同时在处理的方法中还要增加一个Object类型的参数用来接收返回值
之后在方法中便可以直接使用返回值。

	@AfterReturning(value = "declareExecution()",returning = "result")
    public void afterReturn(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Method "+methodName+" return with "+result);
    }

6.后置异常通知
@AfterThrowing注解
在程序出现错误时执行,在try-catch块的打印错误之前执行该方法
可以通过Throwing属性来获取出现的错误,
然后在方法的参数中添加一个指定错误类型的参数,便可以对错误进行处理
并且可以通过指定错误类型来指定要处理的错误,
例如指定为NullPointer错误则只对空指针错误进行处理

	@AfterThrowing(value = "declareExecution()",throwing ="e" )
    public void afterError(JoinPoint joinPoint,ArithmeticException e){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Method "+methodName+" occur error: "+e);
    }

完成了这些就大功告成了嘛?of course not! 我们还需要配置XML文件,接下来看看怎么配置XML文件。
在XML文件中需要配置<context:component-scan/>并且指定所要扫描的包
这样才能将指定包中注解了的bean加载到XML文件中
然后还需要配置<aop:aspectj-autoproxy/>
表示声明自动为spring容器中那些配置@aspectJ切面的bean创建代理,织入切面。
但是实际的实现还是通过Proxy.newInstance()方法,只不过具体细节隐藏了。
注意在<aop:aspectj-autoproxy/>中还有一个proxy-target-class属性!
1.默认值为false:表示使用JDK动态代理,是对接口进行代理,返回的是接口!!!
如果代理的类没有实现任何接口,则会自动使用CGLib进行代理。
2.设置为true:表示使用CGLib进行代理,是对进行代理,返回的则是类。如果使用CGLib代理则需要引入相应的jar包。

		<!--注意添加context和aop命名空间还要指定xsi,我用的idea是自动添加的-->
		<context:component-scan base-package="AOPTest"></context:component-scan>
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

拓展:我们还可以使用@Order注解来设定切面的优先级,值越小,优先级越高,最小值为@Order(1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值