Spring基礎複習-SpringAOP

項目地址:https://gitee.com/chuyunfei/learn.git
一、AOP的概念
:面向切面編程,即將多個業務線的共有操作進行提取,集成爲一個環節,所有需要這個環節的業務可以共用這個切面
:spring對aop的支持是方法級別的支持

二、動態代理基礎
JDK動態代理-》基於接口的動態代理:
1、需要一個接口
public interface Actions {
String askName(String person) throws Exception;
}
2、需要一個實現類,也就是需要被代理的對象
public class ActionsImpl implements Actions {
private String myName = “楚雲飛”;
public String askName(String person) throws Exception{
if(person.equals(myName)){
return “myName is ” + myName;
}else {
throw new Exception(“不知道你在說啥!”);
}
}
}
3、需要一個實現代理處理器接口的代理處理器
public class ProxyHandler implements InvocationHandler {
//被代理對象,執行目標方法的實際對象
private Object target;
public ProxyHandler(Object target){
this.target = target;
}
/**
* @param proxy:鏈接Handler和target的代理對象
* @param method:要執行的方法
* @param args:執行方法的參數
* @return:返回真正的方法執行的結果
* @throws Throwable
*/
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
//表示proxy並不是被代理的對象,所以需要保存被代理對象
System.out.println(proxy.getClass().getName());
System.out.println(“準備執行方法:” + method.getReturnType() + ” ” + method.getName() +
“(” + Arrays.toString(args) + “)”);
//真正的執行方法
Object result = method.invoke(target,args);
System.out.println(“執行方法:” + method.getReturnType() + ” ” + method.getName() +
“(” + Arrays.toString(args) + “):完成,準備返回執行的結果!”);
return result;
}
}
4、需要一個生成代理對象的工廠類
public class ProxyBeanFactory {
/**
* 獲取一個基於JDK動態代理的代理對象
* @param target
* @return
*/
public static Object getProxyBean(Object target){
return Proxy.newProxyInstance(
//一個類加載器,這裏選用傳入的對象進行加載
target.getClass().getClassLoader(),
//該對象實現的全部接口
target.getClass().getInterfaces(),
//一個實現了處理器接口的bean,不能是null:Objects.requireNonNull(handler);
new ProxyHandler(target)
);
}
}
5、需要一個測試用的類
public class JDKProxyApplication {
public static void main(String[] args) throws Exception{
Actions actions = new ActionsImpl();
Actions proxied = (Actions) ProxyBeanFactory.getProxyBean(actions);
String name = proxied.askName(“楚雲飛”);
System.out.println(name);
//output
// com.sun.proxy.$Proxy0
// 準備執行方法:class java.lang.String askName([楚雲飛])
// 執行方法:class java.lang.String askName([楚雲飛]):完成,準備返回執行的結果!
// myName is 楚雲飛
}
}
6、注意事項:
:需要被代理的對象實現接口纔可以進行代理,只能代理接口裏面的方法
:需要保存被代理的對象

CGLIB動態代理-》基於繼承的動態代理:
1、需要一個可以繼承的待代理類:
    public class Actions {
        private String myName = "楚雲飛";
        public String askName(String person) throws Exception{
            if(person.equals(myName)){
                return "myName is " + myName;
            }else {
                throw new Exception("不知道你在說啥!");
            }
        }
    }
2、一個Cglib的方法攔截接口的實現類:
    public class CglibEnhancerProxy implements MethodInterceptor {
        public Object getProxy(Class clazz){
            //聲明一個enhancer對象來實現動態代理
            Enhancer enhancer = new Enhancer();
            //設置代理的父類,cglib代理基於繼承來實現動態代理
            enhancer.setSuperclass(clazz);
            //設置代理的攔截器對象實現類
            enhancer.setCallback(this);
            //創建一個代理對象
            return enhancer.create();
        }
        /**
         * @param object:被代理的對象
         * @param method:被攔截的方法
         * @param args:被攔截方法的參數
         * @param methodProxy:代理的方法,用於執行被代理對象的方法
         * @return:執行的真正的返回值
         * @throws Throwable
         */
        public Object intercept(Object object,Method method,Object[] args,MethodProxy methodProxy) throws Throwable{
            System.out.println("準備執行方法:" + method.getReturnType() + " " + method.getName() +
                    "(" + Arrays.toString(args) + ")");
            //真正的執行方法,執行父類的方法
            Object result = methodProxy.invokeSuper(object,args);
            System.out.println("執行方法:" + method.getReturnType() + " " + method.getName() +
                    "(" + Arrays.toString(args) + "):完成,準備返回執行的結果!");
            return result;
        }
    }
