spring aop

 
(一) AOP的几种实现机制
 
    1.静态代理
        缺点 :
            不灵活.
                原因 : 需要其他编译器预编译,再织入到系统中,方可使用.
                
    
    2.动态代理
        缺点 :
            a.性能 比 静态代理 稍逊. 随着jvm的发展 , 差距越来越小 .
            b.模块类需要实现接口 . 动态代理只对接口有效 .
            
    3.动态字节码增强
        缺点 :
            使用final修饰过的类和方法 是无法动态增强的.
                原因 : 该方案的思想是 生成目标类的子类,达到将横切逻辑加入其中的新方法覆盖父类的.因此,使用final修饰符的无法达到.
                
    4.java代码生成
        缺点 : 需要专门的部署接口 / 部署工具 .目前基本退役 .
        
    5.自定义类加载器
        缺点 : 本身这种策略 是很强大的 .
        但是 , 问题出现在类加载器本身 . 很多应用程序都有自己的类加载体系控制整个系统 , 这种情况使用它 ,很可能造成问题.
        
    6.AOL 扩展
        缺点 : 很强大 , 但很难掌握的一种方式. 首先需要学一门拓展了旧有语言的aol语言 , 甚至是新的一门aol语言.
        
        
        
(二) 一些aop概念(基于AspectJ)
    
    1.Joinpoint :
        解释 :
                织入操作的系统执行点.
                
        包含 :
                方法调用 , 方法调用执行 , 构造方法调用 , 构造方法执行 , 字段设置 , 字段获取 , 异常处理执行 , 类初始化(静态类型/静态块初始化)
    
    2.Pointcut :
        
        解释 :
                joinpoint的表述形式 . pointcut中包含了joinpoint的相关信息 .    
                
        包含 :
                确定的方法名称 , 正则表达式 , 特定的pointcut表述语言 .
                
        pointcut的运算 : 可以使用 逻辑与 或 逻辑或 (&& , ||) 进行运算 .
        
    3.Advice :
 
        解释 : 代表了 将要织入到joinpoint的横切逻辑 . 注意 代表的是 横切逻辑 , 逻辑 , 辑 ..
        包含 :
            before advice
            
            after advice :
                after returning advice
                after throwing advice
                after (final) advice
                
            around advice (也称 interceptor , 拦截器)
            
            Introduction :
                解释 : 与前几种advice 不同 .
                        introduction 不是根据切入时机来区别对待(或说独立出来) , 而是因为它提供的功能与前几个advice不同.
                        introduction 可以为原有的对象添加新的特性或行为.
                    
    4.Aspect :
            
        解释 : aspect 是 对系统中 横切关注点 以及 横切逻辑 进行封装的 aop概念的实体.
                它可以包含 多个pointcut 以及 相关的advice 定义.
                
    5.Weaver :
        解释 : 织入器.
            将所有 包含了pointcut,advice的aspect 织入到系统中的工具.
            它可能是 编译器 , 也可以是 自定义类加载器 , 或者 proxyfactory类 etc.
            
    6.TargetObject :
        解释 : 目标对象. 将符合pointcut的条件/规则 的 横切逻辑 以及 横切点 , 在织入过程中 织入到指定的对象.这个对象成为目标对象 .
        
                
                
