zoukankan      html  css  js  c++  java
  • SpringAOP

    1.理解AOP是什么:
    * AOP是Aspect-oriented programming 面向切面编程
    * AOP的实现可以吧业务逻辑和系统级的服务进行隔离,使得业务逻辑跟各个系统级服务的耦合性降低,提高程序的重用性和开发效率.
    业务逻辑:某个类的某个方法本身要实现的功能
    系统级服务:身份权限验证,日志的记录,事务等等
    * 系统级的插入:权限验证---功能---日志记录
    2.如何实现AOP:
    * AOP的底层实现的原理都是动态代理
    动态代理有两种方式:jdk动态代理和cglib动态代理
    jdb的动态代理机制只能代理实现了接口的类
    cglib的动态代理既可以代理实现了接口的类,也可以代理没有实现了接口的类
    3.AOP的专业术语
    * 切面(Aspect):就是交叉在各个业务逻辑中的系统服务,类似于安全验证,事务处理等等
    * 织入(weaving):就是将切面代码插入到目标对象的某个方法的过程
    * 连接点(JoinPoint):理论上可能被切面织入的所有方法,通常所有的方法都可以作为连接点
    * 切入点(PointCut):被切面织入的连接点,该连接点就是切入点
    * 目标对象(target):切入点和连接点所属的类
    * 通知(Advice):就是切面的整个实现,切面织入的目标对象,时间点以及内容
    * 顾问(Advisor):就是通知的封装和延伸,可以将通知以更为复杂的方式织入到某些方法中去
    将切面织入到目标对象的连接点方法,使得连接点成为切入点
    4.SpringAOP的实现(实现通知---注册通知---注册代理生成器):
    a:引入AOP的jar包:
    * aopalliance-1.0.jar
    * spring-aop-4.2.1.RELEASE.jar
    b:各种通知(前置通知(类似于权限验证),后置通知(类似于日志管理),环绕通知(前后都有切面的实现),异常通知)
    * 前置通知 implements MethodBeforeAdvice
    * 后置通知 implements AfterReturningAdvice
    * 环绕通知 implements org.aopalliance.intercept.MethodInterceptor;
    * 异常通知 implements ThrowsAdvice
    c:注册
    * 注册 <bean id = "beforeAdvice" class = "路径"></bean>
    * 注册代理生成器(注入目标类,目标类接口,通知(切面的实现))
    <bean id = "myBeforeProxy" class = "org.springframework.aop.framework.ProxyFactoryBean">
    注入目标类
    <property name="target" ref = "studentService"></property>
    目标类接口
    <property name="interfaces" value = "service.IStudentService"></property>
    上面注册的通知
    <property name="interceptorNames" value = "beforeAdvice"></property>
    </bean>
    d:通知的注意点
    * 在代理生成器的配置里面配置接口的<property name="interfaces" value = "接口"></property>默认可以省略
    * 因为后置通知是在目标方法执行后才执行 ,他可以得到目标方法返回的值 ,但是不能改变他的值
    * 环绕通知有在目标方法执行前的代码,也有在目标方法执行后的代码,可以得到目标方法的值,也可以改变它
     
    总结:
    (1).一个代理对象只能代理一个bean,意味着实际应用中要定义多个代理(通过默认advisor自动代理生成器来解决)
    (2).从容器中获取对象是通过代理的bean的id,而不是我们在容器中定义的目标对象的id(通过默认advisor自动代理生成器来解决)
    (3).通知只能切入到目标类的所有方法,不能指定某些方法(通过顾问对通知的封装实现)
     
    e:顾问(Advisor) 他将通知进行了包装,根据通知的不同类型,在不同的时间点,将切面织入到指定的目标对象的某些连接点
    PointCutAdvisor是顾问的一种,他是一个接口 ,有两个实现类
    * NameMatchMethodPointcutAdvisor(名称匹配方法切入点顾问)
    <!-- 定义一个名称匹配切入点顾问 -->
    <bean id = "beforeAdvisor" class = "org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
    <property name="advice" ref = "beforeAdvice"></property>
    <!-- <property name="mappedName" value = "addStudent"></property> -->
    <!-- <property name="mappedNames" value = "addStudent,delStudent"></property> -->
    <!-- <property name="mappedNames">
    <array>
    <value>addStudent</value>
    <value>delStudent</value>
    </array>
    </property> -->
    <property name="mappedNames" value = "*Student"></property>
    </bean>
    * RegexpMethodPointcutAdvisor(正则表达式方法匹配切入点顾问)
    (1): * 匹配前面的子表达式任意次
    (2): + 匹配前面的子表达式yici或多次
    (3): . 匹配任意字符 除" "之外的
    .* 代表任意的一个字符串 .*add.* 代表包含add字符的任意字符串
    <!-- 定义一个正则表达shi匹配切入点顾问 -->
    <bean id = "afterAdvisor" class = "org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice" ref = "afterAdvice"></property>
    <!-- <property name="pattern" value = ".*add.*/.*del.*"></property> -->
    <property name="patterns" value = ".*add.*,.*del.*"></property>
    <!-- <property name="patterns">
    <array>
    <value>.*add.*</value>
    <value>.*del.*</value>
    </array>
    </property> -->
    </bean>
     
    f:spring提供了自动代理生成器来解决要定义多个代理的问题,有如下两种方式(AuotProxyCreatorTest.java)
    * 默认advisor自动代理生成器(为配置文件里面所有advisor自动生成代理)
    注意:他会为配置文件里面所有的advisor自动生成代理/会代理配置文件里面所有注册的对象
    <bean class = "org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
    * bean名称自动代理生成器
    <!-- bean名称自动代理生成器,不仅可以指定某些目标对象,还可以指定某些切面的实现(通知/顾问) -->
    <bean class = "org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames" value = "studentService"></property>
    <property name="interceptorNames" value = "afterAdvisor"></property>
    </bean>
    总结:以上各技术的运用,无非就是一个目标,将我们编写的切面的实现(通知/顾问)织入到某些类的某些方法当中
     
     
    5:AspectJ:
    对于AOP的这种编程思想,有很多框架或者组件进行了实现,spring实现AOP就是其中的一种,AspectJ也实现了AOP,而且实现方式更为简单,使用起来更为方便,所以spring将AspectJ对于AOP的实现引入到自己的框架中
    6:AspectJ是什么:
    AspectJ是一个面向切面的框架,他定义了AOP的一些语法,有一个专门的字节码生成器来生成遵守java规范的class文件(是为了代理)
    7:AspectJ的通知类型
    * 前置通知
    * 后置通知
    * 环绕通知
    * 异常通知
    * 最终通知 : 无论程序是否正常执行,最终通知的代码都会得到执行 类似于try{}catch{}finally{}
    8:切入点表达式 标识切面织入到哪些类的哪些方法当中
    * 语法格式如下:public boolean com.tz.spring.service.impl.StudentService.addStudent(Student student)
    execution( // 有问号的代表可以省略
    modifiers-pattern? // 访问权限匹配 如:public,protected
    ret-type-pattern // 返回值类型匹配
    declaring-type-pattern? // 全限定性类名
    name-pattern(param-pattern) // 方法名(参数名)
    throws-pattern? // 抛出异常类型
    )
    注意:中间以空格隔开,有问号的属性可以省略
    * 特殊符号
    a: * 代表0到多个任意字符
    b: .. 放在方法参数中,代表任意个参数,放在包名后表示当前包及其所有子包路径
    c: + 放在类名后,表示当前类及其子类,放在接口后,表示当前接口及其实现类
    * 举例:
    a:execution(public * *(..)) 表示任意的public方法
    b:execution(* set*(..)) 表示任意包含以set字符开头的方法
    c:execution(* com.tz.spring.service.impl.*.*(..)) 表示com.tz.spring.service.impl包下的任意类的任意方法
    d:execution(* com.tz.spring.service..*.*(..)) 表示com.tz.spring.service包下的所有方法以及子包下的所有方法
    e:execution(* com.tz.spring.service.IStudentService+.*(..)) 表示IStudentService和实现了他的所有类
    f:execution(* add(String,int)) 代表任意返回类型的add方法,并且有两个参数类型分别是String,int
    g:execution(* add(String,*))
    9:AspectJ + Spring的环境搭建:
    * 引入jar包
    * aopalliance-1.0.jar
    * spring-aop-4.2.1.RELEASE.jar
    * aspectjweaver-1.6.6.jar
    * spring-aspects-4.2.1.RELEASE.jar
    * 引入aop的约束
    10:基于xml配置的实现
    * 编写切面类
    * 在切面类中实现各种通知
    * 在配置文件中注册切面类
    * 在配置文件里面对aop进行配置
    <!-- AspectJ的aop配置 -->
    <aop:config>
    <!-- 注册切入点表达式 -->
    <aop:pointcut expression="execution(* add*(..))" id="beforePointcut"/>
    <aop:pointcut expression="execution(* update*(..))" id="afterReturningPointcut"/>
    <aop:pointcut expression="execution(* get*(..))" id="aroundPointcut"/>
    <aop:pointcut expression="execution(* del*(..))" id="throwingPointcut"/>
    <aop:pointcut expression="execution(* del*(..))" id="afterPointcut"/>
     
    <!-- 告知aop容器,引入切入点(对应切入点表达式) -->
    <aop:aspect ref="myAspect">
    <aop:before method="beforeAdvice" pointcut-ref="beforePointcut"/>
    <aop:after-returning method="afterReturningAdvice" pointcut-ref="afterReturningPointcut"/>
    <!-- 方法参数必须是全路径名 返回值参数名必须与方法中的参数名相同 -->
    <aop:after-returning method="afterReturningAdvice(java.lang.Object)" pointcut-ref="afterReturningPointcut" returning="result"/>
    <aop:around method="aroundAdvice" pointcut-ref="aroundPointcut"/>
    <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="throwingPointcut"/>
    <aop:after-throwing method="afterThrowingAdvice(java.lang.Exception)" pointcut-ref="throwingPointcut" throwing = "ex"/>
    <aop:after method="lastAdvice" pointcut-ref="afterPointcut"/>
    </aop:aspect>
    </aop:config>
    11:基于注解的
    * 编写切面类,加上@Aspect注解
    * 实现各种通知,在实现通知方法上加上通知的注解以及切入点表达式的注解
    package com.tz.spring.sysmanage.aspect;
     
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.AfterReturning;
    import org.aspectj.lang.annotation.AfterThrowing;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
     
    /**
    * 基于xml配置方式来实现AspectJ 定义通知
    * @author Administrator
    *
    */
    @Aspect
    public class MyAspectAnnotation {
    //定义前置通知
    @Before(value="execution(* add*(..))")
    public void beforeAdvice(){
    System.out.println("这是一个前置通知,应该在目标方法之前打印出来");
    }
     
    //定义后置通知
    @AfterReturning(value="execution(* update*(..))")
    public void afterAdvice(){
    System.out.println("这是一个后置通知,应该在目标方法之后打印出来");
    }
     
    //定义后置通知包含返回值
    @AfterReturning(value="execution(* update*(..))",returning="result")
    public void afterAdvice(Object result){
    System.out.println("这是一个后置通知,应该在目标方法之后打印出来");
    System.out.println("后置通知得到目标方法的返回值="+result.toString());
    }
     
    //定义环绕通知
    @Around(value="execution(* get*(..))")
    public void aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
    System.out.println("这是一个环绕通知,应该在目标方法之前打印出来");
    Object result = pjp.proceed();
    System.out.println("这是一个环绕通知,应该在目标方法之后打印出来");
    }
     
    //定义异常通知
    @AfterThrowing(value="execution(* del*(..))")
    public void afterThrowingAdvice(){
    System.out.println("这是一个异常通知,应该在目标方法出现异常时候打印出来");
    }
     
    //定义异常通知
    @AfterThrowing(value="execution(* del*(..))",throwing="ex")
    public void afterThrowingAdvice(Exception ex){
    System.out.println("这是一个异常通知,应该在目标方法出现异常时候打印出来 ex="+ex);
    }
     
     
    //定义最终通知 finally
    @After(value="execution(* del*(..))")
    public void lastAdvice(){
    System.out.println("这是一个最终通知,无论如何会执行 ");
    }
     
    }
    * 在配置文件注册切面,且加上aspectJ的自动代理
    <!--注册切面 -->
    <bean id= "myAspect" class = "com.tz.spring.sysmanage.aspect.MyAspectAnnotation"></bean>
    <aop:aspectj-autoproxy/>
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    linux系统编程之(一) 信号量
    linux 工具(1)------终端提示符配置
    网络那点事之socket队列
    磨刀砍柴
    线程的分离链接属性
    error C1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include "stdafx.h"”?
    mkdir和_mkdir的区别
    错误 1 error C4996: 'getcwd': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _getcwd. See online help for details.
    error C4996: 'getcwd': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _getcwd. See online help for details. c:users12968desktop estapp estapp estapp.c
    .net与C#
  • 原文地址:https://www.cnblogs.com/wadmwz/p/7628870.html
Copyright © 2011-2022 走看看