3、一個測試的主類:
    public class CglibProxyApplication {
        public static void main(String[] args) throws Exception{
            Actions action = (Actions) new CglibEnhancerProxy().getProxy(Actions.class);
            String name = action.askName("楚雲飛");
            System.out.println(name);
            //output
    //        準備執行方法:class java.lang.String askName([楚雲飛])
    //        執行方法:class java.lang.String askName([楚雲飛]):完成,準備返回執行的結果!
    //        myName is 楚雲飛
        }
    }
4、注意事項:
    :基於繼承的代理,所以被代理的類不能被final修飾
    :同時,實體的方法也不能被final修飾,否則將無法被攔截

三、AOP的配置語法基礎
註解的方式進行配置:
1、需要一個實際接口以及用於增強類型的另外一個接口
public interface Actions {
String askName(String person) throws Exception;
}

    public interface ActionPlus {
        boolean match(String name);
    }
2、兩個接口所對應的實現類
    @Component("actionsImpl")//註冊一個bean
    public class ActionsImpl implements Actions {
        private String myName = "楚雲飛";
        public String askName(String person) throws Exception{
            if(person.equals(myName)){
                return "myName is " + myName;
            }else {
                throw new Exception("不知道你在說啥!");
            }
        }
    }
    //這個類沒有被註冊
    public class ActionPlusImpl implements ActionPlus {
        public boolean match(String name){
            return name != null;
        }
    }
3、需要一個配置類來開啓對aop的支持
    @Configuration//標識其爲配置類
    @ComponentScan(basePackages = "springaop.aop.annotion")//包掃描
    @EnableAspectJAutoProxy//開啓對AOP的支持
    public class RootConfig {
    }
