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);
    }
}

 

posted @ 2018-11-20 22:53  caiJava  阅读(212)  评论(0)    收藏  举报