AOP 面向切面编程

一、 AOP 概述

1、AOP AspectOriented Programing 面向切面编程

         AOP是OOP升华,SOA service-oriented architecture 面向服务架构(web service是SOA实现技术, 分布系统整合)

         特点:AOP采取横向抽取机制,取代了传统纵向继承体系 重复性代码

 

spring的底层采用两种方式进行增强

         第一:Spring传统AOP 纯java实现,在运行期,对目标对象进行代理,织入增强代码

         第二:AspectJ第三方开源技术,Spring已经整合AspectJ,提供对AspectJ注解的支持,开发AOP程序 更加容易(企业主流)

 

2、了解AOP 开发中术语

Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方 法类型的连接点.

Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义.

Advice (通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,  异常通知,最终通知,环绕通知(切面要完成的功能)

Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地 添加一些方法或Field.

Target (目标对象):代理的目标对象

Weaving (织入):是指把增强应用到目标对象来创建新的代理对象的过程.

                  注:spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入

Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

Aspect(切面): 是切入点和通知(引介)的结合

 

二、 Spring AOP 代理底层实现

         第一种 JDK 自带的动态代理技术

         JDK动态代理必须基于接口 进行代理

         作用:使用代理可以对目标对象进行性能监控(计算运行时间)、安全检查(是否具有权限)、 记录日 志等。

         注意:必须要有接口才能进行代理,代理后对象必须转换为接口类型

例:

  

 

         第二种 CGLIB(CodeGenerationLibrary)是一个开源项目        

          Spring使用CGlib 进行AOP代理, hibernate 也是支持CGlib(默认使用 javassist )需要下载cglib 的jar包(Spring 最新版本3.2 内部已经集成了cglib ,无需下载cglib的jar

         作用:可以为目标类,动态创建子类,对目标类方法进行代理(无需接口)

         原理:Spring AOP 底层,会判断用户是根据接口代理还是目标类代理,如果针对接口代理就使用JDK代理,如果针对目标类代理就使用Cglib代理。

   

 

三、 Spring 传统AOP 编程(配置复杂,企业基本不用了)

1、AOP 规范由 AOP 联盟组织(aopalliance)来定义,最初目的采用代理方式,对目标方法进行增强

定义了五种增强方式Advice

         1) 前置通知 org.springframework.aop.MethodBeforeAdvice 

         2) 后置通知org.springframework.aop.AfterReturningAdvice

         3) 环绕通知org.aopalliance.intercept.MethodInterceptor

         4) 异常抛出通知  org.springframework.aop.ThrowsAdvice

         5) 引介通知 org.springframework.aop.IntroductionInterceptor

 

2、 理解Advisor 概念

         Advisor是Spring 框架内部提出切面的概念,通常指一个PointCut和一个Advice组合

         Advisor和Aspect的区别

                  Advisor代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截

                  Aspect代表很多切面和切点。Advisor只代表一个切面一个切点。

 

不带有Pointcut(切点)的切面Advisor:使用一个Advice本身作为一个切面,拦截目标类中所有方法

PointcutAdvisor(有切点的切面):通过定义切点,来指定拦截目标类中哪些方法

 

3、案例: 以前置通知为例,制作一个不带有切点的Advisor(拦截所有方法)

                  在昨天原有6个jar包 基础上 ,导入 2个jar包

                   spring-aop-3.2.0.RELEASE.jar  、 com.springsource.org.aopalliance-1.0.0.jar(来自AOP联盟)

第一步 : 编写被代理类

                   ProductService接口 ---- ProductServiceImpl 实现类

第二步 : 编写增强代码


第三步:通过配置,使MyMethodBeforeAdvice作为一个不带切点的切面,应用到ProductServiceImpl 上

         通过ProxyFactoryBean 为目标对象,添加Advice增强,生成代理对象

         ProxyFactoryBean 可以配置的属性

                   target: 代理的目标对象

                   proxyInterfaces : 代理要实现的接口

                   如果多个接口可以使用以下格式赋值

                   <list>

                           <value></value>

                                ....

                   </list>

                   proxyTargetClass: 是否对类代理而不是接口,设置为true时,使用CGLib代理

                   interceptorNames: 需要织入目标的Advice

                   singleton: 返回代理是否为单实例,默认为单例

                   optimize: 当设置为true时,强制使用CGLib


小结:先配置目标Bean,再配置Advice增强Bean,通过ProxyFactoryBean为目标Bean生成代理对象,    织入Advice

 