(三) Spring AOP
    
    1.实现机制 : 采用动态代理 以及 字节码生成技术.
    
        a.动态代理
            代理模式 : (可以让请求转发 , 最重要的是在转发过程中 可以添加 访问限制等功能)
                代理类 实现 和 目标类相同的 接口 , 并持有改接口的引用 , 代理方法中调用目标类的目标方法(通常是利用接口的引用调用)
                但是对于 aop来讲 , 当有一个新的接口 , 以及新接口的实现类 中也有要拦截的方法(即joinpoint相同) , 就需要创建一个新的代理类,这样不好不好~
                
            动态代理模式 :
                动态代理模式机制的实现 主要由一个类(java.lang.reflect.Proxy) 与 一个接口(java.lang.reflect.InvocationHandler) 组成.
                具体用法 :
                    ①.代理类 实现InvocationHandler接口 , 进行横切逻辑书写.
                    ②.使用Proxy类创建对应的目标类. 通常要提供一个 loader , interface , impl class
                
                Demo :
                        public class RequestCtrlInvocationHandler implements InvocationHandler{
                                private static final Logger logger = LoggerFactory.getLogger(RequestCtrlInvocationHandler.class);
                                Object target ;
 
                                public RequestCtrlInvocationHandler(Object target){
                                        this.target = target ;
                                }
 
                                @Override
                                public Object invoke(Object proxy , Method method , Object[] args) throws Throwable{
                                        if ( "request".equals(method.getMethodName()) ){
                                                TimeOfDay startTime = new TimeOfDay(0,0,0);
                                                TimeOfDay endTime = new TimeOfDay(5,59,59);
                                                TimeOfDay currentTime = new TimeOfDay();
 
                                                if(currentTime.isAfter(startTime) && currentTime.isBefore(endTime) ){
                                                        logger.warn("between 0:00 AM and 6:00 AM , the service call is not avilibale ~");
                                                        return null ;
                                                }
                                                return method.invoke(target , args);
                                        }
                                        return null ;
                                }
 
 
                                public static void main(String[] args){
                                        IRequestable requestable = Proxy.newProxyInstance( 
                                                    ProxyRunner.class.getClassLoader() 
                                                    , new Class[]{IRequestable.class} 
                                                    , new RequestCtrlInvocationHandler(new RequestableImpl()) 
                                        );
                                        requestable.request();
 
                                        ISubject subject = Proxy.newProxyInstance(
                                                    ProxyRunner.class.getClassLoader() 
                                                    , new Class[]{ISubject.class} 
                                                    , new RequestCtrlInvocationHandler(new SubjectImpl()) 
                                        );
                                        subject.request();
                                }
 
                        }
                
            缺点:
                动态代理实现的aop , 只能对 实现了某个接口的实现类(目标对象) 进行代理 , 如果该目标类没有实现任何接口 , 就拿爪儿了 ~
                
        
        b.字节码生成(通常借助CGLIB动态字节码生成库).
            
            a.原理 : 通过字节码动态生成 技术 , 为指定的目标类 生成一个 相应的子类.子类当然可以对父类进行拓展啦.
            b.步骤 : 利用cglib库
                ①.代理类需要实现 net.sf.cglib.proxy.CallBack 接口 , 或者实现 net.sf.cglib.proxy.MethodInterceptor接口 , 进行横切逻辑书写
                ②.通过Enhancer类为 目标对象动态生成一个子类.并将代理类的横切逻辑附加到子类中.
                
                Demo : 
                    public class RequestCtrlCallback implements MethodInterceptor{
                            private static fianl Logger logger = Logger.getLogger(RequestCtrlCallback.class);
 
                            @Override
                            public Object intercept(Object target , Method method , Object[] args , MethodProxy proxy) throws Throwable{
                                       if ( "request".equals(method.getMethodName()) ){
                                                TimeOfDay startTime = new TimeOfDay(0,0,0);
                                                TimeOfDay endTime = new TimeOfDay(5,59,59);
                                                TimeOfDay currentTime = new TimeOfDay();
 
                                                if(currentTime.isAfter(startTime) && currentTime.isBefore(endTime) ){
                                                        logger.warn("between 0:00 AM and 6:00 AM , the service call is not avilibale ~");
                                                        return null ;
                                                }
                                                return proxy.invokeSuper(target , args);
                                        }
                                        return null ;
                            }
 
 
                            public static void main(String[] args){
                                    Enhancer enhancer = new Enhancer();
                                    enhancer.setSuperClass(IRequestable.class);
                                    enhancer.setCallback( new RequestCtrlCallback() );
 
                                    IRequestable proxy = (IRequestable) enhancer.create();
                                    proxy.request();
                            }
                    }
 
 
 
 
 
