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

使用注解创建切面

定义切面

代码结构

《Spring实战》学习笔记(三)面向切面的Spring_第1张图片

程序清单

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


<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();
    }
}

《Spring实战》学习笔记(三)面向切面的Spring_第2张图片

创建环绕通知

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");
        }
    }
}

处理通知中的参数

代码结构

《Spring实战》学习笔记(三)面向切面的Spring_第3张图片

程序清单

package soundsystem;

import java.util.List;

public class BlankDisc implements CompactDisc {
    private String title;
    private String artist;
    private List tracks;

    public void setTitle(String title) {
        this.title = title;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }

    public void setTracks(List 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 trackCounts = new HashMap();

    @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 tracks = new ArrayList();
        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实战》学习笔记(三)面向切面的Spring_第4张图片

通过注解引入新功能

参考:Spring Aop 使用注解引入新功能

代码结构

《Spring实战》学习笔记(三)面向切面的Spring_第5张图片

程序清单

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();
    }
}

《Spring实战》学习笔记(三)面向切面的Spring_第6张图片

在XML声明切面

声明前置和后置通知


    ref="audience">
        id="performance" expression="execution(** concert.Performance.perform(..))"/>
        before pointcut-ref="performance" method="silenceCellPhones" />
        before pointcut-ref="performance" method="takeSeats" />
        after-returning pointcut-ref="performance" method="applause" />
        after-throwing pointcut-ref="performance" method="demandRefund" />
    
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 trackCounts = new HashMap();

    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;
    }
}

<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>11111value>
                <value>22222value>
                <value>33333value>
                <value>44444value>
                <value>55555value>
            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>

通过切面引入新的功能


<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>

你可能感兴趣的:(Java__Spring)