博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring创建切面(方法名匹配切面)
阅读量:4970 次
发布时间:2019-06-12

本文共 7288 字,大约阅读时间需要 24 分钟。

      在之前说增强的时候,有一个问题那就是,增强被织入了目标类的所有方法中,加入我们希望有选择的织入到目标类的特定方法中,就需要使用切点进行目标连接点的定位了,增强提供了连接点方位信息:如织入到方法前还是方法后,而切点进一步描述织入到哪些类的哪些方法上。

      Spring通过org.springframework.aop.Pointcut接口描述切点,Pointcut由ClassFilter和MethodMatcher构成,它功过ClassFliter定位到某些特定类上,通过MethodMatcher定位到某些特定方法上,这样Pointcut就有了描述某些类的某些特定方法的能力。

      Spring支持两种方法匹配器:静态方法匹配器和动态方法匹配器:

      1.所谓静态方法匹配器,它仅对方法签名(包括方法名和入参类型、顺序)进行匹配;

      2.动态匹配器,会在运行期检查方法入参的值。

      静态匹配仅会判别一次;而动态匹配因为每次调用方法的入参可能都不一样,所以每次调用方法都会判断,因此动态匹配对性能的影响很大,一般情况下,动态匹配不常用。方法匹配器的类型由isRuntime()返回值决定,返回false表示静态方法匹配器,反之则是动态方法匹配器;

 一、静态方法匹配器(静态普通方法名匹配切面)

      1.两个业务类

package spring.aop.StaticMethodMatcherPointcutAdvisorDemo;import org.springframework.aop.framework.ProxyFactory;public class Waiter {    public void greetTo(String name) {        System.out.println("waiter greet to " + name + "...");    }    public void serveTo(String name) {        System.out.println("waiter serving to " + name + "...");    }        public static void main(String[] args) {        Waiter waiter = new Waiter();        GreetingAdvisor grettingAdvisor = new GreetingAdvisor();        GreetingBeforeAdvice greetingBeforeAdvice = new GreetingBeforeAdvice();        ProxyFactory pf = new ProxyFactory();        pf.setOptimize(true);        grettingAdvisor.setAdvice(greetingBeforeAdvice);        pf.addAdvisor(grettingAdvisor);        pf.setTarget(waiter);        //pf.addAdvice(greetingBeforeAdvice);        Waiter waiterProxy = (Waiter)pf.getProxy();        waiterProxy.greetTo("lee");        waiterProxy.serveTo("bin");    }}
package spring.aop.StaticMethodMatcherPointcutAdvisorDemo;public class Seller {        public void greetTo(String name) {        System.out.println("seller greet to " + name + "...");    }}

      2.定义一个切面,在Waiter#greetTo()方法调用前织入一个增强

package spring.aop.StaticMethodMatcherPointcutAdvisorDemo;import java.lang.reflect.Method;import org.springframework.aop.ClassFilter;import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;public class GreetingAdvisor extends StaticMethodMatcherPointcutAdvisor {    /**     *      */    private static final long serialVersionUID = -3558599577522442437L;    @Override    public boolean matches(Method arg0, Class
arg1) { // 切点方法匹配规则:方法名必须为greetTo return "greetTo".equals(arg0.getName()); } // 切点类匹配规则:Waiter的类或者子类 @Override public ClassFilter getClassFilter() { return new ClassFilter() { @Override public boolean matches(Class
arg0) { return Waiter.class.isAssignableFrom(arg0); } }; }}

      3.增强类的配合,定义一个前置增强

package spring.aop.StaticMethodMatcherPointcutAdvisorDemo;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;public class GreetingBeforeAdvice implements MethodBeforeAdvice {    @Override    public void before(Method method, Object[] aobj, Object obj)            throws Throwable {        System.out.println("输出切点:" + obj.getClass().getName() + "."                + method.getName());        String clientName = (String) aobj[0];        System.out.println("how are you! Mr." + clientName);    }}

如果我们直接运行Waiter.java里的main方法可以得到如下输出:

输出切点:spring.aop.StaticMethodMatcherPointcutAdvisorDemo.Waiter.greetTo

how are you! Mr.lee
waiter greet to lee...
waiter serving to bin...

      说明:我们定义的GreetingAdvisor包含了两个判定,ClassFilter和MethodMatcher这样我们就只定位到了Waiter的greetTo方法;

      当然我们也可以通过spring配置的方式,配置如下:

      有时候我们可能需要对满足一定命名规范的方法进行织入增强,这个时候我们可以使用正则表达式方法匹配切面,配置如下:

.*greet.*

      以上是通过方法名来匹配切面,下面我们看动态切面;

 

