• Spring 学习二-----AOP的原理与简单实践


    一、Spring  AOP的原理

    AOP全名Aspect-Oriented Programming,中文直译为面向切面(方面)编程。何为切面,就比如说我们系统中的权限管理,日志,事务等我们都可以将其看成一个个切面。

    Spring AOP 采用的是动态代理的设计模式来实现切面编程的。

    首先,我们可以通过 

    23种设计模式----------代理模式(三) 之 动态代理模式

    来了解下动态代理模式,再次不再赘述。

    我们来看看Spring AOP 是怎样运用动态代理模式的。在Spring AOP 通过

    调用流程如下:
    1、实现InvocationHandler接口
    2、通过ProxyFactoryBean用于创建代理类(根据Advisor生成的Bean,也就是TargetBean的代理)
    3、调用invoke方法 
    然后,AOP中几个重要的概念是:
     1、关注点(concern)
       一个关注点可以是一个特定的问题,概念、或者应用程序的兴趣点。总而言之,应用程序必须达到一个目标
       安全验证、日志记录、事务管理都是一个关注点
       在oo应用程序中,关注点可能已经被代码模块化了还可能散落在整个对象模型中
    2、横切关注点(crosscutting concern)
       如何一个关注点的实现代码散落在多个类中或方法中
    3、方面(aspect)
       一个方面是对一个横切关注点模块化,它将那些原本散落在各处的,
       用于实现这个关注点的代码规整在一处,可以通过@Aspect标注或在applictionContext.xml中进行配置: 
          <aop:aspect id="fourAdviceAspect" ref="fourAdviceBean" order="2"> 
    4、建议(advice)通知
       advice是point cut执行代码,是方面执行的具体实现,如
     <aop:aspect ref="advices">
                <!--切点-->
                <aop:pointcut id="pointcut1" expression="execution(* com.jay.springAOP.aop01.Math.*(..))"/>
                <!--连接通知方法与切点-->
                <aop:before method="before" pointcut-ref="pointcut1"/>
                <aop:after method="after" pointcut-ref="pointcut1"/>
            </aop:aspect>
    5、切入点(pointcut)
       用于指定某个建议用到何处
    <aop:pointcut id="myPointcut" expression="execution(* com.wicresoft.app.service.impl.*.*(..))" method="release" /> 
    6、织入(weaving)
       将aspect(方面)运用到目标对象的过程
    7、连接点(join point)
      程序执行过程中的一个点 

     通知类型

    try{
    //前置通知
    //环绕通知
    //调用目标对象方法
    //环绕通知
    //后置通知
    }catch(){
    //异常通知
    }finally{
    //终止通知
    }

     

    注:图片来源于:http://blog.csdn.net/lirui0822/article/details/8555691 

    关于PointCut中使用的execution的说明:

    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?) 

    modifiers-pattern:方法的操作权限

    ret-type-pattern:返回值

    declaring-type-pattern:方法所在的包

    name-pattern:方法名

    parm-pattern:参数名

    throws-pattern:异常

    记忆法则就是Java定义一个方法时的样子:public boolean produceValue(int oo) throws Exception, 只要在方法名前加上包名就可以了。

    其中,除ret-type-pattern和name-pattern之外,其他都是可选的。上例中,execution(* com.spring.service.*.*(..))表示com.spring.service包下,返回值为任意类型;方法名任意;参数不作限制的所有方法。

    二、Spring AOP的简单实践

    1、首先定义一个日志切面,采用前置通知

    package com.jay.springAOP.aopDecorator;

    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;

    /**
    * 一个用于记录日志的切面
    * Created by xiang.wei on 2017/8/14.
    */
    @Component
    @Aspect
    public class LoggerAdvices {

    @Before("execution(* com.jay.springAOP.aopDecorator.*.*(..))")
    public void addLogger(JoinPoint joinPoint) {
    System.out.println(joinPoint.getSignature().getName());
    Logger logger= LoggerFactory.getLogger(this.getClass());
    //记录日志
    logger.debug("-------起始操作----------");
    logger.debug("-------结束操作-----------");
    }
    }

    2、定义一个用于性能统计的切面,其中定义了一个环绕通知

    package com.jay.springAOP.aopDecorator;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.springframework.stereotype.Component;
    
    /**
     * 一个用于性能的统计
     * Created by xiang.wei on 2017/8/14.
     */
    @Component
    @Aspect
    public class PerformanceAdvices {
    
        @Around("execution(* com.jay.springAOP.aopDecorator.*.*(..))")
        public Object execute(ProceedingJoinPoint pjp) throws Throwable {
            System.out.println(pjp.getSignature().getName());
            System.out.println("开始时间:"+System.currentTimeMillis());
            Object result = pjp.proceed();
            System.out.println("结束时间:"+System.currentTimeMillis());
            return result;
        }
    }

    3、相关的业务代码

    package com.jay.springAOP.aopDecorator;
    
    import org.springframework.stereotype.Service;
    
    /**
     * Created by xiang.wei on 2017/8/14.
     */
    @Service("paymentCommand")
    public class PaymentCommand {
    
    
        public void pay() {
            //执行下订单操作
            int j=0;
            for (int i=0;i<10000;i++ ) {
                j++;
            }
            //执行支付操作
            System.out.println("进行支付");
        }
    }
    package com.jay.springAOP.aopDecorator;
    
    import org.springframework.stereotype.Service;
    
    /**
     * Created by xiang.wei on 2017/8/14.
     */
    @Service("placeOrderCommand")
    public class PlaceOrderCommand{
    
        public void handleOrder() {
            //执行下订单操作
            int j=0;
            for (int i=0;i<100000;i++ ) {
                j++;
            }
            System.out.println("进行下单操作");
        }
    }

    4、测试类:

    package com.jay.springAOP.aopDecorator;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * Created by xiang.wei on 2017/8/15.
     */
    public class Client {
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("aopDecorator.xml");
    
            PlaceOrderCommand placeOrderCommand = ctx.getBean("placeOrderCommand", PlaceOrderCommand.class);
            placeOrderCommand.handleOrder();
    
            PaymentCommand paymentCommand = ctx.getBean("paymentCommand",PaymentCommand.class);
            paymentCommand.pay();
        }
    }

    测试结果如下:

     

  • 相关阅读:
    MSP430G2553 4x4矩阵键盘
    数论 (1)
    吐血分享一款免费看所有付费影视的app,不好用来石欠我
    Nginx如何部署静态web项目
    SpringBoot-RestTemplate实现调用第三方API
    信息收集小技巧
    kali常用命令
    kali中的Firefox改中文
    反射与注解
    MyBatis-Plus 基本用法
  • 原文地址:https://www.cnblogs.com/Fly-Bob/p/7368129.html
Copyright © 2020-2023  润新知