hb1993 2022-01-29 19:50 采纳率: 50%
浏览 10

为什么使用 SpEL 语句“#{T(System).out}”无法注入 PrintStream 类型对象

问题场景

最近在看《Spring实战》第四版这本书,刚看完第一章,想跟着文中的例子自己练习一遍。结果出现了一个问题,就是在应用 DI 技术的骑士冒险的例子,具体的是应用 SpEL 注入 PrintStream 类型的时候发现这个类型不起作用,代码如下:

1、Quest 接口

public interface Quest {
    void embark();
}

2、Knight 接口

public interface Knight {
    void embarkOnQuest();
}

3、SlayDragonQuest 类继承 Quest 接口

public class SlayDragonQuest implements Quest {
    private PrintStream stream;

    public SlayDragonQuest(PrintStream stream) {
        this.stream = stream;
    }

    @Override
    public void embark() {
        stream.println("Embarking on quest to slay the dragon!");
    }
}

4、BraveKnight 类继承 Knight 接口

public class BraveKnight implements Knight {
    private Quest quest;

    public BraveKnight(Quest quest) {
        this.quest = quest;
    }

    @Override
    public void embarkOnQuest() {
        quest.embark();
    }
}

接着是 Spring bean 的 XML 配置文件

<?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: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/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    <bean id="braveKnight" class="com.hb.impl.BraveKnight">
        <constructor-arg ref="quest"></constructor-arg>
    </bean>

    <bean id="quest" class="com.hb.impl.SlayDragonQuest">
        <constructor-arg value="#{T(System).out}"></constructor-arg>
    </bean>

    <bean id="minstrel" class="com.hb.impl.Minstrel">
        <constructor-arg value="#{T(System).out}"></constructor-arg>
    </bean>

    <aop:config>
        <!-- 将吟游诗人 Minstrel 声明为一个切面 -->
        <aop:aspect ref="minstrel">
            <aop:pointcut id="embark" expression="execution(* com.hb.interfaces.Knight.embarkOnQuest(..))"/>
            <aop:before method="singBeforeQuest" pointcut-ref="embark"></aop:before>
            <aop:after method="singAfterQuest" pointcut-ref="embark"></aop:after>
        </aop:aspect>
    </aop:config>
</beans>

其中在 IDEA 中显示该配置文件时 SlayDragonQuest 和 Minstrel 这两个使用 SpEL 进行构造器注入 PrintStream 的 bean 有错误提示

img

img

只是当时没管这个提示就往下编写了这个功能的测试,代码如下:

@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = "classpath:knights.xml")
@ContextConfiguration(classes = KnightConfig.class)
public class SlayDragonQuestTest {
    @Rule
    public final StandardOutputStreamLog log = new StandardOutputStreamLog();

    @Autowired
    private Knight knight;

    @Test
    public void shouldBeNotNull() {
        Assert.assertNotNull(knight);
    }

    @Test
    public void shouldBeEqual() {
        knight.embarkOnQuest();
        Assert.assertEquals("Embarking on quest to slay the dragon!\r\n", log.getLog());
    }
}

执行测试方法 shouldBeEqual() 显示失败,细节如下:

img

img

简单分析应该是 SlayDragonQuest 类注入 PrintStream 时使用 SpEL 语句 “#{T(System).out}” 并没有注入成功。于是为了验证我的猜想将 SlayDragonQuest 类的 embark() 方法改成使用 System.out.println() 来实现。

@Override
    public void embark() {
//        stream.println("Embarking on quest to slay the dragon!");
        System.out.println("Embarking on quest to slay the dragon!");
    }

接着再执行测试方法就是正确的,说明 PrintStream 这个类型没有注入成功。

提出问题

找了半天没发现 PrintStream 为什么这样注入是失败的,而且书上的原文也是这样用的,对比了几遍确定代码是无误的。不知道为什么使用 “”“#{T(System).out}” 无法注入 PrintStream。麻烦各位帮忙看看,为什么会这样,原因是啥。

  • 写回答

1条回答 默认 最新

  • a1767028198 2022-01-30 16:26
    关注

    配置类没啥问题

    img

    评论

报告相同问题?

问题事件

  • 创建了问题 1月29日

悬赏问题

  • ¥15 如何让企业微信机器人实现消息汇总整合
  • ¥50 关于#ui#的问题:做yolov8的ui界面出现的问题
  • ¥15 如何用Python爬取各高校教师公开的教育和工作经历
  • ¥15 TLE9879QXA40 电机驱动
  • ¥20 对于工程问题的非线性数学模型进行线性化
  • ¥15 Mirare PLUS 进行密钥认证?(详解)
  • ¥15 物体双站RCS和其组成阵列后的双站RCS关系验证
  • ¥20 想用ollama做一个自己的AI数据库
  • ¥15 关于qualoth编辑及缝合服装领子的问题解决方案探寻
  • ¥15 请问怎么才能复现这样的图呀