二、动态切面

     在低版本中,Spring提供了用于创建动态切面的DynamicMethodMatcherPointcutAdvisor抽象类,因为该类在功能上和其他类有重叠,会给开发者造成选择上的困惑,因此在Spring2.0中已经过期,我们可以使用DefaultPointcutAdvisor和DynamicMethodMatcherPointcut来完成相同的功能。DynamicMethodMatcherPointcut是一个抽象类,它将isRuntime()标示成final并返回true,这样其子类就是一个动态的切点了,该抽象类默认匹配所有类和方法,因此需要通过扩展该类编写符合需求的动态切点。

package spring.aop.DynamicMethodMatcherPointcutDemo;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.List;import org.springframework.aop.ClassFilter;import org.springframework.aop.support.DynamicMethodMatcherPointcut;import spring.aop.beforeadvicedemo.Waiter;public class GreetingDynamicPointcut extends DynamicMethodMatcherPointcut {    private static List
specialClientList = new ArrayList
(); static { specialClientList.add("nicholas"); specialClientList.add("lee"); } // 对类进行静态切点检查 public ClassFilter getClassFilter() { return new ClassFilter() { @Override public boolean matches(Class
arg0) { System.out.println("调用getClassFilter()对" + arg0.getName() + "做静态检查"); return Waiter.class.isAssignableFrom(arg0); } }; } @Override public boolean matches(Method arg0, Class
arg1) { System.out.println("调用matches()" + arg1.getName() + "." + arg0.getName() + "做静态检查"); return "greetTo".equals(arg0.getName()); } @Override public boolean matches(Method arg0, Class
arg1, Object[] arg2) { System.out.println("调用matches()" + arg1.getName() + "." + arg0.getName() + "做动态检查"); String clientName = (String) arg2[0]; return specialClientList.contains(clientName); }}

 

三、流程切面

      Spring的流程切面由DefaultPointcutAdvisor和ControlFlowPointcut实现。流程切点代表由某个方法直接或间接发起调用的其他方法,看一个实例,我们通过一个WaiterDelegate类代理Waiter所有的方法:

      1.WaiterDelegate代理类

package spring.aop.ControlFlowPointcutDemo;import spring.aop.StaticMethodMatcherPointcutAdvisorDemo.Waiter;public class WaiterDelegate {        private Waiter waiter;        public void service(String clientName){        waiter.greetTo(clientName);        waiter.serveTo(clientName);    }    public void setWaiter(Waiter waiter) {        this.waiter = waiter;    }}

     如果我们希望由代理类WaiterDelegate#service()方法发起调用的其他方法都织入GreetingBeforeAdvice增强,那么我们就必须使用流程切面来完成:

package spring.aop.ControlFlowPointcutDemo;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import spring.aop.StaticMethodMatcherPointcutAdvisorDemo.Waiter;public class test {    public static void main(String[] args) {        ApplicationContext ctx = new ClassPathXmlApplicationContext(                "classpath:applicationContext.xml");        Waiter waiter = (Waiter) ctx.getBean("getControlWaiter");        WaiterDelegate wd = new WaiterDelegate();        wd.setWaiter(waiter);        wd.service("lee");        //waiter.serveTo("lee");    }}

输出:

输出切点:spring.aop.StaticMethodMatcherPointcutAdvisorDemo.Waiter.greetTo

how are you! Mr.lee
waiter greet to lee...

输出切点:spring.aop.StaticMethodMatcherPointcutAdvisorDemo.Waiter.serveTo

how are you! Mr.lee
waiter serving to lee...

     总结:流程切面和动态切面从某种程度上来说是一类切面,都需要在运行期间判断动态的环境,开销很大,JVM1.4上,流程切面比别的切面要慢5倍!

转载于:https://www.cnblogs.com/NicholasLee/archive/2012/08/04/2623264.html

你可能感兴趣的文章
当多个类之间有继承关系时,创建子类对象会导致父类初始化块的执行。
查看>>
《大道至简》第六章读后感
查看>>
fdisk创立主分区过程
查看>>
批量插入数据
查看>>
如何获取配置文件Web.config的AppSetting节点数据
查看>>
http协议之request
查看>>
php安装redis扩展,详情请见下面链接
查看>>
html
查看>>
【转】How to Install Apache Spark on Mac OS X Yosemite
查看>>
把指定图片转换为byte
查看>>
ubuntu 11.04 + Macbuntu
查看>>
将页面中指定表格的数据导入到Excel中
查看>>
菜单栏鼠标经过伸缩效果
查看>>
gulp轻松上手
查看>>
用个体软件过程(PSP)记录你的工作
查看>>
NoSQL开篇——为什么要使用NoSQL[转]
查看>>
day 14 项目目录规范; time ; logging
查看>>
Codeforces - 1181B - Split a Number - 贪心
查看>>
模板 - Treap
查看>>
C#注册表操作类(完整版) 整理完整
查看>>