spring-aop切面知识

一、AOP的概念

AOP(Aspect Oriented Programming),即为面向切面编程。在软件开发中,散布于应用中多处的

功能被称为横切关注点(cross-cutting concern),通常来说,这些横切关注点从概念上是与应用的业务

逻辑分离的。比如,声明式事务、日志、安全、缓存等等,都与业务逻辑无关,可以将这些东西抽象成

为模块,采用面向切面编程的方式,通过声明方式定义这些功能用于何处,通过预编译方式和运行期动

态代理实现这些模块化横切关注点程序功能进行统一维护,从而将横切关注点与它们所影响的对象之

间分离出来,就是实现解耦。

横切关注点可以被模块化为特殊的类,这些类被称为切面(aspect)。这样做有两个优点:

1)每个关注点都集中于一个地方,而不是分散到多处代码中;

2)服务模块更简洁,因为它们只包含主要的关注点的代码(核心业务逻辑),

而次要关注点的代码(日志,事务,安全等)都被转移到切面中。

通知(Advice)

切面类有自己要完成的工作,切面类的工作就称为通知。通知定义了切面是做什么以及何时使用。

"做什么",即切面类中定义的方法是干什么的;

"何时使用",即5种通知类型,是在目标方法执行前,还是目标方法执行后等等;

"何处做",即通知定义了做什么,何时使用,但是不知道用在何处,而切点定义的就是告诉通知应该用在

哪个类的哪个目标方法上,从而完美的完成横切点功能。

Spring切面定义了5种类型通知:

1)前置通知(Before):在目标方法被调用之前调用通知功能。

2)后置通知(After):在目标方法完成之后调用通知,不会关心方法的输出是什么。

3)返回通知(After-returning): 在目标方法成功执行之后调用通知。

4)异常通知(After-throwing):在目标方法抛出异常后调用通知。

5)环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和之后执行自定义的行为。

切面(Aspect)

切面是通知和切点的结合,通知和切点共同定义了切面的全部内容。因为通知定义的是切面的

"要做什么"和"在何时做",而切点定义的是切面的"在何地做"。将两者结合在一起,就可以完美的

展现切面在何时,何地,做什么(功能)。

连接点(Join point)

即被通知的类中的方法都可能成为切点,所以这些都是连接点,定义成切点之后,这个连接点就变成了切点,通知的类可能是一个类,也有可能是一个包底下的所有类,所以连接点可以成千上万来记,是一个虚概念,可以把连接点看成是切点的集合。

切点(Poincut)

在被通知的类上,连接点谈的是一个飘渺的大范围,而切点是一个具体的位置,用于缩小切面所通知的连接点的范围。

前面说过,通知定义的是切面的"要做什么"和"在何时做",是不是没有去哪里做,而切点就定义了"去何处做"。

切点的定义会匹配通知所要织入的一个或多个连接点。我们通常使用明确的类和方法名称,或者是使用

正则表达式定义所匹配的类和方法名称来指定切点。说白了,切点就是让通知找到"发泄的地方"。

引入(Introduction)

引入这个概念就比较高大尚,引入允许我们向现有的类添加新方法或属性。

主要目的是想在无需修改A的情况下,引入B的行为和状态。

织入(Weaving)

织入是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。

在目标对象的生命周期里有多个点可以进行织入:

编译期: 

    切面在目标类编译时被织入。需要特殊的编译器,是AspectJ的方式,不是spring的菜。

类加载期: 

    切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器,它可以在目标类被引入应用之前

    增强该目标类的字节码。AspectJ5支持这种方式。

运行期:  

     切面在应用运行的某个时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态的创建

     一个代理对象。而这正是Spring AOP的织入切面的方式。

AOP实战(注解版)

1、创建切面类

切面类包含通知和切入点,在创建切面类之前,我们需要了解下AspectJ的切点表达式,因为我们需要通过

切点表达式定义切点,用于准确的定位应该在什么地方应用切面的通知。

 

 

 

2、创建目标类,定义目标方法

用@Configuration代替xml方式启动容器

/**

 * Jdk代理:基于接口的代理,一定是基于接口,会生成目标对象的接口的子对象。

 * Cglib代理:基于类的代理,不需要基于接口,会生成目标对象的子对象。

 * 1. 注解@EnableAspectJAutoProxy开启代理;

 * 2. 如果属性proxyTargetClass默认为false, 表示使用jdk动态代理织入增强;

 * 3. 如果属性proxyTargetClass设置为true,表示使用Cglib动态代理技术织入增强;

 * 4. 如果属性proxyTargetClass设置为false,但是目标类没有声明接口,

 *    Spring aop还是会使用Cglib动态代理,也就是说非接口的类要生成代理都用Cglib。

 */

利用spring测试类测试

 

 到此,我们基本上了解了基于注解的AOP实战。

环绕通知

关于通知类型,需要单独分析的是环绕通知,他跟其他通知类型不一样,环绕通知也是最为强大的一种通知方式,

所谓的环绕通知,顾名思义,它能够让你所编写的逻辑将被通知的目标方法全部包装起来。

实际上就像我们前面写的开会前,开会后干的哪些事情,对于环绕通知来说,一个方法就搞定了,因为他包围了目标方法,

等同于在一个通知方法中同时编写了前置通知和后置通知,环绕通知都会为执行开会前,开会后等等逻辑。

 

 

原文出自:https://i.cnblogs.com/EditPosts.aspx?opt=1

 

 

 

 

 

@Aspect@Componentpublic class LoggingAspect {
@Before("execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomer(..))")public void logBefore(JoinPoint joinPoint) {
System.out.println("logBefore() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("hijacked : " + joinPoint.getTarget());System.out.println("******");}
@After("execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomer(..))")public void logAfter(JoinPoint joinPoint) {System.out.println("******");System.out.println("logAfter() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("******");
}@AfterReturning(pointcut="execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomerReturnValue(..))", returning= "result")public void logAfterReturning(JoinPoint joinPoint, Object result) {
System.out.println("logAfterReturning() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("Method returned value is : " + result);System.out.println("******");
}@AfterThrowing(pointcut="execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomerThrowException(..))",throwing="error")public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
System.out.println("logAfterThrowing() is running!");System.out.println("hijacked : " + joinPoint.getSignature().getName());System.out.println("Exception : " + error);System.out.println("******");
}@Around("execution(* cn.ffcs.msa.springAop.six.CustomerBoImpl.addCustomerAround(..))")public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("logAround() is running!");System.out.println("hijacked method : " + joinPoint.getSignature().getName());System.out.println("hijacked arguments : " + Arrays.toString(joinPoint.getArgs()));System.out.println("Around before is running!");joinPoint.proceed();System.out.println("Around after is running!");System.out.println("******");
}

转载于:https://www.cnblogs.com/hejj-bk/p/11496505.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值