笔记8 AOP练习2
场景描述:
一张唱片有好多磁道,假设每个磁道只有一首歌,现在需要记录每首歌的播放次数,然后输出。
主要业务:歌曲播放
辅助功能:记录播放次数(切面)
1.创建唱片接口,CompactDiscs.java
1 package soundsystem; 2 3 public interface CompactDiscs { 4 void playTrack(int number); 5 }
2.创建唱片接口的实现类,BlankDisc.java 里面包含一个方法playTrack(int number),根据传入的磁道编号,播放对应的歌曲。
1 package soundsystem; 2 3 import java.util.List; 4 5 public class BlankDisc implements CompactDiscs { 6 private String title; 7 private String artist; 8 private List<String> tracks; 9 10 public String getTitle() { 11 return title; 12 } 13 14 public void setTitle(String title) { 15 this.title = title; 16 } 17 18 public String getArtist() { 19 return artist; 20 } 21 22 public void setArtist(String artist) { 23 this.artist = artist; 24 } 25 26 public List<String> getTracks() { 27 return tracks; 28 } 29 30 public void setTracks(List<String> tracks) { 31 this.tracks = tracks; 32 } 33 34 @Override 35 public void playTrack(int number) { 36 System.out.println(tracks.get(number - 1)); 37 } 38 39 }
3.创建记录播放次数的类,TrackCounter.java<切面>
1 package soundsystem; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 import org.aspectj.lang.annotation.Aspect; 7 import org.aspectj.lang.annotation.Before; 8 import org.aspectj.lang.annotation.Pointcut; 9 10 @Aspect 11 public class TrackCounter { 12 private Map<Integer, Integer> trackCounts = new HashMap<Integer, Integer>(); 13 14 @Pointcut("execution(* soundsystem.CompactDiscs.playTrack(int))" + "&& args(trackNumber)") 15 public void trackPlayed(int trackNumber) { 16 } 17 18 @Before("trackPlayed(trackNumber)") 19 public void countTrack(int trackNumber) { 20 int currentCount = getPlayCount(trackNumber); 21 trackCounts.put(trackNumber, currentCount + 1); 22 } 23 24 public int getPlayCount(int trackNumber) { 25 return trackCounts.containsKey(trackNumber) ? trackCounts.get(trackNumber) : 0; 26 } 27 }
这个切面使用@Pointcut注解定义命名的切点,并使用@Before将一个方法声明为前置通知,切点还声明了要提供给通知方法的参数。
在切点表达式中的args(trackNumber)限定符。它表明传递给playTrack()方法的int类型参数也会传递到通知中去。参数的名称trackNumber也与切点方法签名中的参数相匹 配。这个参数会传递到通知方法中,这个通知方法是通过@Before注解和命名切点trackPlayed(trackNumber)定义的。切点定义中的参数与切点方法中的参数名称是一样的,这样就完成了从命名切点到 通知方法的参数转移。
4.创建配置文件,TrackCounterConfig.java <声明两个Bean>
1 package soundsystem; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import org.springframework.context.annotation.Bean; 7 import org.springframework.context.annotation.Configuration; 8 import org.springframework.context.annotation.EnableAspectJAutoProxy; 9 10 @Configuration 11 @EnableAspectJAutoProxy 12 public class TrackCounterConfig { 13 @Bean 14 public CompactDiscs sgtPeppers() { 15 BlankDisc cd = new BlankDisc(); 16 cd.setTitle("ABCCCCCCCCCCCCCCC"); 17 cd.setArtist("CCCCCCCCCCCCCCAB"); 18 List<String> tracks = new ArrayList<String>(); 19 tracks.add("11111"); 20 tracks.add("222222"); 21 tracks.add("3333333"); 22 tracks.add("44444444"); 23 tracks.add("555555555"); 24 cd.setTracks(tracks); 25 return cd; 26 } 27 28 @Bean 29 public TrackCounter trackCounter() { 30 return new TrackCounter(); 31 } 32 }
5.测试,TrackCounterTest.java
1 package soundsystem; 2 3 import org.junit.Test; 4 import org.junit.runner.RunWith; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.test.context.ContextConfiguration; 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 9 @RunWith(SpringJUnit4ClassRunner.class) 10 @ContextConfiguration(classes = soundsystem.TrackCounterConfig.class) 11 public class TrackCounterTest { 12 @Autowired 13 private CompactDiscs cd; 14 @Autowired 15 private TrackCounter counter; 16 17 @Test 18 public void test() { 19 cd.show(); 20 cd.playTrack(1); 21 cd.playTrack(2); 22 cd.playTrack(2); 23 cd.playTrack(3); 24 cd.playTrack(3); 25 cd.playTrack(3); 26 cd.playTrack(4); 27 cd.playTrack(4); 28 cd.playTrack(4); 29 cd.playTrack(5); 30 cd.playTrack(5); 31 for (int i = 1; i < 6; i++) { 32 System.out.println("磁道" + i + "播放了" + counter.getPlayCount(i) + "次"); 33 } 34 } 35 }
6.结果