使用注解创建切面
定义切面
代码结构
程序清单
PS:定义切面
package concert;
import org.aspectj.lang.annotation.*;
@Aspect
public class Audience {
@Pointcut(
"execution(** concert.Performance.perform(..))")
public void performance() {}
@Before(
"performance()")
public void silenceCellPhones() {
System.out.println(
"Silencing cell phones");
}
@Before(
"performance()")
public void takeSeats() {
System.out.println(
"Taking seats");
}
@AfterReturning(
"performance()")
public void applause() {
System.out.println(
"CLAP CLAP CLAP!!!");
}
@AfterThrowing(
"performance()")
public void demandRefund() {
System.out.println(
"Demanding a refund");
}
}
PS:Java配置,@EnableAspectJAutoProxy启用AspectJ自动代理
package concert;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig {
@Bean
public Audience
audience() {
return new Audience();
}
}
PS:切点接口
package concert;
public interface Performance {
public void perform();
}
PS:切点接口实现
package concert;
import org.springframework.stereotype.Component;
@Component
public class PerformanceImpl implements Performance {
public void perform() {
System.out.println(
"Singing!!!");
}
}
PS:如果通过XML装配bean
<?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.xsd">
<context:component-scan base-package="concert"/>
<aop:aspectj-autoproxy />
<bean class="concert.Audience" />
</beans>
测试
import concert
.ConcertConfig
import concert
.Performance
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
@RunWith(SpringJUnit4ClassRunner
.class)
@ContextConfiguration(classes = ConcertConfig
.class)
public class PerformanceTest {
@Autowired
private Performance performance
@Test
public void perform() {
performance
.perform()
}
}
创建环绕通知
PS:把上面的切面代码改为如下。
package concert;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class Audience {
@Pointcut(
"execution(** concert.Performance.perform(..))")
public void performance() {}
@Around(
"performance()")
public void watchPerformance(ProceedingJoinPoint jp) {
try {
System.out.println(
"Silencing cell phones");
System.out.println(
"Taking seats");
jp.proceed();
System.out.println(
"CLAP CLAP CLAP!!!");
}
catch (Throwable e) {
System.out.println(
"Demanding a refund");
}
}
}
处理通知中的参数
代码结构
程序清单
package soundsystem;
import java.util.List;
public class BlankDisc implements CompactDisc {
private String title;
private String artist;
private List<String> tracks;
public void setTitle(String title) {
this.title = title;
}
public void setArtist(String artist) {
this.artist = 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);
}
}
public void playTrack(
int trackNumber) {
System.out.println(
"Playing track"+trackNumber);
}
}
package soundsystem;
public interface CompactDisc {
public void play();
public void playTrack(
int trackNumber);
}
package 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(* soundsystem.CompactDisc.playTrack(int)) "+
"&& args(trackNumber)")
public void trackPlayed(
int trackNumber) {}
@Before(
"trackPlayed(trackNumber)")
public void countTrack(
int trackNumber) {
int currentCount = getPlayCount(trackNumber);
trackCounts.put(trackNumber, currentCount+
1);
}
public int getPlayCount(
int trackNumber) {
return trackCounts.containsKey(trackNumber) ? trackCounts.get(trackNumber) :
0;
}
}
package soundsystem;
import org.springframework.context.annotation.Bean;
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(
"hello");
cd.setArtist(
"world");
List<String> tracks =
new ArrayList<String>();
tracks.add(
"11111");
tracks.add(
"22222");
tracks.add(
"33333");
tracks.add(
"44444");
tracks.add(
"55555");
cd.setTracks(tracks);
return cd;
}
@Bean
public TrackCounter
trackCounter() {
return new TrackCounter();
}
}
测试
import org
.junit.Rule
import org
.junit.Test
import org
.junit.contrib.java.lang.system.StandardOutputStreamLog
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 soundsystem
.CompactDisc
import soundsystem
.TrackCounter
import soundsystem
.TrackCounterConfig
import static org
.junit.Assert.assertEquals
@RunWith(SpringJUnit4ClassRunner
.class)
@ContextConfiguration(classes= TrackCounterConfig
.class)
public class TrackCounterTest {
@Rule
public final StandardOutputStreamLog log = new StandardOutputStreamLog()
@Autowired
private CompactDisc cd
@Autowired
private TrackCounter counter
@Test
public void testTrackCounter() {
cd
.playTrack(
1)
cd
.playTrack(
2)
cd
.playTrack(
3)
cd
.playTrack(
3)
cd
.playTrack(
3)
cd
.playTrack(
3)
cd
.playTrack(
7)
cd
.playTrack(
7)
assertEquals(
1, counter
.getPlayCount(
1))
assertEquals(
1, counter
.getPlayCount(
2))
assertEquals(
4, counter
.getPlayCount(
3))
assertEquals(
0, counter
.getPlayCount(
4))
assertEquals(
0, counter
.getPlayCount(
5))
assertEquals(
0, counter
.getPlayCount(
6))
assertEquals(
2, counter
.getPlayCount(
7))
}
}
通过注解引入新功能
参考:Spring Aop 使用注解引入新功能
代码结构
程序清单
PS:不需要,没有用到
package concert;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class Audience {
@Pointcut(
"execution(** concert.Performance.perform(..))")
public void performance() {}
@Around(
"performance()")
public void watchPerformance(ProceedingJoinPoint jp) {
try {
System.out.println(
"Silencing cell phones");
System.out.println(
"Taking seats");
jp.proceed();
System.out.println(
"CLAP CLAP CLAP!!!");
}
catch (Throwable e) {
System.out.println(
"Demanding a refund");
}
}
}
PS:注入EncoreableIntroducer
package concert;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig {
@Bean
public Audience
audience() {
return new Audience();
}
@Bean
public EncoreableIntroducer
encoreableIntroducer() {
return new EncoreableIntroducer(); }
}
PS:Encoreable实现类
package concert;
public class DefaultEncoreable implements Encoreable {
public void performEncore() {
System.out.println(
"performEncore!!!");
}
}
PS:Encoreable接口
package concert;
public interface Encoreable {
public void performEncore();
}
PS:EncoreableIntroducer切面,加号表示Performance所有子类型,不是Performance本身
package concert;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
@Aspect
public class EncoreableIntroducer {
@DeclareParents(value=
"concert.Performance+",defaultImpl = DefaultEncoreable.class)
public static Encoreable encoreable;
}
PS:Performance接口
package concert;
public interface Performance {
public void perform();
}
PS:Performance实现类
package concert;
import org.springframework.stereotype.Component;
@Component
public class PerformanceImpl implements Performance {
public void perform() {
System.out.println(
"Singing!!!");
}
}
测试
import concert
.ConcertConfig
import concert
.Encoreable
import concert
.Performance
import org
.junit.Test
import org
.junit.runner.RunWith
import org
.springframework.beans.factory.annotation.Autowired
import org
.springframework.context.ApplicationContext
import org
.springframework.test.context.ContextConfiguration
import org
.springframework.test.context.junit4
.SpringJUnit4ClassRunner
@RunWith(SpringJUnit4ClassRunner
.class)
@ContextConfiguration(classes = ConcertConfig
.class)
public class PerformanceTest {
@Autowired
private ApplicationContext context
@Test
public void performEncore() {
//对象performanceImpl不仅有PerformanceImpl的功能,也有DefaultEncoreable类的功能
Encoreable encoreable = (Encoreable) context
.getBean(
"performanceImpl")
encoreable
.performEncore()
}
}
在XML声明切面
声明前置和后置通知
<aop:config>
<aop:aspect
ref=
"audience">
<aop:pointcut
id=
"performance" expression=
"execution(** concert.Performance.perform(..))"/>
<aop:
before pointcut-
ref=
"performance" method=
"silenceCellPhones" />
<aop:
before pointcut-
ref=
"performance" method=
"takeSeats" />
<aop:
after-
returning pointcut-
ref=
"performance" method=
"applause" />
<aop:
after-throwing pointcut-
ref=
"performance" method=
"demandRefund" />
</aop:aspect>
</aop:config>
package concert;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
public class Audience {
public void silenceCellPhones() {
System.
out.println(
"Silencing cell phones");
}
public void takeSeats() {
System.
out.println(
"Taking seats");
}
public void applause() {
System.
out.println(
"CLAP CLAP CLAP!!!");
}
public void demandRefund() {
System.
out.println(
"Demanding a refund");
}
}
声明环绕通知
<aop:config>
<aop:aspect ref="audience">
<aop:pointcut id="performance" expression="execution(** concert.Performance.perform(..))"/>
<aop:around pointcut-ref="performance" method="watchPerformance"/>
</aop:aspect>
</aop:config>
package concert;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
public class Audience {
public void watchPerformance(ProceedingJoinPoint jp) {
try {
System.
out.println(
"Silencing cell phones");
System.
out.println(
"Taking seats");
jp.proceed();
System.
out.println(
"CLAP CLAP CLAP!!!");
}
catch (Throwable e) {
System.
out.println(
"Demanding a refund");
}
}
}
为通知传递参数
package soundsystem;
import java.util.HashMap;
import java.util.Map;
public class TrackCounter {
private Map<Integer, Integer> trackCounts =
new HashMap<Integer, Integer>();
public void countTrack(
int trackNumber) {
int currentCount = getPlayCount(trackNumber);
trackCounts.put(trackNumber, currentCount+
1);
}
public int getPlayCount(
int trackNumber) {
return trackCounts.containsKey(trackNumber) ? trackCounts.get(trackNumber) :
0;
}
}
<?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.xsd">
<bean id="trackCounter" class="soundsystem.TrackCounter"/>
<bean id="cd" class="soundsystem.BlankDisc">
<property name="title" value="hello"/>
<property name="artist" value="world"/>
<property name="tracks">
<list>
<value>11111
</value>
<value>22222
</value>
<value>33333
</value>
<value>44444
</value>
<value>55555
</value>
</list>
</property>
</bean>
<aop:config>
<aop:aspect ref="trackCounter">
<aop:pointcut id="trackPlayed" expression="execution(* soundsystem.CompactDisc.playTrack(int)) and args(trackNumber)"/>
<aop:before pointcut-ref="trackPlayed" method="countTrack"/>
</aop:aspect>
</aop:config>
</beans>
通过切面引入新的功能
<?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.xsd">
<context:component-scan base-package="concert"/>
<aop:aspectj-autoproxy />
<bean id="audience" class="concert.Audience" />
<bean id="encorebleDelegate" class="concert.DefaultEncoreable"/>
<aop:config>
<aop:aspect ref="audience">
<aop:pointcut id="performance" expression="execution(** concert.Performance.perform(..))"/>
<aop:around pointcut-ref="performance" method="watchPerformance"/>
</aop:aspect>
<aop:aspect>
<aop:declare-parents types-matching="concert.Performance+" implement-interface="concert.Encoreable" delegate-ref="encorebleDelegate"/>
</aop:aspect>
</aop:config>
</beans>