博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring-AOP
阅读量:6949 次
发布时间:2019-06-27

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

引出Spring-AOP

AOP(Aspect Orient Programming),也就是面向切面编程.

在传统OOP编程里以对象为核心,整个软件系统由系统相互依赖的对象组成,而这些对象将被抽象一个一个的类,并允许使用类继承来管理类与类之间一般到特殊的关系,随着软件规模的增大,应用的逐渐升级,慢慢出现了一些OOP很难解决的问题。 现在假设系统中有三段完全相似的代码,这些代码通常会采用“复制”,“粘贴”方式来完成,通过这种方式产生的代码,如果有一天,代码需要修改,那么就要打开涉及这些代码相似的三个地方,逐一修改……,那如果是100,1000个相似的地方呢?为了解决这个问题,我们通常是采用将重复代码部分定义成一个方法,然后再三个代码段中调用该方法即可,如果需要修改代码,只需要修改定义的方法即可,不管整个系统中有多少地方调用了该方法,程序都无须修改这些地方,只需修改被调用的方法即可----通过这种方式,大大降低了软件后期维护的复杂性。AOP专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在JavaEE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理、安全管理、缓存、对象池管理等,AOP已经成为一种非常常见的解决方案。

在工作面试的时候可能遇到的问题:AOP在你的项目中哪些地方可以使用到?

    答:事务管理  操作日志   缓存 

AOP核心概念(了解)

AOP中常用的术语:

1、连接点(Joinpoint)
    程序执行的某个特定位置:如类开始初始化前、类初始化后、类某个方法调用前、调用后、方法抛出异常后。这些代码中的特定点,称为“连接点”。Spring仅支持方法的连接点,即仅能在方法调用前、方法调用后、方法抛出异常时以及方法调用前后这些程序执行点织入增强。
 
2、切点(Pointcut)
    每个程序类都拥有多个连接点,如一个拥有两个方法的类,这两个方法都是连接点。但在这为数众多的连接点中,如何定位到某个感兴趣的连接点上呢?AOP通过“切点”定位特定的连接点。通过数据库查询的概念来理解切点和连接点的关系:连接点相当于数据库中的记录,而切点相当于查询条件。一个切点可以匹配多个连接点。
    Spring中,切点通过Pointcut接口进行描述。
 
3、增强(Advice)
    增强是织入到目标类连接点上的一段程序代码。增强既包含了用于添加到目标连接点上的一段执行逻辑,又包含了用于定位连接点的方为信息,所以Spring所提供的增强接口都是带方位名的:BeforeAdvice(方法调用前的位置)、AfterReturningAdvice(访问返回后的位置)、ThrowsAdvice等。
 
4、目标对象(Target)
    增强逻辑的织入目标类。
  
5、织入(Weaving)
 
    织入是将增强添加到目标类具体连接点上的过程。AOP有三种织入方式:
 
1)编译期织入,这要求使用特殊的Java编译器;
 
2)类装载期织入,这要求使用特殊的类装载器;
 
3)动态代理织入,在运行期为目标类添加增强生成子类的方式。
 
Spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
 
6、切面(Aspect)
   切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。
 

7、代理对象(proxy object)

  为目标对象增加新功能从而产生的一个新的对象称为代理对象.负责调用拦截器和目标对象的方法.

8 、引入(Instroduction)

 引入允许你为已存在类添加新方法和属性。

创建通知

前置通知(@Before) 后置通知(@AfterReturning、@After)异常通知(@AfterThrowing)环绕通知(@Around)