4、需要一個切面
    @Aspect
    /**
     * 這是一個切面:
     * 1、@Aspect 是三方的註解,該註解不會將這個切面註冊爲一個bean,如果要將其註冊爲一個bean的話,需要配置或者運用註解將其註冊到spring容器裏面
     */
    @Component
    //將這個切面註冊爲一個bean
    @Order(1)
    //當多個切面的時候可以規定切面執行的順序,實行責任鏈模式
    public class ActionsAspect {

        /**
         * 對已經存在的類進行動態的增強:引入
         * 注意:AOP無法對引入的方法再次進行攔截,也就是說無法對aop生成的動態代理方法進行攔截
         */
        @DeclareParents(
                //對那個類型進行增強,應該是一個具體的實現類,下面的表達式表示爲 ActionsImpl+ 增加一個接口的功能
                value = "springaop.aop.annotion.service.actions.impl.ActionsImpl+"
                //上面一個增加功能的默認實現類是這個屬性所配置的類來實現
                ,defaultImpl = ActionPlusImpl.class
        )
        public ActionPlus actionPlus;

        /**
         * 各個通知的執行順序:
         * around->before->after->around->afterReturning/afterThrowing
         */

        /**
         * @Pointcut 用於定義一個切點,使用一個方法來提供依附點,不然沒有地方打註解
         * execution:在方法執行時會觸發這個攔截動作
         * *:方法的返回值不限
         * springaop.aop.annotion.service.actions.impl.ActionsImpl:要攔截的方法的類的全限定名稱
         * askName:要攔截的方法名稱
         * (..):方法的參數不限
         * 含義:
         * 當springaop.aop.annotion.service.actions.impl.ActionsImpl#askName方法執行時,觸發攔截動作,無論這個方法有幾個
         * 重載的方法,無論它的返回值是什麼類型,我都要攔截
         */
        @Pointcut(value = "execution(* springaop.aop.annotion.service.actions.impl.ActionsImpl.askName(..))")
        public void pointCut0(){}

        /**
         * 前置通知:執行目標方法之前
         */
        @Before(value = "pointCut0()")
        public void beforePointCut0(JoinPoint joinPoint){
            System.out.println("pointCut0 前置通知:執行" +
                    joinPoint.getSignature().getName() + "(" + Arrays.toString(joinPoint.getArgs()) + ")"
                    + "方法之前!");
        }

        /**
         * 後置通知:執行目標方法之後
         */
        @After("pointCut0()")
        public void afterPointCut0(JoinPoint joinPoint){
            System.out.println("pointCut0 後置通知:執行" +
                    joinPoint.getSignature().getName() + "(" + Arrays.toString(joinPoint.getArgs()) + ")"
                    + "方法之後!");
        }

        /**
         * 後置返回通知:在目標方法返回執行的目標值之後
         * result用於指定方法執行結果的參數名稱
         */
        @AfterReturning(value = "pointCut0()",returning = "result")
        public void afterReturningPointCut0(JoinPoint joinPoint,Object result){
            System.out.println("pointCut0 後置通知:執行" +
                    joinPoint.getSignature().getName() + "(" + Arrays.toString(joinPoint.getArgs()) + ")"
                    + "方法正確返回之後的結果是:" + result);
        }

        /**
         * 後置異常通知:在執行目標方法出現異常之後
         * @param joinPoint:鏈接點,用於獲取一些必要信息
         * @param exception
         */
        @AfterThrowing(value = "pointCut0()",throwing = "exception")
        public void afterThrowingPointCut0(JoinPoint joinPoint,Exception exception){
            System.out.println("pointCut0 後置通知:執行" +
                    joinPoint.getSignature().getName() + "(" + Arrays.toString(joinPoint.getArgs()) + ")"
                     + "方法發生異常: " + exception.getMessage());
        }

        /**
         * 環繞通知相當於前置通知和後置通知合併一起,但是卻更加強大:
         * 1、環繞通知可以影響、操控被攔截方法的執行,所以可以篡改方法的執行結果
         * 2、環繞通知可以對執行方法的異常進行處理
         * 3、環繞通知可以獲取連接點的相關信息
         * @param joinPoint(ProceedingJoinPoint):鏈接點,也就是待執行的方法
         * @return:該方法執行的真正的結果
         */
        @Around("pointCut0()")
        public Object aroundPointCut0(ProceedingJoinPoint joinPoint){

            System.out.println("pointCut0 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之前-------");
            Object result = null;
            try{
                //真正的執行被攔截的方法
                result = joinPoint.proceed();
                System.out.println("pointCut0 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後-------");
            }catch(Throwable throwable){
                //可以進行異常處理
                throwable.printStackTrace();
                System.out.println("pointCut0 環繞通知:執行" + joinPoint.getSignature().getName() + "方法出現異常之後-------");
            }
            System.out.println("pointCut0 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後返回執行的結果-------");
            //返回執行的結果
            return result;
        }

        /**
         * 唯一的確定一個唄攔截的方法
         * 類springaop.aop.annotion.service.actions.impl.ActionsImpl 的一個返回值類型爲String 且參數類型爲String 的askName方法
         */
        @Pointcut("execution(String springaop.aop.annotion.service.actions.impl.ActionsImpl.askName(String))")
        public void pointCut1(){}

        /**
         * @param joinPoint
         * @param person 可以使用 args(person) 將連接點的參數直接傳入進來,但是如果傳入鏈接點的話將沒有必要了
         */
        @Before("execution(String springaop.aop.annotion.service.actions.impl.ActionsImpl.askName(String))" +
                "&& args(person)")
        public void beforePointCut1(JoinPoint joinPoint,String person){
            System.out.println("pointCut1 前置通知:執行" +
                    joinPoint.getSignature().getName() + "(" + Arrays.toString(joinPoint.getArgs()) + ")"
                    + "方法之前!同時直接傳入的參數爲:" + person);
        }

        @Around("pointCut1()")
        public Object aroundPointCut1(ProceedingJoinPoint joinPoint){

            System.out.println("pointCut1 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之前-------");
            Object result = null;
            try{
                //真正的執行被攔截的方法
                result = joinPoint.proceed();
                System.out.println("pointCut1 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後-------");
            }catch(Throwable throwable){
                //可以進行異常處理
                throwable.printStackTrace();
                System.out.println("pointCut1 環繞通知:執行" + joinPoint.getSignature().getName() + "方法出現異常之後-------");
            }
            System.out.println("pointCut1 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後返回執行的結果-------");
            //返回執行的結果
            return result;
        }

        /**
         * 表示springaop.aop.annotion.service.actions包的所有字包(直接子包,之間沒有其他目錄級別)裏面的所有類的所有方法都會
         * 被攔截,無論參數列表和返回值類型
         */
        @Pointcut("execution(* springaop.aop.annotion.service.actions.*.*(..))")
        public void pointCut2(){}

        @Around("pointCut2()")
        public Object aroundPointCut2(ProceedingJoinPoint joinPoint){

            System.out.println("pointCut2 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之前-------");
            Object result = null;
            try{
                //真正的執行被攔截的方法
                result = joinPoint.proceed();
                System.out.println("pointCut2 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後-------");
            }catch(Throwable throwable){
                //可以進行異常處理
                throwable.printStackTrace();
                System.out.println("pointCut2 環繞通知:執行" + joinPoint.getSignature().getName() + "方法出現異常之後-------");
            }
            System.out.println("pointCut2 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後返回執行的結果-------");
            //返回執行的結果
            return result;
        }

        /**
         * 1、@Pointcut("execution(* springaop.aop.annotion.service.actions..*(..))")
         * pringaop.aop.annotion.service.actions 包及其子包(兩個點,無論之間多少目錄級別)裏面的所有類的所有方法,無論參數
         * 類型和返回值類型,將都會被攔截
         * 2、@Pointcut("args(String)")
         * 所有參數表爲(String)的方法將都會被攔截下來
         * 3、@Pointcut("target(springaop.aop.annotion.service.actions.impl.ActionsImpl)")
         * 所有該類型的所有方法將會被攔截下來(父類(子類對象即爲父類對象)和實現的接口的方法也將被攔截)
         * 4、@Pointcut("@target(org.springframework.stereotype.Component)")
         * 所有帶有這個註解的類的所有方法將被攔截
         * 5、@Pointcut("within(springaop.aop.annotion.service..*)")
         * 所有在springaop.aop.annotion.service包及其子包(兩個點,當一個點的時候和1是一樣的道理)裏面的類的所有方法將被攔截
         * 6、@Pointcut("@within(org.springframework.stereotype.Component)")
         * 匹配指定的註解類型的類型的所有方法將被攔截
         * 7、@Pointcut("@annotation()")
         * 註解指定註解的方法將被攔截
         */
        @Pointcut("execution(* springaop.aop.annotion.service..*(..))")
        public void pointCut3(){}

        /**
         * 多個 “且” 鏈接點使用 && 進行連接,但是在xml裏面 & 是一個特殊字符,所以用 and 來代替
         * 多個 “或” 鏈接點使用 || 進行連接,但是在xml裏面 | 是一個特殊字符,所以用 or 來代替
         * 多個 “非” 鏈接點使用 ! 進行連接,但是在xml裏面 ! 是一個特殊字符,所以用 not 來代替
         * @param joinPoint
         * @return
         */
        @Around("pointCut3() && pointCut2() || pointCut1() && pointCut0()")
        public Object aroundPointCut3s(ProceedingJoinPoint joinPoint){

            System.out.println("pointCut3 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之前-------");
            Object result = null;
            try{
                //真正的執行被攔截的方法
                result = joinPoint.proceed();
                System.out.println("pointCut3 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後-------");
            }catch(Throwable throwable){
                //可以進行異常處理
                throwable.printStackTrace();
                System.out.println("pointCut3 環繞通知:執行" + joinPoint.getSignature().getName() + "方法出現異常之後-------");
            }
            System.out.println("pointCut3 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後返回執行的結果-------");
            //返回執行的結果
            return result;
        }
    }
