一尘不染

在spring和不寻常的架构中静态访问实体管理器

hibernate

快速提问:

我有web应用程序(wicket +spring+jpa),并且正在考虑相当不寻常的体系结构设计。请检查出来并发表您的评论。

考虑类包装器:

@Service
public class Wrapper {
    protected static EntityManager entityManager;

    @PersistenceContext
    private void injectEntityManager(EntityManager entityManager) {
        Wrapper.entityManager = entityManager;
    }

如您所见,我现在已经静态注入了EntityManager。

现在考虑简单的实体DogEntity

@Entity
public class DogEntity {
   String name;
}

然后为该实体创建包装器Dog

public class Dog extends Wrapper {
  private DogEntity entity;

  private Dog(DogEntity entity) {
     this.entity = entity;
  }

  public static Dog create(String name) {
    entity = new DogEntity();
    entity.name = name;
    entityManager.persist(entity); // for a moment forget that this code is not in transaction
    return new Dog(entity);
  }
}

现在,在我的Web应用程序中(在我的控制器中),我可以执行以下操作:

saveButton = new Button("save") {

public void onSubmit() {
   Dog dog = Dog.create(name);
   // other code 
}

从代码的角度来看,该架构看起来很完美。我们有代表业务对象的包装器。它们都具有持久状态,在名为DogSaver的应用程序中没有使用方法save(DogEntity)的愚蠢服务,该方法仅在实体管理器上调用持久化。代码确实具有很多可读性,还有其他一些优点,但是我不会详细介绍。

我真正关心的是这个静态EntityManager。我对Spring内部没有足够的知识,无法知道这种方法是否正确和安全。在某些情况下事情会变得丑陋吗?我知道EntityManare是无状态的(根据JPA规范),它始终从事务中获取持久性上下文,因此使其成为静态似乎不是一个坏主意。但是我担心我可能会弄乱一些东西。

有什么想法吗?


阅读 278

收藏
2020-06-20

共1个答案

一尘不染

您应该看看Spring Roo。它们具有类似的东西(没有DAO或服务),但是EntityManager并不是静态的。

他们通过@Configurable在实体中添加注释来达到目的:

@Entiy
@Configurable
class MyEntity() {

  @PersistenceContext
  transient EntityManager Car.entityManager;

  ...

  public static MyEntity findMyEntityById(Long id) {
    if (id == null) return null;
    return entityManager().find(MyEntity.class, id);
  }

  public static EntityManager entityManager() {
    EntityManager em = new MyEntity().entityManager;
    if (em == null) throw new IllegalStateException("Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
    return em;
  }    
}

无论如何,它有两个或三个缺点:

但这也有一些不错的效果:例如persist和delete方法变得非常自然,它们只是实体的成员:

@Transactional
public void persist() {
    if (this.entityManager == null) this.entityManager = entityManager();
    this.entityManager.persist(this);
}

为了使none Roo项目可行,@Configurable您需要至少这样做:

扩展pom.xml:

<properties>
    <spring.version>3.0.5.RELEASE</spring.version>
    <aspectj.version>1.6.11</aspectj.version>
    <aspectj-maven-plugin.version>1.2</aspectj-maven-plugin.version>
    <maven-compiler-plugin.version>2.3.2</maven-compiler-plugin.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

    ...

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aop</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring.version}</version>
    </dependency>

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>${aspectj-maven-plugin.version}</version>
            <!-- NB: do use 1.3 or 1.3.x due to MASPECTJ-90 - wait for 1.4 -->
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjrt</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjtools</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
    <!--
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-aspects</artifactId>
        <version>3.0.5.RELEASE</version>
    </dependency>
    -->
            </dependencies>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                        <goal>test-compile</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <outxml>true</outxml>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                    </aspectLibrary>
                    <!--
                    <aspectLibrary>
                        <groupId>org.springframework.security</groupId>
                        <artifactId>spring-security-aspects</artifactId>
                    </aspectLibrary>
                    -->
                </aspectLibraries>
                <source>1.6</source>
                <target>1.6</target>
                <encoding>utf-8</encoding>
            </configuration>
        </plugin>

spring配置:

<!-- Turn on AspectJ @Configurable support. As a result, any time you instantiate an object,
Spring will attempt to perform dependency injection on that object.
This occurs for instantiation via the "new" keyword, as well as via reflection.
This is possible because AspectJ is used to "weave" Roo-based applications at compile time.
 In effect this feature allows dependency injection of any object at all in your system,
 which is a very useful feature (without @Configurable you'd only be able to
 dependency inject objects acquired from Spring or subsequently presented to
 a specific Spring dependency injection method). -->
 <context:spring-configured />

 <tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />

  <!--
  Spring Security:
  requires version 3.0.4 of Spring Security XSD: spring-security-3.0.4.xsd
  <global-method-security ... mode="aspectj"> 
  -->
2020-06-20