在Spring中编程AOP时的奇怪异常

时间:2018-03-30 08:40:28

标签: java spring aop

我在春天学习AOP时遇到了一个非常奇怪的异常。

以下是我的代码:

CompactDisc界面:

public interface CompactDisc {
    void play();
}

BlankDisc类:

import org.springframework.stereotype.Component;
import java.util.List;

@Component
public class BlankDisc implements CompactDisc {
    private String title;
    private String artist;
    private List<String> tracks;

    public BlankDisc(String title, String artist, List<String> tracks) {
        this.title = title;
        this.artist = artist;
        this.tracks = tracks;
    }

    @Override
    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("-Track "+tracks.get(trackNumber));
    }

TrackCounter类

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

    @Pointcut("execution(* BlankDisc.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.getOrDefault(trackNumber, 0);
    }
}

TrackCounterConfig类

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(name = "compactDisc")
    public BlankDisc blankDisc() {
        List<String> list= new ArrayList<>(5);
        list.add("Sgt.Pepper's Lonely Hearts Club Band");
        list.add("With a Little Help from My Friends");
        list.add("Lucy in the Sky with Diamonds");
        list.add("Getting Better");
        list.add("Fixing a Hole");

        return new BlankDisc("Sgt.Pepper's Lonely Hearts Club Band","The Beatles",list);
    }

    @Bean
    public TrackCounter trackCounter() {
        return new TrackCounter();
    }
}

TrackCounterTest类:

import static org.junit.Assert.*;

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;
import soundsystem.*;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TrackCounterConfig.class)
public class TrackCounterTest {
    @Autowired
    private BlankDisc cd;

    @Autowired
    private TrackCounter counter;

    @Test
    public void testTrackCounter() {
        //Question: cd must be CompactDisc not BlankDisc,
        //otherwise will cause type exception, why?
        cd.playTrack(0);
        cd.playTrack(1);
        cd.playTrack(2);
        cd.playTrack(3);
        cd.playTrack(3);
        cd.playTrack(3);
        cd.playTrack(3);
        cd.playTrack(4);

        assertEquals(1,counter.getPlayCount(1));
        assertEquals(1,counter.getPlayCount(0));
        assertEquals(1,counter.getPlayCount(2));
        assertEquals(4,counter.getPlayCount(3));
        assertEquals(1,counter.getPlayCount(4));
    }
}

我跑了测试,然后我有例外:

Caused by: org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'compactDisc' is expected to be of type 'soundsystem.BlankDisc' but was actually of type 'com.sun.proxy.$Proxy22'
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.checkBeanNotOfRequiredType(DefaultListableBeanFactory.java:1510)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1489)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)

问题是:

1.如果我将cdTrackCounterTest的类型从BlankDisc更改为CompactDisc,则不会发生异常,为什么?

2.第一个问题解决后,如果我未在界面void playTrack(int)中声明方法CompactDisc,则测试类中的assertEquals()将失败。也就是说,AOP不起作用,为什么?

我花了一整天的时间研究这个问题,在搜索谷歌后我仍然无法找到答案。由于我是春天的新秀,我真诚地希望有人能帮助我解决这个问题。

谢谢!!!

1 个答案:

答案 0 :(得分:0)

这个问题是因为自动装配类型类的bean而不是实现的接口: 请检查此stackoverflow链接,该链接解释了同样的问题:

BeanNotOfRequiredTypeException issue stackoverflow explanation