zoukankan      html  css  js  c++  java
  • spring的AOP编程

    基于注解的方式

    cfg.xml中

    1     <!-- 通过注释的方式来实现AOP所以要扫描包 -->
    2     <context:component-scan base-package="spring_aop_helloworld"></context:component-scan>    
    3     <!-- 要把切面自动生成代理写上 -->
    4     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    要在计算器的每个方法的开始和结束时打印日志文件

    首先计算器类被配置成bean,然后

    Logging.java

     1 package spring_aop_helloworld;
     2 
     3 import java.util.Arrays;
     4 
     5 import org.aspectj.lang.JoinPoint;
     6 import org.aspectj.lang.ProceedingJoinPoint;
     7 import org.aspectj.lang.annotation.After;
     8 import org.aspectj.lang.annotation.AfterReturning;
     9 import org.aspectj.lang.annotation.AfterThrowing;
    10 import org.aspectj.lang.annotation.Around;
    11 import org.aspectj.lang.annotation.Aspect;
    12 import org.aspectj.lang.annotation.Before;
    13 import org.aspectj.lang.annotation.Pointcut;
    14 import org.springframework.core.annotation.Order;
    15 import org.springframework.stereotype.Component;
    16 
    17 @Order(2)
    18 @Aspect
    19 @Component
    20 public class Logging {
    21     //以这种方式实现重用,不用每次都写execution(* spring_aop_helloworld.Calculator.*(int,int))
    22     @Pointcut(value="execution(* spring_aop_helloworld.Calculator.*(int,int))")
    23     public void getExpression(){}
    24     
    25     /**
    26      * 前置通知,在执行* spring_aop_helloworld.Calculator.*(int,int)(使用了AspectJ表达式)前执行此方法
    27      * 
    28      * JoinPoint j传入参数
    29      * j.getSignature().getName()获取方法名
    30      * j.getArgs()获取参数数组
    31      * */
    32     @Before(value="getExpression()")
    33     public void before(JoinPoint j){
    34         System.out.println("Before通知"+j.getSignature().getName()+":"+Arrays.asList(j.getArgs())    );
    35     }
    36     
    37     /**
    38      * 后置通知,在执行后执行此方法,不管这个方法有没有异常,能不能执行
    39      * */
    40     @After(value="execution(* spring_aop_helloworld.Calculator.*(int,int))")
    41     public void after(JoinPoint j){
    42         System.out.println("After通知"+j.getSignature().getName()+":"+Arrays.asList(j.getArgs()));
    43     }
    44     
    45     /**
    46      * 返回通知,在方法返回结果之后执行
    47      * returning="result"通过参数中和其名字相同的参数传入可以得到被代理方法的返回值
    48      * */
    49     @AfterReturning(value="execution(* spring_aop_helloworld.Calculator.*(int,int))",returning="result")
    50     public void afterReturning(JoinPoint j,Object result){
    51         System.out.println("AfterReturning通知:"+j.getSignature().getName()+":"+Arrays.asList(j.getArgs())+":"+result);
    52     }
    53     
    54     /**
    55      * 异常通知,在方法抛出异常之后执行,若没有异常则不执行
    56      * throwing="e"通过参数中和其名字相同的参数传入发生的异常。
    57      * 也可以只在指定异常抛出后通知
    58      * */
    59     @AfterThrowing(value="execution(* spring_aop_helloworld.Calculator.*(int,int))",throwing="e")
    60     public void afterEhroeing(JoinPoint j,Exception e){
    61         System.out.println("AfterThrowing通知:"+j.getSignature().getName()+":"+Arrays.asList(j.getArgs())+":"+e);
    62     }
    63     
    64     /**
    65      * 环绕通知
    66      * */
    67     @Around(value="execution(* spring_aop_helloworld.Calculator.*(int,int))")
    68     public Object around(ProceedingJoinPoint p){
    69         String methodName = p.getSignature().getName();
    70         Object o = null;
    71         
    72         try {
    73             System.out.println("-->等同前置通知");
    74             o = (int) p.proceed();
    75             System.out.println("-->等同返回通知");
    76         } catch (Throwable e) {
    77 //            throw new RuntimeException(e);
    78             System.out.println("-->等同异常通知");
    79         }
    80         System.out.println("-->等同后置通知");
    81         return o;
    82     }
    83 }

    验证器类

    package spring_aop_helloworld;
    
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.core.annotation.Order;
    import org.springframework.stereotype.Component;
    
    
    /**
     * Order(1)代表切面被调用的优先级,数字越小越先调用
     * Aspect 表示这是一个切面
     * Component 表示这是一个组件,IOC容器可以扫描到
     * */
    @Order(1)
    @Aspect
    @Component
    public class Validation {
        
        //spring_aop_helloworld.Logging.getExpression()返回要代理的方法,实现重用
        @Before(value="spring_aop_helloworld.Logging.getExpression()")
        public void before_validation(JoinPoint j){
            System.out.println("0000验证前置"+j.getSignature().getName());
        }
        
    }

    基于配置文件的方式

    cfg.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <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-4.0.xsd">
        
        
        <bean id="calculatorImpl" class="spring_aop_xml.CalculatorImpl"></bean>
        <bean id="logging" class="spring_aop_xml.Logging"></bean>
        <bean id="validation" class="spring_aop_xml.Validation"></bean>
        
        <aop:config>
            <aop:pointcut expression="execution(* spring_aop_xml.Calculator.*(int, int))" id="expression"/>
            <aop:aspect ref="logging" order="2">
                <aop:before method="before" pointcut-ref="expression"/>
                <aop:after method="after" pointcut-ref="expression"/>
                <aop:after-returning method="afterReturning" pointcut-ref="expression" returning="result"/>
                <aop:after-throwing method="afterthrowing" pointcut-ref="expression" throwing="e"/>
                <aop:around method="around" pointcut-ref="expression"/>
            </aop:aspect>
            <aop:aspect ref="validation" order="1">
                <aop:before method="before_validation" pointcut-ref="expression"/>
            </aop:aspect>
        </aop:config>
        
    </beans>

    验证器类和日志文件类都和基于注解的一样,只不过去掉注解。

    传统的代理方法实现面向切面编程

    package spring_aop_old;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class CalculatorProxy {
        private Calculator c;
        
        //通过构造器传入被代理的对象
        public CalculatorProxy(Calculator c) {
            this.c = c;
        }
        //获取代理对象
        public Object getInstance(){
            Object proxy = null;
            
            InvocationHandler handler = new InvocationHandler() {
            
                /**
                 * 当想要运行被代理对象的相关方法时,代理对象通过调用invoke来调用被代理对象的方法
                 * 
                 * Object proxy是getInstance()返回的代理对象
                 * Method method被代理对象的方法
                 * Object[] args被代理对象的方法中的参数
                 * */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) {
                    Object result = null;
                    
                    System.out.println("之前..类似前置");
                    try {
                        result = method.invoke(c, args);
                    } catch (Exception e) {
                        System.out.println("异常..类似异常");
                    }
                    System.out.println("之后..类似后置");
                    
                    return result;
                }
            };
            proxy = Proxy.newProxyInstance(c.getClass().getClassLoader(), new Class[]{Calculator.class}, handler);
            
            return proxy;
        }
    }
    package spring_aop_old;
    
    public class TestAOPHello {
    
        public static void main(String[] args) {
            Calculator c = (Calculator) new CalculatorProxy(new CalculatorImpl()).getInstance();
            System.out.println(c.add(1, 2));
            System.out.println(c.div(10, 0));
        }
    
    }
  • 相关阅读:
    软件测试学习总结
    MySQL数据库中主键和索引的区别和联系
    什么是接口测试及其测试流程
    bug生命周期
    啊这...2-get/post请求区别,来给你看看post请求url中传参
    啊这...1-get/post请求区别,你还在认为get只能在url传参吗?传json格式会咋样?
    关于博客园全站内容审核中...如出现此问题:请移步xxx
    git-2-企业级gitlab的使用及管理工具Sourcetree
    fiddler-12-Proxifier+fiddler进行PC端抓包
    微信小程序弹出订阅消息确认弹窗的限制
  • 原文地址:https://www.cnblogs.com/feifeiyun/p/6519927.html
Copyright © 2011-2022 走看看