복붙노트

[SPRING] 스프링과 비정상적인 아키텍처의 엔티티 관리자에 대한 정적 액세스

SPRING

스프링과 비정상적인 아키텍처의 엔티티 관리자에 대한 정적 액세스

빠른 질문:

나는 webapplication (wicket + spring + jpa)을 가지고 있으며 다소 특이한 아키텍처 디자인을 생각하고 있었다. 그것을 확인하고 의견을 말하십시오.

Wrapper 클래스를 고려하십시오.

@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);
  }
}

이제 내 웹 응용 프로그램 (내 컨트롤러에서)에서 다음과 같이 할 수 있습니다.

saveButton = new Button("save") {

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

코드 관점에서이 아키텍처는 완벽 해 보입니다. 우리에게는 비즈니스 객체를 나타내는 래퍼가 있습니다. 그들은 모두 영구 상태를 가지고 있으며, 엔티티 관리자에서만 계속 호출하는 save (DogEntity) 메서드를 사용하는 DogSaver라는 응용 프로그램에는 바보 같은 서비스가 없습니다. 코드는 실제로 많은 가독성과 몇 가지 다른 장점을 갖지만, 세부 사항은 다루지 않을 것입니다.

실제로이 정적 EntityManager에 대한 우려가 있습니다. 이 접근법이 적절하고 안전한지를 알기 위해 Spring의 내부에 대한 충분한 지식이 없습니다. mihgt가 추악 해지는 상황이 있습니까? 나는 EntityManare가 (JPA 스펙에 따라) 무국적이라는 것을 알고 있으며, 트랜잭션에서 영속 컨텍스트를 항상 가져 와서 정적으로 만드는 것이 좋지 않은 것처럼 보입니다. 그러나 나는 내가 뭔가를 망칠 까봐 두렵습니다.

이견있는 사람?

해결법

  1. ==============================

    1.Spring Roo를 봐야합니다. 그것들은 simular (DAOs 나 Services가 없다)가 있지만 EntityManager는 정적이 아닙니다.

    Spring Roo를 봐야합니다. 그것들은 simular (DAOs 나 Services가 없다)가 있지만 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);
    }
    

    @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>
    

    봄 설정 :

    <!-- 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"> 
      -->
    
  2. ==============================

    2.EntityManager는 stateful이다. 공장은 무국적자입니다. 정적 엔티티 관리자를 갖는 것은 "애플리케이션 당 세션"(또는 애플리케이션 당 엔티티 관리자)이라고하는 안티 패턴입니다.

    EntityManager는 stateful이다. 공장은 무국적자입니다. 정적 엔티티 관리자를 갖는 것은 "애플리케이션 당 세션"(또는 애플리케이션 당 엔티티 관리자)이라고하는 안티 패턴입니다.

    구현 세부 사항 - @PersistenceContext EntityManager가 어떻게 처리되는지. Hibernate는 새로운 Hibernate 세션이 아직 생성되지 않았다면 그것을 생성하는 EntityManagerImpl을 제공한다. 그러나 이미 생성 된 경우에는 참조 (세션 = 지속성 컨텍스트)가 유지됩니다.

    정적 엔티티 관리자가 있다는 것은 컨테이너가 관리하지 않는다는 것을 의미합니다. 이는 다시 말해서 당신이 영속 컨텍스트를 관리 할 책임이 있음을 의미합니다.

    당신이하려는 것은 도메인 주도 디자인입니다. 다음은 DDD와 JPA에 관한 기사입니다.

    내 개인적인 취향은 그렇게하지 않아야합니다. 개체가 데이터베이스에서 지속될 수 없어야합니다. 이것이 바로 인프라 논리입니다. 코드 중복을 피하기 위해 persist 메소드를 래핑하는 BaseDao 만 있으면됩니다. 또는 서비스 계층에서 EntityManager를 직접 사용할 수도 있습니다. (이는 사용자가 명확한 레이어 경계를 가지고 있다고 가정합니다)

    DDD 경로로 가고 싶다면 기사의 예제를 살펴보십시오. Spring을 사용하면 aspectJ를 통해 임의의 객체에 엔티티 관리자를 삽입 할 수있다. 따라서 귀하의 엔티티 관리자는 트랜잭션뿐만 아니라 적절하게 처리됩니다.

  3. from https://stackoverflow.com/questions/7007205/static-access-to-entity-manager-in-spring-and-unusual-architecture by cc-by-sa and MIT license