5、需要一個測試的主類
    public class AopApplication {

        public static void main(String[] args) throws Exception{
            //加載註解配置的spring容器
            ApplicationContext context = new AnnotationConfigApplicationContext(RootConfig.class);
            //獲取指定的bean
            Actions actions = (Actions) context.getBean("actionsImpl");
            //不會拋異常,正常的退出
            String name = actions.askName("楚雲飛");
            //使用AOP爲已經存在的實例增強功能增加接口
            ActionPlus actionPlus = (ActionPlus) actions;
            //無法對這個方法的執行進行再次攔截
            actionPlus.match("楚雲飛");
            //拋異常,異常退出
            name = actions.askName("石冬梅");
    //        pointCut0 環繞通知:執行askName方法之前-------
    //                pointCut1 環繞通知:執行askName方法之前-------
    //                pointCut2 環繞通知:執行askName方法之前-------
    //                pointCut3 環繞通知:執行askName方法之前-------
    //                pointCut0 前置通知:執行askName([楚雲飛])方法之前!
    //        pointCut1 前置通知:執行askName([楚雲飛])方法之前!同時直接傳入的參數爲:楚雲飛
    //        pointCut3 環繞通知:執行askName方法之後-------
    //                pointCut3 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut2 環繞通知:執行askName方法之後-------
    //                pointCut2 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut1 環繞通知:執行askName方法之後-------
    //                pointCut1 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut0 環繞通知:執行askName方法之後-------
    //                pointCut0 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut0 後置通知:執行askName([楚雲飛])方法之後!
    //        pointCut0 後置通知:執行askName([楚雲飛])方法正確返回之後的結果是:myName is 楚雲飛
    //        pointCut0 環繞通知:執行askName方法之前-------
    //                pointCut1 環繞通知:執行askName方法之前-------
    //                pointCut2 環繞通知:執行askName方法之前-------
    //                pointCut3 環繞通知:執行askName方法之前-------
    //                pointCut0 前置通知:執行askName([石冬梅])方法之前!
    //        pointCut1 前置通知:執行askName([石冬梅])方法之前!同時直接傳入的參數爲:石冬梅
    //        java.lang.Exception: 不知道你在說啥!
    //        pointCut3 環繞通知:執行askName方法出現異常之後-------
    //                pointCut3 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut2 環繞通知:執行askName方法之後-------
    //                pointCut2 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut1 環繞通知:執行askName方法之後-------
    //                pointCut1 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut0 環繞通知:執行askName方法之後-------
    //                pointCut0 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut0 後置通知:執行askName([石冬梅])方法之後!
    //        pointCut0 後置通知:執行askName([石冬梅])方法正確返回之後的結果是:null
        }
    }

