• AOP切面


    一、存在的问题:为方法添加日志和验证功能

    • 代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点
    • 代码分散:以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块
    • AOP编程便是为了解决上述问题

    二、解决方案

    1. 使用动态代理
    • 代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理,代理对象决定是否以及何时将方法调用转到原始对象上。
    1. AOP
    • AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传统OOP(Object-Oriented Programming)的补充
    • AOP的主要编程对象是切面(aspect),而切面模块化横切关注点
    • 在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能再哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就不模块化到特殊的对象(切面)里。
    • AOP的好处
      • 每一个事物逻辑位于一个位置,代码不分散,便于维护和升级
      • 业务模块更简洁,只包含核心业务代码

    三、AOP术语

    • 切面(Aspect):横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
    • 通知(Advice):切面必须要完成的工作
    • 目标(Target):被通知的对象
    • 代理(Proxy):向目标对象应用通知之后创建的对象
    • 连接点(Joinpoint):程序执行的某个特定位置;如类某个方法调用前、调用后、方法抛出异常后等。连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位。
    • 切点(pointcut):每个类都拥有多个连接点,连接点是程序类中客观存在的事务。AOP通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件。

    AspectJ:java社区里最完整最流行的AOP框架
    在Spring2.0以上版本,可以使用基于AspectJ注解或基于XML配置的AOP

    四、使用

    1. 加入jar包:AspectJ
    2. 在配置文件中加入aop的命名空间
    3. 在配置文件中加入配置(通过注解)
    <!--使AspectJ注解起作用,自动为匹配的类生成代理对象-->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
    1. 前置通知
    • 把横切关注点的代码抽象到切面的类中

      1. 切面首先是一个IOC中bean,即加入@Component注解
      2. 切面还需要加入@Aspect注解
      3. 在切面类中声明各种通知。在方法前加入@Before注释。方法内可以使用JoinPoint参数,访问细节。
    @Before("execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))")
    public void beforeMethod(JoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
    
    
        System.out.println("The method:"+methodName+" begin with:"+args);
    }
    
    1. 后置通知:目标方法执行后(无论是否异常),执行的通知
      与@Before一样,在通知方法前使用注释@After
      后置通知中还不能访问目标方法执行的结果
    @After("execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))")
    public void afterMethod(JoinPoint joinPoint){
        String method = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method:"+method+" end with"+args);
    }
    
    1. 返回通知:目标正常执行后执行的通知
      可以访问到方法的返回值
    @AfterReturning(value = "execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))",
            returning = "result")
    public void aftetReturning(JoinPoint joinPoint,Object result){
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("The method:"+methodName+" end with"+result);
    }
    
    1. 异常通知
      目标方法出现异常会执行的diamante,可以访问到异常对象;其可以在出现指定异常时执行。
    2. 环绕通知
      环绕通知需要携带ProceedingJoinPoint类型的参数。环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。且环绕通知必须有返回值,返回值即目标方法的返回值。
    @Around("execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))")
    public Object around(ProceedingJoinPoint pjp){
        Object result = null;
        String methodName = pjp.getSignature().getName();
        List<Object> args = Arrays.asList(pjp.getArgs());
        try {
            //前置通知
            System.out.println("The method:"+methodName+" begin with:"+args);
            result = pjp.proceed();
            //返回通知
            System.out.println("The method:"+methodName+" end with:"+result);
        } catch (Throwable throwable) {
            //异常通知
            System.out.println("The method:"+methodName+" occurs with:"+throwable);
        }
        //后置通知
        System.out.println("The method "+methodName+" ends");
        return result;
    }
    

    五、切面的优先级

    @Order(level)指定切面的优先级,值越小优先级越高

    六、切点表达式

    • 定义一个方法,用于声明切点表达式。一般地,该方法不需要再添入其他代码。
    • 使用@Piintcut来声明切入点表达式
    • 后面的其他通知直接使用方法名来引用切点表达式
        //切点表达式
        @Pointcut("execution(public int com.atguigu.spring.aopimpl.ArithmeticCalculator.*(..))")
        public void declareJoinPoint(){}
    
        //引用方式
        @Before("declareJoinPoint()")
        public void beforeMethod(JoinPoint joinPoint){
    

    七、基于配置文件的方式来配置AOP

    <aop:config>
        <!--配置切点表达式-->
        <aop:pointcut id="pointcut" expression="execution(* com.atguigu.spring.aopxml.ArithmeticCalculator.*(..))"/>
        <!--配置切面-->
        <aop:aspect ref="loggingAspect" order="2">
            <!--配置通知-->
            <aop:before method="beforeMethod" pointcut-ref="pointcut"></aop:before>
            <aop:after method="afterMethod" pointcut-ref="pointcut"></aop:after>
            <aop:after-returning method="aftetReturning" pointcut-ref="pointcut" returning="result"></aop:after-returning>
            <aop:after-throwing method="aftetThrowing" pointcut-ref="pointcut" throwing="ex"></aop:after-throwing>
        </aop:aspect>
    </aop:config>
    
  • 相关阅读:
    POJ 2159 Ancient Cipher 难度:0
    POJ 3299 Humidex 难度:0
    POJ 1503 Integer Inquiry 大数 难度:0
    POJ 2262 Goldbach's Conjecture 数学常识 难度:0
    POJ 1083 Moving Tables 思路 难度:0
    PAT 甲级 1126 Eulerian Path
    Java 大数运算
    PAT 甲级 1010 Radix
    PAT 甲级 1137 Final Grading
    PAT 甲级 1064 Complete Binary Search Tree
  • 原文地址:https://www.cnblogs.com/ylcc-zyq/p/12547919.html
Copyright © 2020-2023  润新知