您的位置:首页 > 编程语言 > Java开发

《Spring实战》学习笔记(三)面向切面的Spring

2017-02-05 15:04 791 查看

使用注解创建切面

定义切面

代码结构



程序清单

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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: