使用Spring进行切面(AOP)编程(3)

四、   常见问题

1.         同一个切面中的通知的执行顺序如何确定?

当定义在同一个切面中多个通知想在同一个相同的连接点中运行的话,这些通知的执行顺序是未知的(查询后原因是因为没有方法能通过反射Javac生成的类来获取方法的声明顺序)。如果我们出现这种情况,需要把这些方法压缩到一个通知中,或者把这些方法抽象到不同的切面中,通过切面的优先级来指定执行顺序。

2.         不同切面中的通知的执行顺序如何确定?

不同切面中的通知的执行顺序顺序是根据切面的优先级来确定的,我们在切面中需要实现“org.springframework.core.Ordered”接口,通过实现接口的getOrder()方法来确定优先级,返回的数字越小,优先级越高,优先级越高,切面中的通知则优先执行。对于前置通知,优先级越高,则优先执行;对于后置通知,优先级越高,则越后执行。

3.         通过new产生的实例也会触发通知吗?

通过new方法产生的实例是不会触发切面通知的,比如上面的实例中,我们通过下面的代码来调用update方法是不会触发通知的。

StudentMgr  aStudentMgr = new StudentMgr();

aStudentMgr.update(“wuguowei”);//new实例对象是不会触发切面通知的。

 

4.         ApplicationContext获得的bean可以不是接口吗?

当我们在通过Spring的ApplicationContext来获取bean的时候,返回的对象可以是接口或者接口的实现,如果一个实现类继承了接口,但是把获取到的类转化为了实现类,则会报类转化的错误。比如我们执行下面的代码

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

StudentMgr studentMgr = (StudentMgr) context.getBean("IStudentMgr");//这里会报错,StudentMgr实现了接口,这里转化为接口的话则不会报错

 

则会报下面的转化错误,信息如下:

java.lang.ClassCastException: $Proxy9 cannot be cast to com.trs.components.mgr.StudentMgr

at com.trs.components.mgr.StudentMgrTest.testUpdate(StudentMgrTest.java:29)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

 

5.         BeanFactory和ApplicationContext的区别

l  BeanFactory主要负责配置和管理bean对象及其加载

l  ApplicationContext是BeanFactory的扩展类,包含了BeanFactory的所有功能,同时增加了更多支持企业核心内容的功能,比如AOP

l  BeanFactory为延迟加载,而ApplicationContext为初始化的时候就把所有的bean加载进来。这样ApplicationContext能够更早的发现程序中的Bug,而BeanFactory只有在使用的时候才能发现程序中的Bug。

6.         切入点表达式的说明

Spring AOP中我们经常使用execution pointcut designator来定义切入点,表达式的格式如下:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)

除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是 *,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用 * 通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:() 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。 模式 (*) 匹配了一个接受一个任何类型的参数的方法。 模式 (*,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型。 请参见AspectJ编程指南的Language Semantics 部分。

任意公共方法的执行

execution(public * *(..))

任何一个以“set”开始的方法的执行

execution(* set*(..))

AccountService 接口的任意方法的执行

execution(* com.xyz.service.AccountService.*(..))

定义在service包里的任意方法的执行

execution(* com.xyz.service.*.*(..))

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wyjgwf.html