1 package com.cy.aspect;  2   3 import org.aspectj.lang.JoinPoint;  4 import org.aspectj.lang.ProceedingJoinPoint;  5 import org.aspectj.lang.annotation.After;  6 import org.aspectj.lang.annotation.AfterReturning;  7 import org.aspectj.lang.annotation.AfterThrowing;  8 import org.aspectj.lang.annotation.Around;  9 import org.aspectj.lang.annotation.Aspect; 10 import org.aspectj.lang.annotation.Before; 11  12 import com.cy.entitys.UserInfoT; 13  14 @Aspect// 声明一个日志切面 15 public class LogAspectJ { 16      17     //第一个*代表目标方法的访问修饰符,如:public,private…… 18     //*Impl 这里的*代表着:所有以Impl结尾的JAVA类 19     //*(..)  这里的*代表着:JAVA类内部的方法名 20     /** 21      * 定义一个前置通知(before) 22      * @param jp 连接点 23      */ 24     @Before("execution(* com.lovo.service.impl.*Impl.*(..))") 25     public void beforeAdvice(JoinPoint jp){ 26         System.out.println("before通知的目标对象:" + jp.getTarget()); 27         System.out.println("before通知的目标方法:" + jp.getSignature().getName()); 28              29     } 30      31     /** 32      * 定义一个后置通知(afterReturning),只有目标方法正常执行的情况下,才会被通知 33      * @param jp 连接点 34      * @param rvt 目标方法的返回 35      */ 36     //returning="rvt" 指定一个返回的形参名,通知方法可以通过该形参名来获取目标方法的返回值 37     //pointcut 用于指定该切入点对应的切入表达式 38     @AfterReturning(returning="rvt",pointcut="execution(* com.lovo.service.impl.*Impl.*(..))") 39     public void afterReturningAdvice(JoinPoint jp,Object rvt){ 40         System.out.println("afterReturning通知的目标对象:" + jp.getTarget()); 41         System.out.println("afterReturning通知的目标方法:" + jp.getSignature().getName()); 42         System.out.println("afterReturning通知的目标方法的返回值:"+ rvt); 43         UserInfoT user = (UserInfoT) rvt; 44         System.out.println("afterReturning具体返回的值是:" + user.getName()); 45     } 46      47      48      49     /** 50      * 定义一个异常通知 51      * @param jp 连接点 52      * @param tx 目标方法所抛出的异常 53      */ 54      55      56     //throwing="tx" 指定一个返回异常的形参名,通知方法可以通过该形参名来获取目标方法返回的异常信息   // Integer.valueOf("asdfasdf"); 57     //pointcut 用于指定该切入点对应的切入表达式     58     @AfterThrowing(throwing="tx",pointcut="execution(* com.lovo.service.impl.*Impl.*(..))") 59     public void afterThrowingAdvice(JoinPoint jp,Throwable tx){ 60         System.out.println("afterThrowing通知的目标对象:" + jp.getTarget()); 61         System.out.println("afterThrowing通知的目标方法:" + jp.getSignature().getName()); 62         System.out.println("afterThrowing通知目标方法抛出的异常:" + tx); 63     }     64      65     /** 66      * 定义一个后置通知,无论目标方法是否正常运行,都会被通知到 67      * @param jp 连接点 68      */ 69      70     @After("execution(* com.lovo.service.impl.*Impl.*(..))") 71     public void afterAdvice(JoinPoint jp){ 72         System.out.println("after通知的目标对象:" + jp.getTarget()); 73         System.out.println("after通知的目标方法:" + jp.getSignature().getName()); 74     } 75      76     /** 77      * 定义一个环绕通知,该通知可以认为是:before + afterReturning 78      * 有2个特点:1、可以控制目标方法何时执行   2、可以修改目标方法的参数和返回 79      * @param jp 第一个参数必须是ProceedingJoinPoint  80      * @return 81      * @throws Throwable  82      */ 83     @Around("execution(* com.lovo.service.impl.*Impl.*(..))") 84     public Object aroundAdvice(ProceedingJoinPoint jp) throws Throwable{ 85          86         UserInfoT user = new UserInfoT(); 87         user.setId(Long.valueOf(2)); 88         user.setName("小丽变胖了"); 89         user.setSex(1); 90          91         Object[] params = jp.getArgs();//获取目标方法的参数 92         System.out.println("around通知目标方法获取的参数:" + params); 93          94         Object ret = jp.proceed(new Object[]{user});//显示调用该方法,控制目标方法执行 95         if(ret == null){ 96             return user; 97         } 98         return ret; 99     }100     101 }

 

测试

package com.cy.action;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.cy.entitys.Configer;import com.cy.entitys.UserInfoT;import com.cy.service.IUserService;public class TestAction {    public static void main(String[] args) {                ApplicationContext ac  = new ClassPathXmlApplicationContext("applicationContext.xml");                        /** */        IUserService service = (IUserService) ac.getBean("userServiceImpl");        UserInfoT user = new UserInfoT();        user.setName("小黄");        System.out.println("saveUser======================================");        service.saveUser(user);                System.out.println("updateUser======================================");        service.updateUser(user);        System.out.println("deleteUser======================================");        service.deleteUser(user);        System.out.println("getUser======================================");        service.getUser(UserInfoT.class, Long.valueOf(1));        System.out.println("testException======================================");        service.testException();                                                    }}

 

 结果:

 

重要理解AOP思想

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

你可能感兴趣的文章
[摘录]第4章 不道德的谈判策略
查看>>
IOS 视图传值
查看>>
【转】WEB网站常见受攻击方式及解决办法
查看>>
[转]五种开源协议的比较(BSD,Apache,GPL,LGPL,MIT)
查看>>
re模块 正则表达式
查看>>
学习:深度和广度之谈
查看>>
leetcode495
查看>>
用分解的方式学算法002——插入排序
查看>>
剑指Offer 16 数值的整数次方
查看>>
Intent 调用系统中经常用到的组件
查看>>
乱搞-模拟退火
查看>>
AC日记——滑动窗口 洛谷 P1886
查看>>
Android监听手机网络变化
查看>>
ES6基础-解构赋值
查看>>
html转义字符
查看>>
C++ 简单的日志类
查看>>
VirtualBox不显示64bit版本的iso
查看>>
vim缩进
查看>>
UVA 10837 A Research Problem
查看>>
NOIP模拟2
查看>>