Spring roo实体中的服务自动连接始终为null(使用带有@RooJpaEntity的JPA存储库)

时间:2013-11-11 18:35:19

标签: java spring jpa spring-roo autowired

当我的实体被保存时,我一直在寻找一种从服务中调用某种方法的方法。

我的应用程序是使用roo 1.2.4.RELEASE

创建的

我有一个名为SaldoCliente的平衡实体和一个名为AuxCliente的ClientAction实体。

每次持久保存新的ClientAction实体时,我都需要更新客户端余额。

这是我的代码:

@RooJavaBean
@RooToString
@RooJpaEntity(entityName = "AUX_CLIENTES")
public class AuxCliente {


    @Transient
    @Autowired
    static private SaldoClienteService saldoClienteService;


...


    @PostConstruct
    public void init() 
    {
        System.out.println("Initializing with dependency ["+ saldoClienteService + "]");
    }

    @PostPersist
    private void afectaSaldoCliente(/*Long idTrans, Cliente, Integer cargo, BigDecimal importe, Integer creditos*/) {
      if (saldoClienteService == null) {
          System.out.println("saldoClienteService FUE NULL");
      }
...

我不知道为什么saldoClienteService始终为null。

(注意我不希望在我的数据库中保存saldoClienteService字段,因此@Transient注释

我一直在寻找一个没有成功的解决方案。许多解释都说this之类的内容:You need <context:annotation-config/> (or <context:component-scan/>) to enable @PostConstruct handling.

我的applicationContext.xml(由Roo创建)中有<context:component-scan>

文档说:

  

默认情况下,Spring提供的@ Component,@ Repository,@ Service和@Controller构造型   将被检测到。注意:此标记表示激活“annotation-config”标记的效果   @ Required,@ Autowired,@ PostConstruct,@ PreDestroy,@ Resource,@ PersistenceContext和   组件类中的@PersistenceUnit注释,通常需要自动检测   组件(无外部配置)。

至少@Autowired注释可以在任何地方使用,但在那里。

有人有指点吗?

------------------ EDITED -----------------

首先:我要感谢@Sotirios和@Ralph花时间帮助我。

如果我从字段中删除“静态”,则它是相同的。在我的实体中,注入的字段始终为空。 (请参阅我在这个问题中的评论,我补充说,因为“可能的”解决方案)。

我也遇到了另外一个我需要注射的课程。我将此添加到与之前相同的类(AuxClientes):

@Transient
@Autowired
private ConfigUser configUser;

并且configUser也始终为null。

这是另一堂课的开始,如果重要的话。

@RooJavaBean(settersByDefault=false)
public class ConfigUser {
...

和当然,在applicationContext.xml中:

<bean class="com.i4b.adminctes.util.ConfigUser" id="appConfigUser" />

我在构造函数,服务和存储库中成功使用了configUser。但不能在实体中使用它。

如果您认为我应该发布我的代码的任何其他部分,请告诉我。

---------------编辑2 ------------------

我的所有实体也是如此。

---------------编辑3.a ------------------

我更改了问题标题,以获得更好的标题。在此之前:

  

Spring roo(服务自动装配)实体不调用@PostConstruct。 (将JPA Repository与@RooJpaEntity一起使用)

---------------编辑3.b ------------------

我刚刚创建了一个最小的测试项目。

// Spring Roo 1.2.4.RELEASE [rev 75337cf] log opened at 2013-11-13 11:36:27
project --topLevelPackage org.example --projectName TestAutowiredOnEntities --java 7 --packaging WAR
jpa setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY 
entity jpa --class ~.domain.MyEntity --testAutomatically --activeRecord false
field string --fieldName text 
repository jpa --interface ~.repository.MyEntityRepository --entity ~.domain.MyEntity
service type --interface ~.service.MyEntityService --entity ~.domain.MyEntity
web mvc setup 
web mvc all --package org.example.web

编辑服务:

package org.example.service;

public class MyEntityServiceImpl implements MyEntityService {

    @Override
    public String testAutowire() {
        return "Some data";
    }
}

编辑实体:

package org.example.domain;
import javax.persistence.PrePersist;
import javax.persistence.Transient;

import org.example.service.MyEntityService;
import org.example.service.MyEntityServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.jpa.entity.RooJpaEntity;
import org.springframework.roo.addon.tostring.RooToString;

@RooJavaBean
@RooToString
@RooJpaEntity
public class MyEntity {

    @Transient
    @Autowired
    MyEntityService myEntityService; 

    /**
     */
    private String text;

    @PrePersist
    public void prePersist() {
        if (myEntityService == null) {
            System.out.println("myEntityService IS NULL");
        } else {
            String data=myEntityService.testAutowire();
            System.out.println("it works: " + data);
            this.text = data;
        }
    } 
}

编辑create.jspx以隐藏服务字段。否则它不会让你保存。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<div xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" xmlns:form="urn:jsptagdir:/WEB-INF/tags/form" xmlns:jsp="http://java.sun.com/JSP/Page" xmlns:spring="http://www.springframework.org/tags" version="2.0">
    <jsp:directive.page contentType="text/html;charset=UTF-8"/>
    <jsp:output omit-xml-declaration="yes"/>
    <form:create id="fc_org_example_domain_MyEntity" modelAttribute="myEntity" path="/myentitys" render="${empty dependencies}" z="T0LoTr6PZAwfIQHkjOZMmPW7cO8=">
        <field:input field="myEntityService" id="c_org_example_domain_MyEntity_myEntityService" render="false" z="12sHnsW2dWYyuD+vDtbTve/jWuI="/>
        <field:input field="text" id="c_org_example_domain_MyEntity_text" z="jUCTnP7E3pYPcZcfGn1tyJ2VeFI="/>
    </form:create>
    <form:dependency dependencies="${dependencies}" id="d_org_example_domain_MyEntity" render="${not empty dependencies}" z="Un0bJ/PmWmczxoVTom9NowwIRWk="/>
</div>

然后执行应用程序并创建一个新的“我的实体”。将该字段留空,我预先保存了保存按钮。

日志显示:

INFO: Reloading Context with name [/testAutowiredOnEntities] is completed
nov 13, 2013 2:31:52 PM org.apache.jasper.compiler.TldLocationsCache tldScanJar
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
myEntityService IS NULL

实体有一个空文本字段。

为了确定,我将@Component添加到了“MyEntity”类:

...
@Component
@RooJavaBean
@RooToString
@RooJpaEntity
public class MyEntity {
...

没有任何改变。该服务仍为空。

我真的希望能帮助一些比我更了解的人帮助我找到解决方案。

谢谢大家。

与此同时,我将重新阅读@Ralph指出的文档部分。 我显然做错了什么。我不知道我是唯一需要这个的人。

再次:谢谢大家

2 个答案:

答案 0 :(得分:0)

Spring不会在static字段中注入。

@RooJavaBean
@RooToString
@RooJpaEntity(entityName = "AUX_CLIENTES")
public class AuxCliente {


    @Transient
    @Autowired
    private SaldoClienteService saldoClienteService;

    @PostPersist
    void afectaSaldoCliente() {
       this.saldoClienteService.doWhatYouWant();
    }

}

关于更新#2

看起来ConfigUser是一个Hibernate / JPA / Whatever Entity但不是Spring Bean。但是你只能注入Spring Beans(比如Services,Dao,......)(每件事都有@Component@Controller@Service@Repository注释*。))

你只能注入带有@Configurable注释的Spring Beans或Classes(需要AspectJ)See Spring Reference Chapter 7.8.1 Using AspectJ to dependency inject domain objects with Spring

使用@Configurable是Spring-Roo的方式(实体旁边必须有一个文件AuxCliente_Roo_Configurable.aj(在Eclipse中需要禁用“隐藏生成Spring Roo ITD” - 过滤器才能显示包资源管理器中的这个文件))。


*还有一些方法可以让对象成为一个弹簧bean,但这并不重要

答案 1 :(得分:0)

终于搞定了。

正如我在上次对@Ralph的评论中提到的那样:添加@Configurable注释就可以了。

如果该类如下所示,则自动装配有效:

@Configurable                <--- added this
@RooPlural("Tarjetas")
@RooJavaBean
@RooToString
@RooJpaEntity
@Table(name = "TARJETAS")
public class Tarjeta {

    @Autowired
    @Transient
    private ConfigUser configUser;

...

但是最后我决定使用一个帮助器类,以避免所有Spring roo为这个属性生成代码。我不想为configUser添加私有getter,以防止Spring Roo的公共存在,并在所有脚手架视图中标记'render =“false”。

现在我有:

@Configurable
@RooJavaBean
public class Helper {

    @Autowired
    private ConfigUser configUser;

    @Autowired
    private SaldoClienteService saldoClienteService;
}

当我需要自动装配的bean时,我使用这样的东西:

ConfigUser configUser = new Helper().getConfigUser();

再次:非常感谢@Ralph