30--基于Schema的AOP

作者: 闲来也无事 | 来源:发表于2018-11-05 16:32 被阅读15次

    前几篇已经对AOP中的相关概念做了解释,但是都是通过编码方式实现的,每次都需要通过ProxyFactory去创建代理,接下来我们介绍Spring中的自动代理方式来实现AOP,基于Schema配置文件方式和基于@AspectJ注解的方式。当然自动代理实现的机制,放到后面的章节分析,本篇权当温习,也为接下来的源码分析做好铺垫。

    1.普通切面
    • 目标对象
    package com.lyc.cn.v2.day06;
    
    public interface Animal {
        void sayHello(String name,int age);
    
        void sayException(String name, int age);
    }
    
    package com.lyc.cn.v2.day06;
    
    public class Cat implements Animal {
    
        @Override
        public void sayHello(String name, int age) {
            System.out.println("--调用被增强方法");
        }
    
        @Override
        public void sayException(String name, int age) {
            System.out.println("==抛出异常:" + 1 / 0);
        }
    }
    
    • 切面类
    package com.lyc.cn.v2.day06;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class CatAspect {
    
        /**
         * 前置增强
         */
        public void beforeAdvice(String name, int age) {
            System.out.println("==前置增强,name:" + name + ",age:" + age);
        }
    
        /**
         * 后置异常增强
         */
        public void afterExceptionAdvice(String name, int age) {
            System.out.println("==后置异常增强,name:" + name + ",age:" + age);
        }
    
        /**
         * 后置返回增强
         */
        public void afterReturningAdvice(String name, int age) {
            System.out.println("==后置返回增强,name:" + name + ",age:" + age);
        }
    
        /**
         * 后置最终增强
         */
        public void afterAdvice(String name, int age) {
            System.out.println("==后置最终增强,name:" + name + ",age:" + age);
        }
    
        /**
         * 环绕增强
         */
        public Object roundAdvice(ProceedingJoinPoint p, String name, int age) {
            System.out.println("==环绕增强开始,name:" + name + ",age:" + age);
            Object o = null;
            try {
                o = p.proceed();
                Object[] args = p.getArgs();
                if (null != args) {
                    for (int i = 0; i < args.length; i++) {
                        System.out.println("==环绕增强参数值:" + args[i]);
                    }
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }
            System.out.println("==环绕增强结束,name:" + name + ",age:" + age);
            return o;
        }
    
    }
    
    • 配置文件
    <?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.xsd">
    
        <!-- 目标对象 -->
        <bean id="cat" class="com.lyc.cn.v2.day06.Cat"/>
    
        <!-- 切面类-->
        <bean id="catAspect" class="com.lyc.cn.v2.day06.CatAspect"/>
    
        <!--AOP配置(一)-->
        <aop:config proxy-target-class="true">
            <!-- 切入点-->
            <aop:pointcut id="pointcut" expression="execution(* com.lyc.cn.v2.day06..*.*(..)) and args(name,age)"/>
            <aop:aspect ref="catAspect" order="0">
                <!--前置增强,在切入点选择的方法之前执行-->
                <aop:before method="beforeAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
                <!--后置异常增强,在切入点选择的方法抛出异常时执行-->
                <aop:after-throwing method="afterExceptionAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
                <!--后置返回增强,在切入点选择的方法正常返回时执行-->
                <aop:after-returning method="afterReturningAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
                <!--后置最终增强,在切入点选择的方法返回时执行,不管是正常返回还是抛出异常都执行-->
                <aop:after method="afterAdvice" pointcut-ref="pointcut" arg-names="name,age"/>
                <!--
                    环绕增强,环绕着在切入点选择的连接点处的方法所执行的通知,可以决定目标方法是否执行,
                    什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值
                -->
                <aop:around method="roundAdvice" pointcut-ref="pointcut" arg-names="p,name,age"/>
            </aop:aspect>
        </aop:config>
    </beans>
    
    • 测试类及结果
    package com.lyc.cn.v2.day06;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyTest {
    
        @Test
        public void test1() {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day06.xml");
            Cat cat = ctx.getBean("cat", Cat.class);
            cat.sayHello("美美", 3);
        }
    
    
        @Test
        public void test2() {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day06.xml");
            Cat cat = ctx.getBean("cat", Cat.class);
            cat.sayException("美美", 3);
        }
    }
    
    // 测试1
    ==前置增强,name:美美,age:3
    ==环绕增强开始,name:美美,age:3
    --调用被增强方法
    ==环绕增强参数值:美美
    ==环绕增强参数值:3
    ==环绕增强结束,name:美美,age:3
    ==后置最终增强,name:美美,age:3
    ==后置返回增强,name:美美,age:3
    
    // 测试2
    ==前置增强,name:美美,age:3
    ==环绕增强开始,name:美美,age:3
    
    ==环绕增强结束,name:美美,age:3
    ==后置最终增强,name:美美,age:3
    ==后置返回增强,name:美美,age:3java.lang.ArithmeticException: / by zero
        at com.lyc.cn.v2.day06.Cat.sayException(Cat.java:12)
        at com.lyc.cn.v2.day06.Cat$$FastClassBySpringCGLIB$$336350b6.invoke(<generated>
    

    相信大家对这样的配置已经非常熟悉了,而且在配置文件中已经有了比较完善的说明,而且Schema的配置方式已经不是那么流行,所以我们不做过多的介绍。

    2.引介增强

    Spring引入允许为目标类对象引入新的接口。

    • 引介接口和实现
    package com.lyc.cn.v2.day06;
    
    /**
     * 引入
     * @author: LiYanChao
     * @create: 2018-10-28 15:48
     */
    public interface IIntroduce {
        void sayIntroduce();
    }
    
    package com.lyc.cn.v2.day06;
    
    /**
     * @author: LiYanChao
     * @create: 2018-10-28 15:48
     */
    public class IntroduceImpl implements IIntroduce {
        @Override
        public void sayIntroduce() {
            System.out.println("--引入");
        }
    }
    
    • 修改配置文件配置引介增强
      <aop:aspect/>标签中加入如下配置:
    <!--
        引入
        1、types-matching:匹配需要引入接口的目标对象的AspectJ语法类型表达式。
        2、implement-interface:定义需要引入的接口。
        3、default-impl和delegate-ref:定义引入接口的默认实现,二者选一,
          default-impl是接口的默认实现类全限定名,而delegate-ref是默认的实现的委托Bean名。
    -->
    <aop:declare-parents types-matching="com.lyc.cn.v2.day06.Cat"
                     implement-interface="com.lyc.cn.v2.day06.IIntroduce"
                     default-impl="com.lyc.cn.v2.day06.IntroduceImpl"/>
    
    • 测试及结果
    @Test
    public void test3() {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("v2/day06.xml");
        // 注意:getBean获取的是cat
        IIntroduce introduce = ctx.getBean("cat", IIntroduce.class);
        introduce.sayIntroduce();
    }
    
    --引入
    
    3.总结

    本篇主要回顾一下基于Schema的AOP的配置方式,都是基于配置文件,当然这里涉及到的知识点也很多,这里只是做了简单的介绍,关于更多的配置,大家可以参考Spring的官方文档。

    相关文章

      网友评论

        本文标题:30--基于Schema的AOP

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