• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
风吹花落泪如雨
博客园    首页    新随笔    联系   管理    订阅  订阅

spring学习笔记整理(二)-----AOP讲解

一、什么是AOP?

      AOP:面向切面编程,采用横向抽取机制,取代了传统的纵向继承  

      AOP是一种面向切面的思想,但是我们平常说的spring使用了AOP,实际上说的是spring实现AOP思想的底层原理,而底层原理就是使用动态代理来增强某个方法。所以平常说AOP技术实际上就是指通过动态代理来对方法进行增强。

        比如:我们需要对一个已经写好的类中的方法进行增强,在不改动该类方法的代码的情况下,如何做呢?

        传统纵向继承 

          编写一个类,继承该类,重写该类中的这种需要增强的方法,这样确实可以达到我们的目的,但是一旦需要修改的方法所属的类不是一个类,那么就需要在多写很多子类,增加很多方法,编程量就是一个很大的问题,并且后期要修改,工作量也很大。

                

        横向抽取机制,将要增强所用到的代码提取到一个类中,然后对需要增强的方法通过代理类去将其增强即可。

二、动态代理的两个方式

      JDK动态代理。接口+实现类

      cglib字节码增强。 实现类

      为了更好的理解spring的AOP技术,我们应该手动编写以上两种实现动态代理的方法,然后才能体会到spring实现AOP技术所带来的便利。

      2.1、JDK动态代理。

          要使用JDK动态代理的类,必须要有接口。这是前提条件。

                

          编写UserService接口和UserServiceImpl。 

                  

          创建代理类的工厂proxyFactory

                  

            增强代码的类

                  

            测试testApp

                  

            测试结果 成功增强了userServiceImpl对象的add方法。如果别的类有需要被增强的方法,那么同样通过创建工厂代理就可以拿到对应的代理对象。然后进行加强

                  

                  

                  

        2.2、cglib动态代理。

            被代理的对象不需要在实现接口,要求就放松了很多。很多时候都采用cglib来进行动态代理。

            需要导入两个jar包

                  

            spring已经将cglib和asm整合到了spring-core-3.2.0.jar中,所以我们导入spring的jar包就不需要在重复导这两个包了。

            跟JDK动态代理的编写流程是一样的

            UserServiceImpl。没有接口了

                  

            增强方法的类

                    

          

            创建代理的工厂(和jdk动态代理有区别)

                      

 

              测试

                   成功增强方法。

              注意:CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,所以说被代理的类不能有final关键字 

三、spring中使用AOP的相关术语

         3.1、Target:目标类,需要被增强的类,也就是上面我们写的UserServiceImpl。

         3.2、JointPoint:连接点,目标类上需要被增强的方法,(这些方法可以被增强,也可以不增强,也就是说目标类中所有的方法都可以称为是连接点)

         3.3、PointCut:切入点,被增强的方法(已经确定这个方法要被增强),切入点就是一个连接点的子集

         3.4、Advice:增强/通知,增强的代码,也就是上面将增强的代码凑成的一个类。类中的每个方法都代表一个增强的功能代码,这个类中的方法就被称为通知

          前置通知:在方法之前执行

          后置通知:在方法之后执行

          异常通知:方法出现异常

          最终通知:在后置之后执行

          环绕通知:在方法之前和之后执行

         3.5、weaving:织入,将切入点和通知结合,从没被增强到已经增强的过程

         3.6、Aspect:切面,切入点和通知结合,切入点和通知点多点形成面特殊情况:一个切入点 和 一个通知

                画张图就可以理解了。

                

          3.7、Introduction(引介) 特殊的通知,可以对类增强,添加方法或字段。(知道)

四、使用AspectJ框架(注解方式)实现aop

         使用注解的话,很简单,就是把xml方式用注解给替代,其中也就做6件事

        1、将切面类配置给spring,相当于<bean id="" class="切面类全限定类名">

           @component

        2、将切面类申明为切面

           @Aspect

            

        3、将目标类配置给spring

           @component  如何不编写名称的话,那么要获取该对象,则使用userServiceImpl进行获取。

            

        4、申明目标类切入点范围

            1.方法必须private,没有返回值,没有参数

            2.之后使用将其当成方法调用。例如:@After("myPointcut()") 

           @Pointcut("execution(* com.wuhao.aspectj.annotation.*.*(..))")

            

        5、编写相应的通知           

          @Before 前置

          @AfterReturning  后置,可以获得返回值,必须在注解中确定返回值参数名称。

          @AfterThrowing 抛出异常,可以获得具体异常信息,必须在注解确定第二个参数名称

          @Around 环绕[]

          @After 最终  

            

         6:必须在xml中扫描注解和启用aop

            

        7、测试

            

三、AspectJ切点函数

1. 方法切点函数 
execution():根据匹配规则匹配 
eg:前置增强@Before(execution(public * *Service(..))) 
匹配所有以Service结尾的方法

@annotation():根据相应的的注解匹配 
eg:后置增强@AfterReturning(“@annotation(com.sxd.annotation.Tag)”) 
只有方法注解了@Tag才能匹配

2. 方法入参切点函数 
args:根据输入参数类型参数匹配 
eg:环绕增强@Around(com.sxd.domain.Student) 
输入参数为Student才能匹配(包含子类)

@args:根据输入参数类型是否注解指定注解匹配 
eg:抛出增强@AfterThrowing(com.sxd.annotation.Respository) 
比如输入参数StudentDao类上注解了@Repository才能匹配(包含子类)

3. 目标类切点函数 
within(): 根据匹配条件匹配 
eg:Fianl增强@After(within(com.sxd.service.*Service)) 
service包下的以Service结尾类所有的方法才能匹配,与execution类似,但只精确到类级别

@within():根据输入参数注解类型匹配 
eg:引介增强@DeclareParents(@within(com.sxd.annotation.Tag)) 
匹配标注了@Tag的类的子类和子孙类

target():根据类型匹配指定类来决定连接点是否匹配 
eg:@Before(target(com.sxd.service.BaseService)) 
匹配BaseService的实现类StudentService的所有方法(接口方法以及没有在接口定义的方法)

@target():根据输入参数注解类型匹配 
eg:@Before(@Target(com.sxd.annotation.Tag)) 
匹配只有标注了@Tag的类(不包含其子类)

4. 代理类切点函数 
this() 
判断代理对象的类是否按类型匹配于指定类,如果匹配,则代理对象的所有连接点匹配切点

 

   

 

posted @ 2018-03-09 22:50  风吹花落泪如雨  阅读(119)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3