4、案例:以环绕通知为例, 定义带有切点的Advisor

         JdkRegexpMethodPointcut构造正则表达式切点(指定拦截目标类中某些方法

         其方法切面为RegexpMethodPointcutAdvisor

第一步: 编写被代理对象  CustomerService

第二步 :编写增强代码 Advice


第三步:配置 applicationContext.xml


注意: 正则表达式写法“ .* ” 代表拦截目标类中所有方法

         例:cn\.itcast\.springaop\.service\.CustomerService\.save 只拦截save

                  cn\.itcast\.springaop\.service\.CustomerService\.s.*  拦截所有s开头的方法

 

5、自动代理

前面的案例中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大

自动创建代理应用到的类

         BeanNameAutoProxyCreator:根据Bean名称创建代理(针对Bean所有方法)

         DefaultAdvisorAutoProxyCreator:根据Advisor本身包含信息创建代理(针对特定的方法)

以上两个案例用自动代理改

1 BeanNameAutoProxyCreator根据Bean名称创建代理,拦截符合名称的Bean中所有方法(类级别)

与原理的配置区别

         原来的是有一个被代理的bean和一个增强的beanBeanNameAutoProxyCreator的配置是采用了后处       bean的方式,在生成bean的时候进行增强。只有一个bean

        

2 DefaultAdvisorAutoProxyCreator根据Advisor本身包含信息创建代理

         根据切面配置进行代理 (切面中包含切点信息 )

 

四、Spring框架使用AspecJ进行AOP编程

         AspectJ是一个基于Java语言的AOP框架(第三方)

 

         工程 在基本6个jar包的基础上还需导入

                  spring-aop-3.2.0.RELEASE.jar

                  com.springsource.org.aopalliance-1.0.0.jar

                  spring-aspects-3.2.0.RELEASE.jar

                  com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

AspectJ的开发有两种方式:注解与xml文件

1使用@AspectJ注解开发AOP程序 

使用AspectJ 进行开发

Spring 配置文件applicationContext.xml需要引入 aop用的Schema

<beans xmlns="http://www.springframework.org/schema/beans"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xsi:schemaLocation="

        http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans.xsd

       http://www.springframework.org/schema/aop       http://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- beandefinitions here -->

</beans>

 

开启自动代理 <aop:aspectj-autoproxy />

 

         @AspectJ 注解提供六种通知Advice类型

                  * @Before:前置通知

                  * @AfterReturning:后置通知

                  * @Around:环绕通知

                  * @AfterThrowing:异常抛出通知

                  * @After:最终通知,相当于代码 finally(之前没有的)

                  * @DeclareParents:引介通知 (不要求)

注:以上Advice对应注解,都提供value属性,通过属性可以用来定义切点表达式         

         切点表达式语法:execution(<访问修饰符>? <返回类型><方法名>(<参数>)<异常>)

举例说明:

         execution(public* *(..))  ----- 所有public 的方法都进行增强

         execution(*cn.itcast.dao.*(..))  ------cn.itcast.dao包中所有方法

         execution(*cn.itcast.dao..*(..)) ------ cn.itcast.dao包和其子包中所有方法

         execution(*cn.itcast.service.UserService.*(..)) ----- cn.itcast.service.UserService类中所有方法

         execution(*cn.itcast.dao.GenericDAO+.*(..)) ------ cn.itcast.dao.GenericDAO 接口所有实现类的方法

         execution(*save*(..))  ------- 匹配所有以save开头的方法

        

         注:AspecJ对原有代码进行增强,不需要实现接口,任何JavaBean都可以

例:第一步 : 编写被代理类 EmployeeService

         第二步 : 编写增强代码 MyAspect (自定义JavaBean ----作为一个切面)

                  在切面类内部 ,提供五种Advice 增强方法, 并使用对应注解修饰

            

         第三步:在配置文件中进行配置

   

注意事项:

         1) @Before (前置通知):方法中传入如果传入JoinPoint参数就可以获得拦截的切点信息


         2) @AfterReturing (后置通知):方法可以传入JoinPoint用来获得切点信息,也可以传入Object类  型参数用于获得目标业务方法的返回值


         3)  @Around (环绕通知)方法中传入ProceedingJoinPoint用于控制目标方法的执行

                   应用: 权限控制 、方法运行时间统计


         4) @AfterThrowing (抛出通知):在目标方法出现异常的时候才调用advice,方法中传入 Throwable 对象,代表被捕获的异常


         注:异常抛出后目标代码不会继续执行。        

         5) @After(最终通知):无论目标方法是否出现异常,仍然执行通知 ,效果类似finally

         注:在目标方法产生异常后,@AfterReturing不会得到执行

 

@Pointcut为切点命名

如果每个Advice的注解都定义切点表达式,开发或者维护非常不方便

         *通过@Pointcut 注解将切点单独定义出来,只需要在 advice注解中引用定义的切点就可以了

         * 定义切点方法规则:private void无参数方法,方法名为切点名


小结:需要掌握的注解:@Aspect@Before @AfterReturning @After @Around @AfterThrowing @Ponitcut

        

2 Spring通过xml方式配置 AspectJ

第一步:编写被代理类EmployeeService

第二步:编写切面JavaBean  ---- MyAspect2

 

第三步: 编写增强方法进行配置

                   注:无需配置自动代理了


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值