当前位置: 首页 > 面试题库 >

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

柯瀚海
2023-03-14
问题内容

快速提问:

我有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规范),它始终从事务中获取持久性上下文,因此使其成为静态似乎不是一个坏主意。但是我担心我可能会弄乱一些东西。

有什么想法吗?


问题答案:

您应该看看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;
  }    
}

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

  • 您需要AspectJ
  • 这条线EntityManager em = new MyEntity().entityManager;很丑
  • 如果要模拟持久性“层”,则测试将变得有些困难。但是幸运的是,Spring提供了一个特殊的AOP拦截器(@见org.springframework.mock.staticmock.AnnotationDrivenStaticEntityMockingControl的JavaDoc)

但这也有一些不错的效果:例如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"> 
  -->


 类似资料:
  • 否则,我将需要把我的大查询放在一个注释中。我更希望有更清楚的东西,而不是一个长的文本。

  • 问题内容: 我是Django(1.4)的新手,我很难理解静态文件,媒体文件和管理文件的原理。该项目的结构从一个教程到另一个教程都是不同的,对于Webfaction(我将在其中托管应用程序)也是如此。我想知道什么是组织它的最佳方式,并且在将它部署到Webfaction时花费最少的精力和编辑,静态媒体和管理文件的意义是什么?先感谢你 问题答案: 本质上,你想在开发中使用django提供静态文件。准备好

  • 我正在为Spring Data JPA存储库编写一个自定义实现。所以我有: = 我的问题是:在的实现中,我需要访问注入SpringData的实体管理器。如何得到它?我可以使用自动连接,但问题是这个存储库必须在设置多个持久性单元的应用程序中工作。因此,要告诉Spring我需要哪一个,我必须使用。然而,由于我的存储库是在可重用服务层中定义的,因此我不知道高级应用程序层将配置注入我的存储库中的持久化单元

  • 我正在使用Spring的事务支持和JPA(Hibernate)来持久化我的实体。一切正常,但我在处理一个请求中的部分更新时陷入困境: 对于每个用户(HTTP)请求,我必须将一个日志条目写入数据库表,即使“主”业务实体的更新失败(例如,由于验证错误)。因此,我的第一个/主要事务get被回滚,但第二个(写日志)应该提交。这似乎可以使用正确的传播级别来写入日志条目: 然而,我的问题是,我在第二个事务中注

  • 我有以下设计,我想在Kotlin中实现: null 有没有更好的,更Kotlin的方法?

  • 问题内容: 我需要一种使用实体框架LINQ区分SQL异常的方法,例如,当我从DbUpdateException获得的所有信息都是大量嵌套的内部异常和无用的长错误消息时,如何区分前面的关键约束违例或唯一约束违例?是否有任何较低级别的例外,我可以在其中执行“ Catch FKException”之类的操作;捕获“ uniqueException”或类似的东西。 问题答案: 正在使用sql错误代码…