xml的方式進行配置
1、其他一樣,切面進行改變一下
    @Component//除了將其註冊爲一個bean以外無其他任何東西,在配置文件裏面將這個切面進行織入
    public class ActionsAspect {

        public void beforePointCut0(JoinPoint joinPoint,String person){
            System.out.println("pointCut0 前置通知:執行" +
                    joinPoint.getSignature().getName() + "(" + Arrays.toString(joinPoint.getArgs()) + ")"
                    + "方法之前:傳入的參數爲:" + person);
        }

        public void afterPointCut0(JoinPoint joinPoint){
            System.out.println("pointCut0 後置通知:執行" +
                    joinPoint.getSignature().getName() + "(" + Arrays.toString(joinPoint.getArgs()) + ")"
                    + "方法之後!");
        }

        public void afterReturningPointCut0(JoinPoint joinPoint,Object result){
            System.out.println("pointCut0 後置通知:執行" +
                    joinPoint.getSignature().getName() + "(" + Arrays.toString(joinPoint.getArgs()) + ")"
                    + "方法正確返回之後的結果是:" + result);
        }

        public void afterThrowingPointCut0(JoinPoint joinPoint,Exception exception){
            System.out.println("pointCut0 後置通知:執行" +
                    joinPoint.getSignature().getName() + "(" + Arrays.toString(joinPoint.getArgs()) + ")"
                     + "方法發生異常: " + exception.getMessage());
        }

        public Object aroundPointCut0(ProceedingJoinPoint joinPoint){

            System.out.println("pointCut0 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之前-------");
            Object result = null;
            try{
                //真正的執行被攔截的方法
                result = joinPoint.proceed();
                System.out.println("pointCut0 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後-------");
            }catch(Throwable throwable){
                //可以進行異常處理
                throwable.printStackTrace();
                System.out.println("pointCut0 環繞通知:執行" + joinPoint.getSignature().getName() + "方法出現異常之後-------");
            }
            System.out.println("pointCut0 環繞通知:執行" + joinPoint.getSignature().getName() + "方法之後返回執行的結果-------");
            //返回執行的結果
            return result;
        }
    }
