zoukankan      html  css  js  c++  java
  • Spring 实战-第四章-4.3使用注解创建切面

    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
  • 相关阅读:
    Dubbo服务提供者Provider启动流程下(四)
    修改超链接的默认格式
    给 3Com 3C940 Gigabit LOM 安装Windows Server 2008 驱动
    Express版SQL定时备份BAK文件(SQL2005,SQL2008)
    DataGridView的行、列调整
    更新DNS缓存
    VB.Net类型转换——全角半角间转换(StrConv)
    VB.Net 获取或者转换时间不受系统时间格式影响
    Active Desktop
    VB.Net类型转换——全角半角间转换(StrConv)
  • 原文地址:https://www.cnblogs.com/lvjianwei/p/7700931.html
Copyright © 2011-2022 走看看