AspectJ面向注解的模型可以非常简便地通过少量注解把任意类转变为切面。
注解类型:
注解 | 功能 |
@Aspect | 将类声明为一个切面 |
@After | 通知方法会在目标方法返回或抛出异常后调用 |
@AfterReturning | 通知方法会在目标方法返回后调用 |
@AfterThrowing | 通知方法会在目标方法抛出异常后调用 |
@Around | 通知方法会将目标方法封装起来 |
@Before | 通知方法会在目标方法调用之前执行 |
定义接口CompactDisc
package main.java.soundsystem; public interface CompactDisc { void play(); void playTrack(Integer trackNumber); }
实现BlankDisc:
package main.java.soundsystem; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Component public class BlankDisc implements CompactDisc{ private String title; private String artist; private List<String> tracks; public BlankDisc setTitle(String title) { this.title = title; return this; } public BlankDisc setArtist(String artist) { this.artist = artist; return this; } public String getTitle() { return title; } public String getArtist() { return artist; } public void setTracks(List<String> tracks) { this.tracks = tracks; } public void play() { System.out.println("Playing " + title + " by " + artist); for (String track : tracks) { System.out.println("-Track: " + track); } } @Override public void playTrack(Integer trackNumber) { System.out.println("Playing "+tracks.get(trackNumber-1)); } }
定义一个切面,用于计数播放次数,类上的@Aspcet注解表示这是一个切面,在方法上的@Before等表示了方法执行的顺序
其中@Before("execution(* CompactDisc.playTrack(Integer)) && args(trackNumber)")表达式,
表示要在CompactDisc.playTrack方法执行前执行被注解的方法,并且有一个Integer的参数,前面的*表示不限制返回参数。
当对于某个点需要执行多个方法,在每个注解上重复方法声明就有些冗余,所以这里使用
@Pointcut("execution(* CompactDisc.playTrack(Integer)) && args(trackNumber)") public void trackPlayed(int trackNumber) { }
定义一个切点,其中的方法名字可以为任意名字,只要保证输入输出与代理方法一致就行,这样在声明通知的时候,只需要简短的声明即可。
package main.java.soundsystem; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import java.util.HashMap; import java.util.Map; @Aspect public class TrackCounter { private Map<Integer, Integer> trackCounts = new HashMap<Integer, Integer>(); @Pointcut("execution(* CompactDisc.playTrack(Integer)) && args(trackNumber)") public void trackPlayed(int trackNumber) { } // @Before("execution(* CompactDisc.playTrack(int)) && args(trackNumber)") @Before("trackPlayed(trackNumber)") public void countTrack(int trackNumber) { int currentCount = getPlayCount(trackNumber); System.out.println("TrackCoutner:" + trackNumber); trackCounts.put(trackNumber, currentCount + 1); } @Before("execution(* CompactDisc.play())") public void test2() { System.out.println("this is trackCounter test2"); } @Before("execution(* CompactDisc.play())") public void test1() { System.out.println("this is trackCounter test1"); } public void PrintMap() { trackCounts.forEach((k, v) -> System.out.println("Key:" + k + ",Value:" + v)); } public int getPlayCount(int trackNumber) { return trackCounts.containsKey(trackNumber) ? trackCounts.get(trackNumber) : 0; } }
如果使用Javaconfig,可以在配置类的类级别上通过使用@EnableAspectJAutoProxy注解启用自动代理功能。
package main.java.soundsystem; import com.sun.deploy.util.BlackList; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; import java.util.ArrayList; import java.util.List; @Configuration @EnableAspectJAutoProxy public class TrackCounterConfig { @Bean public CompactDisc sgtPeppers(){ BlankDisc cd=new BlankDisc(); cd.setTitle("Sgt. Pepper's Lonely Hearts Club Band"); cd.setArtist("The Beatles"); List<String> tracks=new ArrayList<String>(); tracks.add("Sgt. Pepper's Lonely Hearts Club Band"); tracks.add("With a Little Help from My Friends"); tracks.add("Lucy in the Sky with Diamonds"); tracks.add("Getting Better"); tracks.add("Fixing a Hole"); cd.setTracks(tracks); return cd; } @Bean public TrackCounter trackCounter(){ return new TrackCounter(); } }
也可以通过xml配置,使用Spring aop命名空间中的<aop:aspectj-autoproxy>元素,启用自动代理功能,
并且在名空间中使用aop相关配置
<?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/aop http://www.springframework.org/schema/aop/spring-aop.xsd 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"> <context:component-scan base-package="main.java.soundsystem"/> <aop:aspectj-autoproxy/> <bean class="main.java.soundsystem.TrackCounter"></bean> <bean xml:id="sgtPeppers" class="main.java.soundsystem.BlankDisc"> <property name="title" value="Sgt. Pepper's Lonely Heart Club Band"/> <property name="artist" value="the Beatles"/> <property name="tracks"> <list> <value>Sgt. Pepper's Lonely Hearts Club Band</value> <value>With a Little Help from My Friends</value> <value>Lucy in the Sky with Diamonds</value> <value>Getting Better</value> <value>Fixing a Hole</value> </list> </property> </bean> </beans>
测试代码
package main.java.soundsystem; import org.springframework.beans.factory.annotation.Autowired; import static org.junit.Assert.*; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {TrackCounterConfig.class}) public class TrackCounterTest { @Autowired private CompactDisc cd; @Autowired private TrackCounter counter; @Test public void testTrackCounter(){ cd.playTrack(1); cd.playTrack(1); cd.playTrack(3); cd.playTrack(4); cd.playTrack(4); cd.playTrack(4); assertEquals(2,counter.getPlayCount(1)); assertEquals(1,counter.getPlayCount(3)); assertEquals(3,counter.getPlayCount(4)); } }
结果:
Track:1 Playing Sgt. Pepper's Lonely Hearts Club Band Track:1 Playing Sgt. Pepper's Lonely Hearts Club Band Track:3 Playing Lucy in the Sky with Diamonds Track:4 Playing Getting Better Track:4 Playing Getting Better Track:4 Playing Getting Better