2、配置文件用來配置切面
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns="http://www.springframework.org/schema/beans"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xmlns:cache="http://www.springframework.org/schema/cache"
           xmlns:c="http://www.springframework.org/schema/c"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:util="http://www.springframework.org/schema/util"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-4.0.xsd
         http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
         http://www.springframework.org/schema/util
         http://www.springframework.org/schema/util/spring-util-4.0.xsd
         http://www.springframework.org/schema/cache
         http://www.springframework.org/schema/cache/spring-cache-4.0.xsd">

        <!--開啓aop的自動代理,相當於 @EnableAspectJAutoProxy 註解,開啓對aop的支持-->
        <aop:aspectj-autoproxy/>

        <!--配置包掃描,掃描xml配置的類包-->
        <context:component-scan base-package="springaop.aop.xml"/>

        <!--配置一個切面bean-->
        <bean name="actionsAspect" class="springaop.aop.xml.aspects.ActionsAspect"/>

        <!--配置aop的根節點-->
        <aop:config>
            <!--配置一個切面並指定其順序-->
            <aop:aspect ref="actionsAspect" order="1">
                <!--對一個類型進行增強-->
                <aop:declare-parents types-matching="springaop.aop.xml.service.actions.impl.ActionsImpl+"
                                     implement-interface="springaop.aop.xml.service.actionsplus.ActionPlus"
                                     default-impl="springaop.aop.xml.service.actionsplus.impl.ActionPlusImpl"/>
                <!--定義一個切點-->
                <aop:pointcut id="actionsAskName" expression="execution(* springaop.aop.xml.service.actions.impl.ActionsImpl.askName(..))"/>
                <!--定義攔截的方法-->
                <aop:before method="beforePointCut0" pointcut="execution(* springaop.aop.xml.service.actions.impl.ActionsImpl.askName(..)) and args(person)"/>
                <aop:after method="afterPointCut0" pointcut-ref="actionsAskName"/>
                <aop:after-returning method="afterReturningPointCut0" pointcut-ref="actionsAskName" returning="result"/>
                <aop:after-throwing method="afterThrowingPointCut0" pointcut-ref="actionsAskName" throwing="exception"/>
                <aop:around method="aroundPointCut0" pointcut-ref="actionsAskName"/>
            </aop:aspect>
        </aop:config>
    </beans>
3、一個測試的主類
    public class AopApplication {

        public static void main(String[] args) throws Exception{
            //加載XML配置的spring容器
            ApplicationContext context = new ClassPathXmlApplicationContext("classpath:springaop/applicationContext-aop.xml");
            //獲取指定的bean
            Actions actions = (Actions) context.getBean("actionsImpl");
            //不會拋異常,正常的退出
            String name = actions.askName("楚雲飛");
            //測試增強的方法
            ActionPlus actionPlus = (ActionPlus) actions;
            actionPlus.match("楚雲飛");
            //拋異常,異常退出
            name = actions.askName("石冬梅");
    //        pointCut0 前置通知:執行askName([楚雲飛])方法之前:傳入的參數爲:楚雲飛
    //        pointCut0 環繞通知:執行askName方法之前-------
    //                pointCut0 環繞通知:執行askName方法之後-------
    //                pointCut0 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut0 後置通知:執行askName([楚雲飛])方法正確返回之後的結果是:myName is 楚雲飛
    //        pointCut0 後置通知:執行askName([楚雲飛])方法之後!
    //        pointCut0 前置通知:執行askName([石冬梅])方法之前:傳入的參數爲:石冬梅
    //        pointCut0 環繞通知:執行askName方法之前-------
    //                java.lang.Exception: 不知道你在說啥!
    //        pointCut0 環繞通知:執行askName方法出現異常之後-------
    //                pointCut0 環繞通知:執行askName方法之後返回執行的結果-------
    //                pointCut0 後置通知:執行askName([石冬梅])方法正確返回之後的結果是:null
    //        pointCut0 後置通知:執行askName([石冬梅])方法之後!
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章