Spring AOP 相关概念
    1.JoinPoint
 
        只支持方法级别的joinpoint , 确切的说 只支持 "方法执行" 类型的joinpoint .
    
    2.PointCut
    
        a.接口定义 :
        
            public interface Pointcut {
            
                // 匹配将要被执行织入操作的 对象
                ClassFilter getClassFilter();
                
                // 匹配将要被执行织入操作的 方法
                MethodMatcher getMethodMatcher();
                
                // 默认对所有对象 以及对象上的所有支持的 pointcut进行匹配
                Pointcut TRUE = TrueClassFilter.INSTANCE ;
                
            }
            
            
            // 对pointcut所处的对象进行 Class级别类型的匹配
            public interface ClassFilter{
            
                boolean matches(Class clazz);
                
                ClassFilter TRUE = TrueClassFilter.INSTANCE;
            }
            
            // 重头戏
            public interface MethodMatcher{
                
                // false --> 不考虑目标方法的参数 ; true --> 对目标方法参数进行操作
                boolean isRuntime();
                
                // isRuntime() 返回false时 调用; 称为 "StaticMethodMatcher"
                boolean matches(Method method , Class targetClass);
                
                // isRuntime() 返回true时 调用 ; 称为 "DynamicMethodMatcher"  -- 最好使用static的 避免使用这个的
                boolean matches(Method method , Class targetClass , Object[] args);
                
                MethodMatcher TRUE = TrueMethodMatcher.INSTANCE ;
            
            }
        
        
        b.Spring提供的常见的PointCut
        
            ①.NameMatchMethodPointcut
                
                解释 : 其为StaticMethodMatcherPointcut的子类.
                
                Demo :
                    NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
                    
                    // 单个方法匹配
                    pointcut.setMappedName("matches");
                    
                    // 或者传入多个 匹配方法名称
                    pointcut.setMappedNames(new String[]{"matches","isRuntime"});
                    
                    // 支持 * 通配符
                    pointcut.setMappedNames(new String[]{"match*","*matches","mat*es"});
                    
                缺点 : 只能匹配指定的方法名 , 无法匹配方法重载 , 因为没有 函数签名的描述.
                
            
            ②.JdkRegexpMethodPointcut
                
                解释 : 其为StaticMethodMatcherPointcut的子类. 需要 JDK1.4 以上.
                        必须匹配整个方法签名
                
                Demo :
                    JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
                    
                    // 单个表达式
                    pointcut.setPattern(".*match.*");
                    
                    // 多个表达式
                    pointcut.setPatterns(new String[]{".*match.*",".*matches"});
                
                
            
            ③.Perl5RegexpMethodPointcut
                略过, 都有 JDK 1.4 以上了. 用JdkRegexpMethodPointcut替代.
            
            
            ④.AnnotationMatchingPointcut
                解释 : JDK5 以上版本可以使用.
                
                Demo :
                
                    @Retention(RetentionPolicy.RUNTIME)
                    @Target(ElementType.TYPE)
                    public @interface ClassLevelAnnotation{
                    }
            
                    
                    @Retention(RetentionPolicy.RUNTIME)
                    @Target(ElementType.METHOD)
                    public @interface MethodLevelAnnotation{
                    }
            
                    @ClassLevelAnnotation
                    public class GenericTargetObject{
                    
                        @MethodLevelAnnotation
                        public void withAnnotation(){
                            System.out.println("i have an apple , i have a pen");
                        }
                        
                        public void noAnnotation(){
                            System.out.println("no apple , no pen !!!-.-");
                        }
                        
                        
                        public static void main(String[] args){
                        
                            // 这两种写法表达的 都是对标注了 @ClassLevelAnnotation 的类中所有的 method进行匹配
                            AnnotationMatchingPointcut clazzLvPc = new AnnotationMatchingPointcut(ClassLevelAnnotation.class);
                            AnnotationMatchingPointcut clazzLvPc1 = AnnotationMatchingPointcut.forClassAnnotation(ClassLevelAnnotation.class);
                            
                            // 对所有 标注了 @MethodLevelAnnotation 的方法进行匹配 , 而不局限于某一个类 , 比如GenericTargetObject
                            AnnotationMatchingPointcut methodLvPc = AnnotationMatchingPointcut.forMethodAnnotation(MethodLevelAnnotation.class);
                            
                            // 对标注了 @ClassLevelAnnotation 的类中 标注了 @MethodLevelAnnotation 的方法 进行匹配. (这里只匹配到 withAnnotation() )
                            AnnotationMatchingPointcut methodLvPc1 = new AnnotationMatchingPointcut(ClassLevelAnnotation.class,MethodLevelAnnotation.class);
                            
                        }
                    
                    }
                    
            
            
            ⑤.ComposablePointcut
                解释 : 提供 逻辑运算 功能的pointcut类.
            
            
            ⑥.ControlFlowPointcut
                解释 : 可以帮助你 在调用流程中的 只有指定调用类(special caller)调用了目标类的pointcut才触发织入操作, 忽略其他的调用类
                
                用法 :
                    
                    public static void main(String[] args){
                        //指定调用类
                        ControlFlowPointcut pointcut = new ControlFlowPointcut(XxxTargetCaller.class);
                        
                        //指定调用类 , 精确到指定方法
                        ControlFlowPointcut pointcut1 = new ControlFlowPointcut(XxxTargetCaller.class,"xxxMethodName");
                        
                    }
            
            
            
            
    3.Advice
            
        解释: 两种类型 (per-class , per-instance) ,前者实例间共享,后者每个实例有自己的advice.
              在Spring中 这些 Advice 都是 普通的POJO . 配置上和普通的Bean没有区别.
        
        a.BeforeAdvice
            实现org.springframework.aop.MethodBeforeAdvice接口.
            通常, before advice 不会中断调用流程 , 如果有需要 ,可以用异常来调用.
            
        b.ThrowsAdvice
            实现org.springframework.aop.ThrowsAdvice接口.
            ThrowsAdvice接口没有定义方法 , 但是 子类要遵循以下规则 , []中的参数可以省略.
                void afterThrowing( [ method , args , target] , ThrowableSubClass);
                
            Demo :
                public class ExceptionBarrierThrowsAdvice implements ThrowsAdvice{
                    
                    public void afterThrowing(Throwable t){
                        // 普通异常处理
                    }
                    
                    public void afterThrowing(RuntimeException e){
                        // 运行时异常处理
                    }
                    
                    public void afterThrowing(Method method , Object[] args , Object target , XxxAppException e){
                        // 处理应用程序生成的异常
                    }
                    
                }
            
            
            
        c.AfterReturningAdvice
            解释 : 只有方法正常返回时才可以执行. 
                        可以访问到方法的返回值 , 但是不可以更改返回值.
                        还可以获得方法,方法参数 以及目标对象的相关信息.
            
        d.AroundAdvice
            解释 :
                Spring没有提供相应的 after (finally) advice .
                但是 提供了 AroundAdvice , 它可以做到所有上面提到的advice所能做的.
                还可以修改返回值.非常强大 , 应用场景最多 .
                Spring中并没有AroundAdvice接口 , 而是直接使用了 org.aoplliance.intercept.MethodInterceptor 接口.
                
            Demo :
            
                public class PerformanceMethodInterceptor implements MethodInterceptor{
                
                    private static final Logger logger = LoggerFactory.getLogger(this.getClass());
                    
                    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
                        StopWatch watch = new StopWatch();
                        try{
                            watch.start();
                            return methodInvocation.proceed();
                        }catch(Exception ex){
                            logger.error("exception happens : " + ex.getCauseMessage());
                        }finally{
                            watch.stop();
                            logger.info(watch.toString());
                        }
                    }
                
                }
                
            
        e.Introduction (Spring中唯一的一个 per-instance类型的Advice)    
            
            //todo 这部分 有点绕 , 麻烦 , 如非真的需要 不用算了 , 毕竟两个实现类的拓展性不好(不知道spring team改了没有) 待补充 ... 2333333
            
            两个具体实现类 :
            
                ①.DelegatingIntroductionInterceptor
                    该实现类 并不能做到 per-instance , 如果想达到 需要用它的兄弟类,见②.
                    
                ②.DelegatePerTargetObjectIntroductionInterceptor
            
            
    
       4.Advisor
        解释 :
            Spring提供的 Advisor 对应着 概念中的 Aspect. 可以说Advisor是特殊的/弱化版的 Aspect.
            Advisor 包含 一个Advice 以及一个Pointcut , 而Aspect可以包含 多个Advice 以及多个Pointcut.
            
        两个Advisor家族 :
            
            ①.PointcutAdvisor
                
                1).DefaultPointcutAdvisor
                    PointcutAdvisor 门派的大弟子 , 除了IntroductionAdvice , 其他类型的pointcut , advice都可以使用.
                    可以在构造方法,setter中设置pointcut,advice. 实际生产中,推荐使用spring的xml配置,和普通bean的配置没什么不同.
                
                2).NameMatchMethodPointcutAdvisor
                    对DefaultPointcutAdvisor的细化:
                        pointcut方面 限制了只可使用NameMatchPointcut,无法更改.
                        advice方面 可以使用除IntroductionAdvice类型以外的advice.
                        
                3).RegexpMatchPointcutAdvisor
                    限制了只可使用正则表达式进行设置pointcut.
                    除了IntroductionAdvice , 其他类型的advice均可使用.
                    
                4).DefaultBeanFactoryPointcutAdvisor
                    使用比较少的advisor.
                    通过绑定容器中advice注册的beanName来实例化advice.前提是pointcut匹配成功,否则不实例化.
                    减少了容器启动初期advisor和advice之间的耦合.但会依赖并强行绑定到spring的ioc容器.
                        
                        
            ②.IntroductionAdvisor
                只能应用于类级别的拦截.
                只能使用IntroductionInterceptor , 仅限Introduction使用场景.
                参数有两个 : 一个IntroductionInterceptor的impl类 , 一个接口类型.
                
                
        Ordered接口的作用.
            当有多个advisor可以拦截到 同一个方法 , 那么指定他们的拦截顺序有的时候就很有必要,这时可以通过设置order来解决.
            
            
    5.Spring AOP 的织入
        ①.ProxyFactory
            解释 :
                Spring AOP中 使用org.springframework.aop.framework.ProxyFactory 作为最基本的织入器.
                AspectJ AOP 使用 ajc编译器 ; JBOSS AOP 使用自定义ClassLoader
                
                ProxyFactory 只需要 advisor 和 targetObject 相关信息.
                对于 非IntroductionInterceptor 类型的advice , ProxyFactory可以内部构造相应的advisor.
                对于 IntroductionInterceptor 类型 分为两种情况 :
                    如果是DynamicIntroductionAdvice的子类 , 会抛出AopConfigExecption , 因为该子类没有必要的对象目标信息.
                    如果是其他的 , ProxyFactory可以为其配置一个 DefaultIntroductionAdvisor
                
            Demo :
                ProxyFactory weaver = new ProxyFactory(XxxTargetObject);
                Advisor advisor = xxxx;
                weaver.addAdvisor(advisor);
                Object proxy = weaver.getProxy();
                // 可以使用 proxy 做你想做的事儿了~
                
                
            使用方式 :
            
                1).基于接口的代理
                    
                    ProxyFactory weaver = new ProxyFactory(new MockTask());
                    weaver.setInterfaces(new Class[]{ITask.class}); //可以省略 , ProxyFactory会检测到 目标类所实现的接口.
                    NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
                    advisor.setMappedName("execute");
                    advisor.setAdvice(XxxAdviceImpl());
                    weaver.addAdvisor(advisor);
                    ITask taskProxy = (ITask) weaver.getProxy();
                    taskProxy.execute();
                    
                    
                2).基于类的代理 (使用CGLIB)
                
                    ProxyFactory weaver = new ProxyFactory(new Executable());
                    
                    // 如果目标类(这里是Executable)没有实现任何接口 ,可以省略设置 ,默认使用基于类的代理 ;
                    // 反之,可以强制使用类的代理而非接口代理 : 设置 proxyTargetClass 或者 optimize 为true ,
                    weaver.setProxyTargetClass(true);    
                    
                    NameMatchMethodPointcutAdvisor advisor = new NameMatchMethodPointcutAdvisor();
                    advisor.setMappedName("execute");
                    advisor.setAdvice(XxxAdviceImpl());
                    weaver.addAdvisor(advisor);
                    Executable taskProxy = (Executable) weaver.getProxy();
                    taskProxy.execute();
                
                3).对于 Introduction的织入
                    类似对于 基于接口的代理 的织入.
                    不同的是
                        a.必须setInterfaces(xxx);
                        b.可以不用设置advisor , 而是设置advice , ProxyFactory会为Introduction这种使用 DefaultIntroductionAdvisor
        
        
        ②.ProxyFactoryBean
            解释 :
                另外一个SpringAOP提供的织入器 , 是ProxyFactory的兄弟类 , 同样继承自ProxyCreatorSupport  添加了特有的属性 :
                    proxyInterfaces :
                        与 父容器的interfaces属性一样的功效.
                        
                    interceptorNames :
                        可以 指定多个要织入到目标对象的advice , 拦截器 以及 advisor , 不需要像ProxyFactory那样一个一个指定了.
                    
                    singleton :
                        为true时 , 每次调用getObejct() 返回同一个 proxy实例 ; 反之 , 每次返回不同的实例 .
                        
            使用方式 : (前两者 和 ProxyFactory 并没有什么不同)
                1).基于接口的代理
                2).基于类的代理
                3).对于 Introduction的织入(略)
                
                
        ③.AutoProxy
            解释 :
                SpringAOP提供的自动代理 , 自动化织入方式.
                需要以ApplicationContext为IoC容器(使用BeanFactory的话,需要进一步编码,否则不是自动化).
                它的实现是建立在IoC容器的BeanPostProcessor概念上.
                
                fake code :
                    
                    for(Bean bean : IocContainer){
                        if(bean.isSatifySomeCondition){ // 关键! 可以通过配置文件 , 或是注解
                            Proxy proxy = createProxyFor(bean); // 无非就是利用 ProxyFactory 或 ProxyFactoryBean 来实现
                        }else{
                            Object object = createInstancce(bean);
                            return object ;
                        }
                    }
                
            
            具体实现类 :
                BeanNameAutoProxyCreator    --半自动步枪 , 需要配置自己应该持有那些target 以及相应的 advice
                DefaultAdvisorAutoProxyCreator    --全自动步枪 , 需要配置 自己 以及 各个单独的 advisor 即可. 可以看出 它只对advisor 有效.
                
                
    6.TargetSource            
        解释 :
            spring对target object的封装 , 提供的实现类如下 :
                1).SingletonTargetSource  -- ProxyFactory 以及 ProxyFactoryBean 都是使用的它 , 每次getTarget(),返回同一个目标类代理的引用.
                2).PrototypeTargetSource  -- 与 SingletonTargetSource相反 .
                3).HotSwappableTargetSource
                    比较有用的一个 TargetSource . //todo
                4).CommonsPoolTargetSource
                5).ThreadLocalTargetSoure
                6).自定义TargetSource
                
                
                
                
                
