4

我正在寻找对这个问题的更好理解。一种解决方法非常简单,即将配置数据移动到另一个没有代理/建议的类,但我认为更好地理解这一点将有助于我将来避免其他相关问题,所以我想要任何解释可以提供。

我将 Spring 3.1.0.RELEASE 与 Spring STS 和 vFabric tc 服务器一起使用。使用 @Controller 类实现了一个基本的小型 REST 服务器。这一切都很好(确实如此),但@Controller 也是@Transactional,在它与加载时间编织和 vFabric tc 服务器之间,它破坏了@Value。

@Controller
@RequestMapping("/hello")
public class MyAPI {

    @Value("${my.property}")
    private String prop;
    ...

    @Transactional
    handleRequest(...) ...


}

还有一个属性文件 app.properties:

my.property = SUCCESS

这在 JUnit 下运行良好,测试获得了一个将 prop 设置为“SUCCESS”的 MyAPI 对象。但是当应用程序被加载到 vFabric 中时,我猜它会获得加载时间编织和代理。无论发生什么,都会创建两个 MyAPI 实例,一个具有 prop == "SUCCESS",另一个(不幸的是,它是处理 http 请求的那个)具有 prop == "${my.prop}"。

所以总而言之,我称之为魔法失败,这是我使用 AOP 之类的东西时最关心的问题。即使使用 STS,我也不知道如何找出问题背后的原因或弄清楚这是否是一个严重的错误。如果是 bug,我不知道是 Spring、AspectJ、load-time weaver 还是 vFabric 中的 bug,所以我什至不知道在哪里提交 bug 报告。

因此,对于理解这一点的任何帮助将不胜感激。谢谢。

4

4 回答 4

6

我想到了。确实,这太魔幻了。

我在 STS 中使用 Spring Roo 来生成基本的应用程序框架,然后使用 STS 分解 Roo,因为我们不想坚持使用它。

Roo 作为“最佳实践”所做的一件事是创建两个 Spring 上下文,一个用于整个应用程序,一个仅限于调度程序 servlet。究竟是为什么,我还没有明白,但我猜他们希望保持表示层的东西,比如控制器,不会蔓延到共享的服务层。axtavt在这里很好地解释了这一点。这一切都被 STS 隐瞒了。

在带有 Roo 的 STS 中,WEB-INF 源不是我期望的,在 /src/main/resources 下(这是 META-INF 目录所在的位置),而是在 /src/main/webapp 下,它不是 Java源目录,因此完全单独显示,就在 /target 目录上方,所以我误认为它是一个输出文件夹。

在 applicationContext.xml 中,Roo 插入了过滤器以防止应用程序上下文构造控制器,如 axtavt 的帖子中所述,但它还放入了另一个过滤器以消除扫描 Roo 生成的类。我同时取出了两个过滤器,我并不知道它们是用来做什么的,但我认为它们只是 Roo 的剩菜。

所以现在我遇到了控制器被创建两次的问题,如前所述。应用程序上下文中的那个获取分配的属性,因为它正在使用 applicationContext.xml 并查找属性文件。但是为什么他们都没有设置属性呢?

这让我回到了模糊的 webapps 文件夹。在 WEB-INF 文件夹中,Roo (自然地)放置了 web.xml 和一个包含 webmvc-config.xml 文件的 spring 文件夹。此配置文件设置为仅扫描、创建和设置控制器。web.xml 文件设置 web 应用程序使用 applicationContext.xml 和 dispatcherServlet 使用 webmvc-config.xml,所以我应该在 applicationContext.xml 中保留过滤器以避免重复创建。

最后一块拼图是这个 webmvc-config.xml 文件。由于这是设置控制器的上下文,因此文件还需要配置 <context:property-placeholder/> 以便它可以找到属性文件。

于 2012-04-12T02:50:50.037 回答
1

首先,使用 $ 的符号是正确的,而不是 #

现在关于原始海报,我认为您在 2 个注释(@Controller 和 @Transactional)之间存在冲突行为。

使用 @Transactional 注释将代理您的实现(我想检测错误并启动回滚)。

现在你说你看到了你的控制器的 2 个实例。那不应该发生。通常,您应该只在内存中加载一个控制器实例。

可能与您的配置文件有关,还是由于 @Transactional 的存在及其代理性质?

作为旁注,我从不在控制器本身中使用@Transactional,而是在服务或dao的方法上使用。由于可能失败并需要回滚的实际进程在那里,并且可以从不同的控制器/源访问。

问候。

于 2012-04-11T13:42:40.527 回答
1

我有同样的问题,这是我需要两者的事实

让这两个 senarios 工作

  1. 将属性(通过@Value)注入控制器
  2. 将具有属性(通过@Value)的托管bean(通过@Inject)注入控制器

我希望这有帮助。

这是 web.xml。

    <servlet>
    <servlet-name>spring</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/spring-config/spring-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>spring</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

这是 spring-servlet.xml:关键是同时拥有 util:properties 和 context:property-placeholder。尽管它们定位相同的文件,但它们的用途不同。

<util:properties id="propSource" location="classpath:/properties/prop1.properties" />
<context:property-placeholder location="classpath:/properties/prop1.properties" />

<context:component-scan base-package="com.concurrent.controller" />

<context:annotation-config/>
<mvc:annotation-driven/> 

这是我的控制器类的片段:

@Controller
@RequestMapping("/fooController")
public class MyController {

@Value("${message1}")
public String message1;

@Inject
public ConfigProperties configProperties;

最后,这是我将属性注入的类:

@Service
public class ConfigProperties {

@Value("${message1}")
public String message1;
}

这对我有用,也对你有用。祝你好运!

于 2013-10-30T05:35:13.757 回答
0

就我而言,我是这样解决的:在我放这个spring-servlet.xml之前:<context:component-scan ... />

<context:property-placeholder location="classpath:strings.properties"/>

虽然strings.properties我把文件放到src/main/resources/.

注意:context:property-placeholder标签的可见性有限,因此我在某处阅读了建议,以在每个上下文文件中复制它,您可以在其中使用字符串。

于 2013-09-11T03:49:03.043 回答