概述:
本书建立过这样一种原则,那就是基于注解的配置要优于基于Java的配置,基于Java的配置要优于基于XML的配置。但是,如果你需要声明切面,但是又不能为通知类添加注解的时候,那么就必须转向XML配置了。
基于xml配置切面保证你类看起来很干净
需要用到的标签:
- <aop:advisor> 定义AOP通知器
- <aop:after> 定义AOP后置通知(不管被通知的方法是否执行成功)
- <aop:after-returning> 定义AOP返回通知
- <aop:after-throwing> 定义AOP异常通知
- <aop:around> 定义AOP的环绕通知
- <aop:aspect> 定义一个切面
- <aop:aspectj-autoproxy> 启用@AspectJ注解驱动的切面
- <aop:before> 定义一个AOP的前置通知
- <aop:config>顶层的AOP配置元素,大多数的<aop:*>元素必须包含在<aop:config>元素内
- <aop:declare-parents> 以透明的方式为被通知的对象引入额外的接口
- <aop:pointcut> 定义一个切点
首先配置xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<!-- 这里有点dry -->
<!-- <aop:config>
<aop:aspect ref="audience">
<aop:before method="silenceCellPhones"
pointcut="execution(* *.chapter4.Performance.perform(..))"/>
<aop:before method="takeSeats"
pointcut="execution(* *.chapter4.Performance.perform(..))"/>
<aop:after-returning method="applause"
pointcut="execution(* *.chapter4.Performance.perform(..))"/>
<aop:after-throwing method="demandRefund"
pointcut="execution(* *.chapter4.Performance.perform(..))"/>
</aop:aspect>
</aop:config> -->
<bean id="audience" class="learn.chapter4.Audience"/>
<bean id="chaplin" class="learn.chapter4.Chaplin"/>
<aop:config>
<aop:aspect ref="audience">
<aop:pointcut expression="execution(* *.chapter4.Performance.perform(..))"
id="performance"/>
<aop:before method="silenceCellPhones"
pointcut-ref="performance"/>
<aop:before method="takeSeats"
pointcut-ref="performance"/>
<aop:after-returning method="applause"
pointcut-ref="performance"/>
<aop:after-throwing method="demandRefund"
pointcut-ref="performance"/>
</aop:aspect>
</aop:config>
</beans>
总结:
1.必须增加aop命名空间
2.注意切点名和bean的Id不能相同
3.<aop:aspect ref="audience"> 是执行内容 what
package learn.chapter4;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class Audience {
public void silenceCellPhones(){
System.out.println("手机设置成静音状态");
}
public void takeSeats() {
System.out.println("选择位子坐下");
}
public void applause(){
System.out.println("表演很精彩,鼓掌!");
}
public void demandRefund(){
System.out.println("太烂了,请求退款");
}
}
package learn.chapter4;
public class Chaplin implements Performance{
public void perform() {
System.out.println("卓别林正在表演哑剧。。。。。");
}
}
package learn.chapter4.javaConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
@Configuration
@ImportResource("classpath:aop.xml")
public class XmlConfig {
}
总结:通过@ImportResource导入xml配置文件
package learn.chapter4;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import learn.chapter4.javaConfig.XmlConfig;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={XmlConfig.class})
public class XmlAOPTest {
@Autowired
private Performance performance;
@Test
public void play(){
performance.perform();
}
}
结果为:
手机设置成静音状态
选择位子坐下
卓别林正在表演哑剧。。。。。
表演很精彩,鼓掌!
环绕通知:(将上面4个合并为一个环绕通知)
package learn.chapter4;
import org.aspectj.lang.ProceedingJoinPoint;
public class Audience {
public void watchPerformance(ProceedingJoinPoint jp){
try{
System.out.println("手机设置成静音状态");
System.out.println("选择位子坐下");
jp.proceed();
System.out.println("表演很精彩,鼓掌!");
} catch (Throwable e) {
System.out.println("太烂了,请求退款");
}
}
}
然后修改一个配置
<aop:config><aop:aspect ref="audience">
<aop:pointcut expression="execution(* *.chapter4.Performance.perform(..))"
id="performance"/>
< aop:around method=" watchPerformance"
pointcut-ref="performance"/>
</aop:aspect>
</aop:config>
2。为通知传递参数
创建一个计数的类
package learn.chapter4;
import java.util.HashMap;
import java.util.Map;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
public class TrackCounter {
private Map<Integer, Integer> trackCounts =
new HashMap<Integer, Integer>();
public void trackPlayed(int trackNumber){}
public void countTrack(int trackNumber) {
System.out.println("===================");
int currentCount = getPlayCount(trackNumber);
trackCounts.put(trackNumber, currentCount+1);
}
public int getPlayCount(int trackNumber) {
return trackCounts.containsKey(trackNumber)
? trackCounts.get(trackNumber) : 0;
}
}
增加 xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
<bean id="trackCounter" class="learn.chapter4.TrackCounter"/>
<bean id="cd" class="learn.chapter4.BlankDisc">
<property name="title" value="beyond"/>
<property name="artist" value="25年精选"/>
<property name="tracks">
<list>
<value>海阔天空</value>
<value>光辉岁月</value>
<value>情人</value>
<value>谁伴我闯荡</value>
<value>不再犹豫</value>
<value>冷雨夜</value>
</list>
</property>
</bean>
<aop:config>
<aop:aspect ref="trackCounter">
<aop:pointcut expression="execution(* *.chapter4.CompactDisc.playTrack(int))
and args(trackNumber)"
id="trackPlayed"/>
<aop:before method="countTrack"
pointcut-ref="trackPlayed"/>
</aop:aspect>
</aop:config>
</beans>
测试类:
package learn.chapter4;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import learn.chapter4.javaConfig.XmlConfig;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={XmlConfig.class})
public class TrackCounterTest {
@Autowired
private CompactDisc cd;
@Autowired
private TrackCounter counter;
@Test
public void testCounter(){
cd.playTrack(0);
cd.playTrack(1);
cd.playTrack(2);
cd.playTrack(3);
cd.playTrack(3);
cd.playTrack(4);
cd.playTrack(5);
cd.playTrack(5);
cd.playTrack(5);
System.out.println(counter.getPlayCount(1));
System.out.println(counter.getPlayCount(2));
System.out.println(counter.getPlayCount(3));
System.out.println(counter.getPlayCount(4));
System.out.println(counter.getPlayCount(5));
System.out.println(counter.getPlayCount(0));
}
}
package learn.chapter4;
/**
* 定义一个CD接口
* @author chenliang
*
*/
public interface CompactDisc {
void play();
void playTrack(int num);
}
package learn.chapter4;
import java.util.List;
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
public BlankDisc() {
super();
// TODO Auto-generated constructor stub
}
public BlankDisc(String title, String artist) {
super();
this.title = title;
this.artist = artist;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public List<String> getTracks() {
return tracks;
}
public void setTracks(List<String> tracks) {
this.tracks = tracks;
}
@Override
public String toString() {
return "BlankDisc [title=" + title + ", artist=" + artist + ", tracks=" + tracks + "]";
}
public void play() {
System.out.println("专辑为" + title + "\t 歌手为:" + artist);
if(null!=tracks && tracks.size() > 0){
for (String track : tracks){
System.out.println("---磁道: " + track);
}
}
}
public void playTrack(int num) {
System.out.println("获取对应磁道:" + num +"\t 歌曲为:"+ tracks.get(num));
}
}
结果:
===================
获取对应磁道:0 歌曲为:海阔天空
===================
获取对应磁道:1 歌曲为:光辉岁月
===================
获取对应磁道:2 歌曲为:情人
===================
获取对应磁道:3 歌曲为:谁伴我闯荡
===================
获取对应磁道:3 歌曲为:谁伴我闯荡
===================
获取对应磁道:4 歌曲为:不再犹豫
===================
获取对应磁道:5 歌曲为:冷雨夜
===================
获取对应磁道:5 歌曲为:冷雨夜
===================
获取对应磁道:5 歌曲为:冷雨夜
1
1
2
1
3
1
总结:xml配置AOP比较简洁,适用范围广