Spring 2.0的新配置:
如果如果service没有基于接口,使用cgilib来实现AOP,定义proxy-target-class="true"
<aop:config proxy-target-class="true">
<aop:advisor pointcut="execution(* com.cutoff.service..*Manager.*(..))" advice-ref="transactionAdvice"/>
//这里是spring例子自带的,可以实现自定义的advice,在每次save动作完成后。会触发emailAdvice
<aop:advisor pointcut="execution(* com.cutoff.service..*Manager.save(..))" advice-ref="emailAdvice"/>
</aop:config>
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="insert*" />
<tx:method name="update*" />
<tx:method name="save*" />
</tx:attributes>
</tx:advice>
<bean id="emailAdvice" class="org.springframework.samples.jpetstore.domain.logic.SendOrderConfirmationEmailAdvice">
<property name="mailSender" ref="mailSender"/>
</bean>
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="${mail.host}"/>
</bean>
唯一有点难懂的是pointcut里的语法,其实也很好学,Spring参考文档6.2.3.4 示例里有完整说明 ,其实一排子过去是
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)其中带问号的modifiers-pattern?(public/protected) 和 declaring-type-pattern? throws-pattern? 可以不填
execution(* *..BookManager.save(..))的解读:
第一颗* 代表ret-type-pattern 返回值可任意,
*..BookManager 代表任意Pacakge里的BookManager类。
如果写成com.xyz.service.* 则代表com.xyz.service下的任意类
com.xyz.service..* com.xyz.service则代表com.xyz.service及其子package下的任意类
save代表save方法,也可以写save* 代表saveBook()等方法
(..) 匹配0个参数或者多个参数的,任意类型
(x,..) 第一个参数的类型必须是X
(x,,,s,..) 匹配至少4个参数,第一个参数必须是x类型,第二个和第三个参数可以任意,第四个必须是s类型。
注意事项:
1. name-pattern千万不要写成*..*Manager ,这样子会把所有第三方类库的Manager比如Spring的PlatformTranstationManager 也加入aop,非常危险。所以最好还是加上项目的package前缀,如"org.springside..*Manager"
2. 因为有*,会修饰所有方法,有些hibernateTemplate的final的方法不能被cglib修改,会抛warning,无害。
4. 事务定义选项
事务定义一般默认的PROPAGATION_REQUIRED即可,另提供的几个选择很少使用。值得注意的是一个PROPAGATION_NESTED,嵌入式事务的意义在于多级事务,如果出错只rollback子事务自己,不rollback主事务的所有操作。比如OrderManager的shipOrder函数 调用 save函数,如果save()被定义为嵌入式事务,当进入save()时,会存储save point。如果在save 中出错,会rollback 到刚才的save point,但不影响其他的操作。这需要JDBC3.0 SavePoint功能的支持。 而一般service间互相嵌入调用时,如果都定义为PROPAGATION_REQUIRED,有其中一个操作出错,rollback全部操作。