@AspectJ 更多相关话题 :
    1.Advice的执行顺序
        ①.如果这些advice是在同一个 Aspect/Advisor中 , 那么按照定义顺序 排列优先级.
            @Before的 先定义的先执行 ; @AfterReturningAdvice 先定义的最后执行 .
            
        ②.当这些advice是在不同的Aspect中 , 那么就需要借助 Ordered 接口(数值越小 , 优先级越高)
            public class AnotherAspect implements Ordered {
            
                public int getOrder(){
                    return 100 ;
                }
            }
            
    2.Aspect的实例化模式
        默认采用的 是singleton模式.
        SpringAOP还支持perthis 以及 pertarget
        
        Demo :
            @Aspect(perthis(execution(boolean *.execute(String,..))))
            public class MultiAdviceAspect{
                ...
            }
            
        perthis     会为相应的 代理对象 实例化各自的Aspect实例.
        pertarget    为匹配的 单独的目标对象 实例化Aspect实例 .
        
        注意 , 当使用这两种模式的 Aspect , 其Xml中的Bean定义 就不能再使用 scope="singleton" , 否则会报错. 最好连带相应的 目标对象也配置为 prototype类型.
        
        
基于Schema的AOP :
    即 使用XSD 取代了 DTD . 同一个XML可以配置多个 <aop:config />
    虽然 @AspectJ 模式的AOP支持 三种模式 , 但是 XSD的 只支持 singleton模式.
    当你就喜欢用XML模式配置,或者JVM是5以下的 ,可以使用这种方式来管理AOP , 一般用基于@AspectJ就ok了.
        <!-- 只有proxy-target-class属性 , 默认为 fasle 即基于 接口的代理 todo-->
        <aop:config proxy-target-class="fasle">
            <aop:pointcut />
            <aop:advisor />
            <aop:aspect />
        </aop:config>
        
        <aop:config proxy-target-class="true">
            <aop:pointcut />
            <aop:advisor />
            <aop:aspect />
        </aop:config>
        
        
        Demo :
            <aop:config>
                <aop:advisor
                    id="performanceAdvisor"
                    pointcut-ref="targetPointcut"
                    advice-ref="targetAdvice"
                    order="1"
                    />
            </aop:config>
            
            <bean id="targetPointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut" >
                <property name="pattern" value="..." />
            </bean>
            
            <bean id="performanceInterceptor" class="...PerformanceMethodInterceptor" />
            
            其中,pointcut-ref
                a.可以用pointcut替代 , 直接指定pointcut="execution(...)"
                b.可以在 <aop:advisor>中定义 一个或多个 <aop:pointcut> , 然后 在<aop:advisor>甚至<aop:aspect>中 使用pointcut-ref属性来指定.
                    如果<aop:pointcut>中的type="regex" ,那么 可以书写expression="xx正则表达式" .
                    默认type="aspectj" , 采用的是 pointcut 表达式的 处理方案.
                    但是 type只是语义上如此 , 实际情况 是 type="regex"时, 仍然使用的是默认的类型,而不是正则表达式 , 该bug不知道目前是否修复.todo
                    
                
                    
            
 
原文地址:https://www.cnblogs.com/lmxxlm-123/p/11131917.html