• Spring AOP


    在一个方法前面和后面增加通知,不改变原来的方法,使程序的扩展性加大。

    给Demo 的demo2方法前后加通知:

    applicationContext.xml配置:

        <!-- after 和 before类由Spring管理 ,因为要注入切面-->
        <bean id="myAfterAdvice" class="com.spring.advice.MyAfterAdvice"></bean>
        <bean id="myBeforeAdvice" class="com.spring.advice.MyBeforeAdvice"></bean>
        <!-- 配置切面 -->
        <aop:config >
            <aop:pointcut expression="execution(* com.spring.demo.Demo.demo2())" id="point"/>
            <aop:advisor advice-ref="myAfterAdvice" pointcut-ref="point"/>
            <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="point"/>
        </aop:config>
        <!-- demo类由Spring管理,才能实现切面 -->
        <bean id="demo" class="com.spring.demo.Demo"></bean>

    Demo类:

    public class Demo {
        public void demo1() {
            System.out.println("demo1");
        }
        public void demo2() {
            System.out.println("demo2");
        }
        public void demo3() {
            System.out.println("demo3");
        }
    }

    test:

        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            Demo demo = applicationContext.getBean("demo",Demo.class);
            demo.demo1();
            demo.demo2();
            demo.demo3();

    前置通知,要实现MethodBeforeAdvice接口(后置通知同理,实现AfterReturningAdvice接口):

    public class MyBeforeAdvice implements MethodBeforeAdvice{
        @Override
        public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
            System.out.println("before advice");
        }
    }

    输出结果:

    demo1
    before advice
    demo2
    after adivce
    demo3

     前置通知和后置通知参数:

    public class MyBeforeAdvice implements MethodBeforeAdvice{
        @Override
        public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
            //arg0是切点的方法名
            System.out.println(arg0.getName());
            //arg1是切点的参数
            if(arg1.length>0) {
                System.out.println(arg1[0]);
            }
            //arg2是切点对象
            System.out.println(arg2);
            System.out.println("before advice");
        }
    }
    
    public class MyAfterAdvice implements AfterReturningAdvice{
        @Override
        public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
            //arg0是切点方法的返回值
            System.out.println(arg0.toString());
            //arg1是切点方法
            System.out.println(arg1.getName());
            //arg2是切点方法的参数
            if(arg2.length>0) {
                System.out.println(arg2[0]);
            }
            //arg3是切点对象
            System.out.println(arg3);
            
            System.out.println("after adivce");
        }
    }

    *通配符的使用:

        <aop:config>
        <!-- *代表通配,比如 (* com.spring.demo.Demo.*())代表匹配Demo类的所有无参方法
             (* com.spring.demo.Demo.*(..))代表匹配Demo类的所有任意参数方法
             (* com.spring.demo.*.*(..))代表匹配com.spring.demo包下所有类的所有的任意参数方法
              *更多使用方法类似
        -->
            <aop:pointcut expression="execution(* com.spring.demo.Demo.demo1(..))" id="point"/>
            <aop:advisor advice-ref="myAfterAdvice" pointcut-ref="point"/>
            <aop:advisor advice-ref="myBeforeAdvice" pointcut-ref="point"/>
        </aop:config>
        <!-- demo类由Spring管理,才能实现切面 -->
        <bean id="demo" class="com.spring.demo.Demo"></bean>

     给方法加异常通知(使用aop:aspect标签):

    applicationContext.xml:

        <!-- 自己定义一个异常通知类,必须交给Spring管理 -->    
        <bean id="myException" class="com.spring.demo.MyException"></bean>
        <!-- 配置异常通知 -->
        <aop:config>
        <!-- 给Demor 的demo1方法配置异常通知 -->
            <aop:pointcut expression="execution(* com.spring.demo.Demo.demo1(..))" id="myPoint"/>
        <!-- 配置自己定义的异常通知类的id -->
            <aop:aspect ref="myException">
            <!-- 配置自己定义的异常通知类的方法 -->
                <aop:after-throwing method="myThrowException" pointcut-ref="myPoint"/>
            </aop:aspect>
        </aop:config>
        <!-- 要加入异常通知的类必须由Spring管理 -->
        <bean id="demo" class="com.spring.demo.Demo"></bean>

    自己定义的异常通知类:(当demo1方法出现异常时,会运行自定义的异常通知。注意:如果在demo1内使用cry,catch

    Spring不会知道程序出异常了,因为异常被cry,catch处理了)

    public class MyException {
        public void myThrowException() {
            System.out.println("Throw Exception!!");
        }
    }

    给方法加异常通知(使用aop:aspect标签):

    applicationContext.xml配置文件:

        <!-- 自己定义一个异常通知类,必须交给Spring管理 -->    
        <bean id="myException" class="com.spring.demo.MyException"></bean>
        <!-- 配置异常通知 -->
        <aop:config>
        <!-- 给Demor 的demo1方法配置异常通知 -->
            <aop:pointcut expression="execution(* com.spring.demo.Demo.demo1(..))" id="myPoint"/>
        <!-- 配置自己定义的异常通知类的id -->
            <aop:advisor advice-ref="myException" pointcut-ref="myPoint" />
        </aop:config>
        <!-- 要加入异常通知的类必须由Spring管理 -->
        <bean id="demo" class="com.spring.demo.Demo"></bean>

    自定义的异常通知对象:

    //自定义的异常通知对象,实现ThrowAdvice接口,实现afterThrowing方法
    public class MyException implements ThrowsAdvice{
        //方法名必须是afterException,第一种只有一个异常对象
        public void afterThrowing(Exception e){
            System.out.println("Throw Exception!!");
        }
        //第二种:方法名一样,参数不一样,第一个参数是切点方法,第二个参数是切点方法参数,
        //第三个参数是切点对象,第四个是异常对象
        public void afterThrowing(Method m, Object[] args,Object target, Exception ex) {
            System.out.println(m.getName());
            System.out.println(args.length);
            System.out.println(target);
            System.out.println("Throw Exception!!!!");
        }
    }

    环绕通知:

    配置文件:

        <!-- 自己定义的环绕通知类 -->
        <bean id="arround" class="com.spring.advice.AroundAdvice"></bean>
        <!-- 配置环绕通知 -->
        <aop:config>
        <!-- 给Demor 的demo1方法配置环绕通知 -->
            <aop:pointcut expression="execution(* com.spring.demo.Demo.demo1(..))" id="myPoint"/>
        <!-- 配置自己定义的环绕通知类的id -->
            <aop:advisor advice-ref="arround" pointcut-ref="myPoint" />
        </aop:config>
        <!-- 要加入环绕通知的类必须由Spring管理 -->
        <bean id="demo" class="com.spring.demo.Demo"></bean>

    环绕通知类:

    //环绕通知,将前置和后置通知写在一起,环绕通知类需要实现MethodInterceptor接口
    public class AroundAdvice implements MethodInterceptor{
        @Override
        public Object invoke(MethodInvocation arg0) throws Throwable {
            //前置通知
            System.out.println("before!!");
            //通知完毕,执行方法
            Object obj = arg0.proceed();
            //后置通知
            System.out.println("after");
            return obj;
        }
    }

    使用 aop:aspect配置前置,后置,异常通知:

        <!-- 通知对象,由Spring管理 -->
        <bean id="myAdvice" class="com.spring.advice.MyAdvice"></bean>
        <aop:config>
        <!-- 无参数的方法配置通知 -->
            <aop:aspect ref="myAdvice">
                <aop:pointcut  expression="execution(* com.spring.demo.Demo.demo1())" id="myPoint"/>
                <aop:before method="before" pointcut-ref="myPoint"/>
                <!-- after一定会执行 -->
                <aop:after method="after" pointcut-ref="myPoint"/>
                <!-- after-returning 程序出异常的话不会执行 -->
                <aop:after-returning method="aftering" pointcut-ref="myPoint"/>
                <aop:after-throwing method="myThrow" pointcut-ref="myPoint"/>
            </aop:aspect>
        <!-- 有参数的方法配置通知 -->
            <aop:aspect ref="myAdvice">
            <!-- args里有几个参数,arg-name里就必须有几个参数,而且名字必需一样 -->
                <aop:pointcut expression="execution(* com.spring.demo.Demo.demo2(String,int)) and args(name,index)" id="myPoint2"/>
                <aop:before method="beforeArgs" arg-names="name,index" pointcut-ref="myPoint2"/>
            </aop:aspect>
        </aop:config>
        <bean id="demo" class="com.spring.demo.Demo"></bean>

    通知类:

    //使用<aop:aspect>来配置前置、后置、异常通知
    public class MyAdvice {
        //前置通知
        public void before() {
            System.out.println("before");
        }
        //后置通知
        public void after() {
            System.out.println("after");
        }
        public void aftering() {
            System.out.println("aftering");
        }
        public void myThrow() {
            System.out.println("Exception!!");
        }
        //带参数的前置通知
        public void beforeArgs(String name,int index) {
            System.out.println("before="+name+"--"+index);
        }
    }

    测试代码:

    public class Test {
        public static void main(String[] args) {
            ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
            Demo demo = applicationContext.getBean("demo",Demo.class);
            demo.demo1();
            System.out.println("==================");
            demo.demo2("Spring", 520);
        }
    }
  • 相关阅读:
    记一次文件上传报错解决过程The temporary upload location is not vali
    Redis反序列化LocalDateTime时报错
    Redis连接池Lettuce Jedis 区别
    Java获取时间打印到控制台
    Java多线程之volatile关键字
    Java多线程之Future,有返回值的线程
    ccf集合竞价
    增广路径求解最大流
    2016年9月ccf
    hash表的建立和查找
  • 原文地址:https://www.cnblogs.com/lastingjava/p/9992351.html
Copyright © 2020-2023  润新知