框架之Spring的AOP

作者: vaneL | 来源:发表于2017-08-01 10:18 被阅读0次

    首先在学习AOP之前,先了解一下动态代理。

    动态代理指的是通过一个代理对象来创建需要的业务对象,然后在这个代理对象中统一进行各种需求的处理

    1.写一个类实现相应的InvocationHandler接口,以后创建对象就完全通过这个代理类来进行创建
    2.创建要代理的对象
    代理模式的详解

    public class LogProxy implements InvocationHandler {
           //2、创建一个代理对象
           private Object target;
           private LogProxy( ){   }
           //3、创建一个方法来生成对象
           //创建一个静态的newInstance方法来创建代理对象
        public static Object getInstance(Object o) {
            //3.1、创建LogProxy对象
            LogProxy proxy = new LogProxy();
            //3.2、设置这个代理对象
            proxy.target = o;
            //3.3、通过Proxy的方法创建代理对象
            //第一个参数是要代理对象的classLoader
            //第二个参数是要代理对象实现的所有接口
            //第三个参数是实现类InvocationHandler的对象
            //此时的result就是一个代理对象,代理的是o    【result代理o】
            Object result = Proxy.newProxyInstance(o.getClass().getClassLoader(), 
                                                   o.getClass().getInterfaces(), 
                                                   proxy);
            return result;
        }
    
         /**
         * 当有了代理对象之后,不管这个代理对象执行什么方法,都会调用以下的invoke方法
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //      if(method.getName().equals("add")||method.getName().equals("delete")) {
    //          Logger.info("进行了相应的操作");
    //      }
            Object obj = method.invoke(target, args);
            if(method.isAnnotationPresent(LogInfo.class)) {
                LogInfo li = method.getAnnotation(LogInfo.class);
                Logger.info(li.value());
            }
            return obj;
        }
    
    AOP.jpg
    基于XML配置的Spring AOP:
    <?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"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
            
            <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
            <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
            <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
            <bean id="logHandler" class="com.xrq.aop.LogHandler" />
            
            <aop:config>
                <aop:aspect id="time" ref="timeHandler" order="1">
                    <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                    <aop:before method="printTime" pointcut-ref="addTime" />
                    <aop:after method="printTime" pointcut-ref="addTime" />
                </aop:aspect>
                <aop:aspect id="log" ref="logHandler" order="2">
                    <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                    <aop:before method="LogBefore" pointcut-ref="printLog" />
                    <aop:after method="LogAfter" pointcut-ref="printLog" />
                </aop:aspect>
            </aop:config>
    </beans>
    
    使用注解配置AOP:
    @Service("math")
    public class Math{
        //加
        public int add(int n1,int n2){
            int result=n1+n2;
            System.out.println(n1+"+"+n2+"="+result);
            return result;
        }
        
        //减
        public int sub(int n1,int n2){
            int result=n1-n2;
            System.out.println(n1+"-"+n2+"="+result);
            return result;
        }
    }
    /**
     * @Component表示该类的实例会被Spring IOC容器管理;
     * @Aspect表示声明一个切面;
     * @Before表示before为前置通知,通过参数execution声明一个切点
    **/
    
    @Component
    @Aspect
    public class Advices {
        @Before("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")
        public void before(JoinPoint jp){
            System.out.println("----------前置通知----------");
            System.out.println(jp.getSignature().getName());
        }
        
        @After("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")
        public void after(JoinPoint jp){
            System.out.println("----------最终通知----------");
        }
    }  // 在xml中配置为<aop:aspectj-autoproxy proxy-target-class="true">
    
    AspectJ切点函数:

    @AspectJ使用AspectJ专门的切点表达式描述切面。

    AspectJ表达式可分为四类:

    • 方法切点函数:通过描述目标类方法信息定义连接点。
    • 方法参数切点函数:通过描述目标类方法入参信息定义连接点。
    • 目标类切点函数:通过描述目标类类型信息定义连接点。
    • 代理类切点函数:通过描述代理类信息定义连接点。

    常见的AspectJ表达式函数:
    execution():满足匹配模式字符串的所有目标类方法的连接点
    @annotation():任何标注了指定注解的目标方法链接点
    args():目标类方法运行时参数的类型指定连接点
    @args():目标类方法参数中是否有指定特定注解的连接点
    within():匹配指定的包的所有连接点
    target():匹配指定目标类的所有方法
    @within():匹配目标对象拥有指定注解的类的所有方法
    @target():匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解
    this():匹配当前AOP代理对象类型的所有执行方法
    最常用的是:execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)切点函数,可以满足多数需求。

    AspectJ通知注解:
    /**
     * 通知类,横切逻辑
     */
    @Component
    @Aspect
    public class Advices {
        //切点
        @Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.a*(..))")
        public void pointcut(){
        }
        
        //前置通知
        @Before("pointcut()")
        public void before(JoinPoint jp){
            System.out.println(jp.getSignature().getName());
            System.out.println("----------前置通知----------");
        }
        
        //最终通知
        @After("pointcut()")
        public void after(JoinPoint jp){
            System.out.println("----------最终通知----------");
        }
        
        //环绕通知
        @Around("execution(* com.zhangguo.Spring052.aop04.Math.s*(..))")
        public Object around(ProceedingJoinPoint pjp) throws Throwable{
            System.out.println(pjp.getSignature().getName());
            System.out.println("----------环绕前置----------");
            Object result=pjp.proceed();
            System.out.println("----------环绕后置----------");
            return result;
        }
        
        //返回结果通知
        @AfterReturning(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.m*(..))",returning="result")
        public void afterReturning(JoinPoint jp,Object result){
            System.out.println(jp.getSignature().getName());
            System.out.println("结果是:"+result);
            System.out.println("----------返回结果----------");
        }
        
        //异常后通知
        @AfterThrowing(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.d*(..))",throwing="exp")
        public void afterThrowing(JoinPoint jp,Exception exp){
            System.out.println(jp.getSignature().getName());
            System.out.println("异常消息:"+exp.getMessage());
            System.out.println("----------异常通知----------");
        }
    }
    

    结果
    add
    ----------前置通知----------
    100+0=100
    ----------最终通知----------
    sub
    ----------环绕前置----------
    100-0=100
    ----------环绕后置----------
    100*0=0
    mut
    结果是:0
    ----------返回结果----------
    div
    异常消息:/by zero
    ----------异常通知----------

    相关文章

      网友评论

        本文标题:框架之Spring的AOP

        本文链接:https://www.haomeiwen.com/subject/zaodlxtx.html