Spring AOP中的BeanNotOfRequiredTypeException异常

3

我正在尝试使用Spring AOP,以下是Spring配置文件:

<?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:util="http://www.springframework.org/schema/util" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
        http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <bean id="eddie" class="com.springinaction.Instrumentalist">
        <property name="instrument" ref="violin"></property>
        <property name="song" value="Samarame"></property>

    </bean>


    <bean id="kenny" class="com.springinaction.Instrumentalist">
        <property name="song" value="SAMARAME "></property>
        <property name="instrument" ref="saxopone"></property>
    </bean>

    <bean id="hank" class="com.springinaction.OneManBand">
        <property name="instruments">
            <props>
                <prop key="GUITAR">STRUM STRUM STRUM</prop>
                <prop key="CYMBAL">CRASH CRASH CRASH CRASH</prop>
                <prop key="HARMONICA">HUM HUM HUM</prop>
            </props>
        </property>
    </bean>

    <bean id="guitar" class="com.springinaction.Guitar">
    </bean>

    <bean id="violin" class="com.springinaction.Violin">
    </bean>

    <bean id="tabala" class="com.springinaction.Tabala">
    </bean>

    <bean id="saxopone" class="com.springinaction.Saxophone">
    </bean>

    <bean id="audience" class="com.springinaction.Audience"></bean>

    <aop:config>

        <aop:aspect ref="audience">

            <aop:before pointcut="execution(* com.springinaction.Performer.perform(..))" method="takeSeats()"/>
        </aop:aspect>
    </aop:config>

</beans>

当我运行代码时,出现错误提示:
“主线程中的异常 org.springframework.beans.factory.BeanNotOfRequiredTypeException: 名称为'eddie'的bean必须是类型为[com.springinaction.Instrumentalist], 但实际上是类型[$Proxy4]”。 在AbstractBeanFactory.java:348处, org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:348) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193) at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1008) at com.springinaction.Main.main(Main.java:12)
如果我在Spring配置文件中注释掉元素,则可以完美运行。
为什么会发生这种情况?
1个回答

7
默认情况下,Spring使用代理类来实现AOP。动态地创建了一个代理类以实现多个接口,您将其传递给一个'handler'对象,当在它上面调用这些接口方法时,它会调用该对象。您可以阅读代理对象的Javadoc这里
在应用程序上下文中初始化所有bean之后,Spring将执行任何必要的后处理。这包括应用AOP建议。Spring将使用另一个对象上的方法调用代理对象替换名称为eddie的bean,然后再将调用传递给原始对象。每当您请求名称为eddie的bean时,您都将获得代理对象而不是真实对象。
我找不到堆栈跟踪中提到的Main类的源代码,但我在这里找到了大部分其他代码。无论如何,在Main类中,似乎您正在做类似于下面的事情:
Instrumentalist eddie = (Instrumentalist) appContext.getBean("eddie", Instrumentalist.class);

Spring应用程序上下文的getBean(String, Class)方法将检查返回的bean是否是指定类的实例,如果不是,则会抛出异常。这就是上面示例中发生的情况。代理对象不是Instrumentalist的实例,而是其自己的代理类$Proxy4的实例。(这个代理类不能是Instrumentalist的子类,因为所有代理类都扩展了java.lang.reflect.Proxy)
代理类将始终实现它们创建时使用的所有接口。Spring将注意到Instrumentalist实现了Performer,因此它创建的代理类也将实现Performer。你可以用以下代码替换上面的行:
Performer eddie = (Performer) appContext.getBean("eddie", Performer.class);

只要你只需要在eddie上调用perform()方法,你的代码就可以工作。


感谢Litytestdata提供详细的答案...看起来你对SpringIdol比赛非常了解 :)我想我需要学习代理类...再次感谢你的澄清... - javanoob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接