zoukankan      html  css  js  c++  java
  • Spring AOP 的基本使用

    AOP

    一、  什么是AOP

    AOP是面向切面编程的简称,将程序运行过程分解成各个切面,可以在不修改源码的情况下给程序方法动态地添加功能,其底层实现是使用了动态代理模式;

    二、  为什么要用AOP

    分离系统中的各种关注点,将核心关注点和横切关注点分离开来(例如主业务程序和一些校验、日志、安全类的程序分离),实现业务逻辑和切面逻辑的解耦;

    三、  实现效果

    可以在方法的前后加入其它操作,比如:每次进行一次数据库查询操作之后,要添加一条日志,而添加日志的操作我们不用写在数据库查询这个方法内,而是交由AOP框架来做;使用动态代理后,每当我们执行这个数据库查询方法时,都会被AOP框架截获,从而进行方法增强,在方法的前后添加一些其它操作,我们自己调用的方法(例如这个数据库查询方法),称之为连接点(JoinPoint);

    四、  使用注解的配置方式(使用 AspectJ 类库实现)

    0、jar包

    aspectiweaver.jar    aopaliance-.jar    asperctjrt.jar

    1. 基本配置

    (0)IOC容器的注解方式配置照旧

    (1)首先要把一个类声明成切面,就需要先把该类放到IOC容器里去(配置它的bean),再声明为一个切面,即在类上面加上@Aspect和@Component这两个注解

    (2)在xml配置文件中加入aop命名空间,并在beans标签中写入:

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    表示自动为匹配的方法生成代理对象;

    1. 前置通知(在目标方法执行前做的操作)

    (1)   在切面类中加入一个方法,并在该方法前加入注解:

    @Before(“execution(匹配的目标方法)”)

    括号里的值称为切入点表达式,可以使用模糊匹配(比如*./正则)

    表达式格式为:访问权限 返回值 方法的完整限定名(参数类型)

    (2)   该前置通知方法可以有类型为JoinPoint参数

    通过该参数可以获取目标方法的各种参数,例如方法名、参数值列表、类…

     

    1. 后置通知(在目标方法执行后做的操作)

    (1)   使用@After注解,与前置通知功能相对应;

    (2)   即使是目标方法发生了异常,后置通知照样执行;

    (3)   前置通知和后置通知都无法访问目标方法的返回结果;

    1. 返回通知

    (1)   在方法正常结束之后执行的方法;

    (2)   在方法前使用:

    @AfterReturning(value=” execution(匹配的目标方法)”,returning=”变量名”)

    (3)   在方法的参数中加入  Object 变量名(该变量名与注解中的变量名对应),即可在返回通知方法内访问到目标方法的返回值;

    1. 异常通知

    (1)   在目标方法发生异常的时候使用;

    (2)   在方法前加入:

    @AfterThrowing(value=” execution(匹配的目标方法)”,throwing=”变量名”)

    (3)   在方法的参数中加入 异常类型 变量名(该变量名与注解中的变量名对应),即可在异常通知方法内访问到目标方法抛出的异常

    1. 上述四个通知的执行顺序

    前置通知->返回|异常->后置通知;

    1. 环绕通知

    (1)   环绕通知相当于动态代理的全过程,包含了以上四个通知

    (2)   在方法前加入@Around(” execution(匹配的目标方法)”)

    (3)   在方法的参数中 加入ProceedingJoinPoint类型参数,使用该类型参数的.proceed();方法可以控制目标方法的执行,并且该方法的返回值就是目标方法的返回值;

    (4)   同样,ProceedingJoinPoint类型参数也可以获得目标方法的方法名和参数之类的值;

    (5)   环绕通知方法必须得有返回值;

    1. 切面优先级

    当有多个切面类时,使用@order(整数值),该注解写在切面类上,值越小,优先级越高;

    1. 重用切入点表达式

    (0)   我们在每个通知方法的注解里都要写入切入点表达式executtion(….),里面的值很可能都是一样的,所以将其封装起来,以便重用;

    (1)   写一个空方法(即方法里没有写任何代码的方法);

    (2)   在方法前加入@Pointcut(” execution(匹配的目标方法)”);

    (3)   而后,在其它通知的注解里,就可以将” execution(匹配的目标方法)”替换为该方法名;

    (4)   跨类、跨包引用需要加上相应的类、包前缀;

    五、  使用XML文件的配置方式(使用 AspectJ 类库实现)

    1. (1)切面类首先得是一个bean,所以在xml配置文件里,得先把切面类配置成一个bean;

    (2)切面类、切面类里的通知方法代码都和注解配置时的代码一致;

    1. AOP基本配置

    (1)先写<aop:config></aop:config>标签,而后所有的aop配置都写在该标签里面;

    (2)配置切入点表达式:

    <aop:pointcut expression=”execution(匹配的方法名)” id=”该表达式ID”>

    该表达式指定了目标方法,该方法执行时,就会被引用了该表达式的通知截获;

    (3)配置切面:

    <aop:aspect ref=”切面类的bean” order=”优先级整数值”></aop:aspect>

    而后,属于该切面的通知都写在该标签内;

    (4)配置通知:

    <aop:before method=”切面类里的方法名” pointcut-ref=”切入点表达式ID”>

    返回、后置、异常、环绕通知配置类似;注意异常通知和返回通知的变量名称要和方法参数的变量名一致;

    (5)<aop:config>标签内可以有多个切面配置标签,而切面标签内可以有多个通知;

    (6)要使用目标bean时,就直接获取目标对象的bean,AOP会自动生成代理,自动织入;

    1.  
    2. 需要将通知各自写成一个类并继承相应的接口:
    3. 配置

    六、  使用XML文件的配置方式(使用 spring框架自身aop实现)

          前置通知:MethodBeforeAdvice   环绕通知:MethodInterceptor 
                后置通知:AfterReturningAdvice  异常通知:ThrowsAdvice
     

    (1)   将目标对象、各个通知方法(称为切面)都配置成bean

    (2)   将代理对象也配置成bean ,id随意,

    class=” org.springframework.aop.framework.ProxyFactoryBean”

    分别有三个参数:

    interceptorNames,值是切面的list(<list><value>通知/顾问beanID</value>…)

    target,值为目标对象<ref=”目标对象beanID”>

    interfaces,是目标对象实现的接口list(<list><value>接口路径</value>…)

    (3)   要使用目标对象时,获取代理对象的beanID;

    1. 使用 名称匹配方法切入点 顾问(advisor)

    (0)   顾问包装通知,让通知更精细地织入

    (1)   没有使用顾问时,默认地,会为目标对象的全部方法实现通知操作,使用顾问后,就可以更精细地指定拦截哪些方法;

    顾问也要先配置成bean,id随意

    class=”org.springframework.aop.support.NameMatchMethodPointcutAdvisor”

    (2)   该顾问有两三个参数:advice,值为引用类型,引用通知的beanID(即想让某个通知精确地作用某个某个/些方法);mappedName/ mappedNames,第一个为value类型,指定目标方法名,第二个为array类型,指定多个方法名(第二个的值也可以写value里,各方法名用逗号隔开);

    (3)   mappedNames的值可以用*号去匹配,比如do*,指定以do开头的所有方法

    (4)   顾问也是切面,所以要使用顾问时,将其像通知一样放入代理对象bean里的interceptorNames参数

    1. 使用 正则表达式匹配方法切入点 顾问(advisor)

    (0)   与”名称匹配方法切入点”写法类似;

    (1)   class要换成org.springframework.aop.support.RegexpMethodPointcutAdvisor

    (2)   该顾问也要三个参数:advice,使用方法同上;

    pattern/patterns:其value值为正则表达式(其实多个表达式都可以写在pattern里,用|隔开);

    (3)   常用的正则表达式运算符有 . 表示任意单个字符,

    * 表示前一个字符出现0次或多次   + 表示前一个字符出现1次或多次;

    (4)   正则表达式匹配的是方法的全限定名(包.类.方法名);

    (5)   例:  .*do.* 全限定名中表示包含do的方法;

    1. 默认Advisor自动代理器

    (0)   没使用自动代理器时,若有多个目标对象,则需要手动配置多个代理对象,造成代码冗余且耗费时间;

    (1)   默认Advisor自动代理器底层使用了bean的后置处理器(BeanPostProcessor),在bean初始化之后,会自动地帮配置文件中的所有目标对象生成代理对象,并自动绑定配置文件中的顾问而需要使用目标对象时,只需要获取目标对象的beanID就可以了;

    (2)   配置:目标对象、通知、顾问的bean配置都照旧,只需加多以下bean:

    <bean class=”org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator”>

    (3)   弊端:该自动代理的切面只能是Advisor;不能指定目标对象;

    1. Bean名称自动代理生成器

    (0)   可以指定需要代理的目标对象;需要手动指定切面(可以是通知也可以是顾问);

    (1)   配置:目标对象、通知、顾问的bean配置都照旧,只需加多以下bean:

    <bean class=”org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator”>

    (2)   该bean需要使用两个参数:beanNames,value值为目标对象的beanID,当有多个beanID时使用逗号隔开;  interceptorNames,value值为切面beanID,当有多个beanID时使用逗号隔开;

    1. CGLIB代理

    (0)   以上所说的代理皆为JDK动态代理,在代理对象配置中需要指定目标对象的接口;

    (1)   而当目标对象没有接口时,则Spring AOP会自动使用CGLIB代理(当然在代理对象配置中也不用指定接口了);

    (2)   当目标对象有接口时,也可以指定使用CGLIB代理:在代理对象配置中,加上ProxyTargetClass参数,该参数value值为true|false,为true时,强制使用CGLIB代理;

    也可以使用optimize参数,value值也是true|false,为true时,指定了接口则使用jdk代理,无接口则使用CGLIB代理;

    (3)   JDK代理和CGLIB代理区别:JDK创建代理对象快,但执行慢;CGLIB则相反;

    (4)   注:JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

    而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

    ps.请另外查阅开发过程中需要使用的jar包

  • 相关阅读:
    Ionic3 遇到的一些错误-Error: Cannot find module 'reflect-metadata'
    Ionic3 遇到的一些错误-submodule update -q --init --recursive
    Ionic3 一些命令
    Npm 使用淘宝镜像
    在PHP中使用AES加密算法加密数据-2
    php实现AES/CBC/PKCS5Padding加密解密(又叫:对称加密)-1
    php rsa加密解密实例
    composer 安装Laravel、thinkphp5.1
    PHP原生分页的编写
    微信授权登录并获取用户信息接口开发
  • 原文地址:https://www.cnblogs.com/Drajun/p/8278839.html
Copyright © 2011-2022 走看看