在春天和不寻常的体系结构中静态访问实体经理 [英] static access to entity manager in spring and unusual architecture

查看:116
本文介绍了在春天和不寻常的体系结构中静态访问实体经理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

quick question:

我有web应用程序(wicket + spring + jpa),并且正在考虑相当不寻常的架构设计。

考虑class wrapper:

  @Service 
public class Wrapper {
protected static EntityManager entityManager;

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

正如你所看到的那样,我现在将EntityManager静态注入。



现在考虑简单实体DogEntity

  @Entity 
public class DogEntity {
字符串名称;

$ / code>

对于那个实体,我们创建了包装狗狗狗狗

  public class Dog扩展包装器{
private DogEntity entity;

私人狗(DogEntity实体){
this.entity = entity;


public static Dog create(String name){
entity = new DogEntity();
entity.name = name;
entityManager.persist(entity); //暂时忘记这段代码不在事务中
return new Dog(entity);






$ b现在在我的web应用程序中(在我的控制器中),我可以做这样的事情:

  saveButton = new Button(save){

public void onSubmit (){
Dog dog = Dog.create(name);
//其他代码
}

从代码的角度来看,完善。我们有代表业务对象的包装器。它们都具有持久性状态,应用程序中没有任何称为DogSaver的愚蠢服务,只有在实体管理器上才会调用的方法保存(DogEntity)。代码真的有很多可读性,还有其他一些优点,但我不会去详细讨论。



我真正关心的是这个静态EntityManager。我没有足够的关于Spring内部知识来了解这种方法是否合适和安全。有什么情况下事情变得丑陋?
我知道EntityManare是无状态的(根据JPA规范),它总是从事务中获取持久化上下文,因此使其成为静态并不是一个坏主意。但是我担心我可能会搞点什么。



有什么想法?

解决方案

你应该看看Spring Roo。他们有一些类似的东西(没有DAO或服务),但是EntityManager不是静态的。



他们用 @Configurable

  @entiy 
@Configurable
class MyEntity(){code>>实体中的注释
b
$ b @PersistenceContext
瞬间EntityManager Car.entityManager;



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


public static EntityManager entityManager(){
EntityManager em = new MyEntity()。entityManager;
if(em == null)抛出新的IllegalStateException(实体管理器没有被注入(是否将Spring Aspects JAR配置为AJC / AJDT方面库?));
返回em;


$ / code>

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





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

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






制作无Roo项目aviable为 @Configurable 您至少需要这样做:



扩展pom.xml:

 <属性> 
< 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>
< groupId> org.aspectj< / groupId>
< artifactId> aspectjweaver< / artifactId>
< version> $ {aspectj.version}< / version>
< /依赖关系>
< dependency>
< groupId> org.springframework< / groupId>
< artifactId> spring-aop< / artifactId>
< version> $ {spring.version}< / version>
< /依赖关系>
< dependency>
< groupId> org.springframework< / groupId>
< artifactId> spring-aspects< / artifactId>
< version> $ {spring.version}< / version>
< /依赖关系>

...

 < plugin> 
< groupId> org.codehaus.mojo< / groupId>
< artifactId> aspectj-maven-plugin< / artifactId>
< version> $ {aspectj-maven-plugin.version}< / version>
<! - NB:由于MASPECTJ-90,请使用1.3或1.3.x - 等待1.4 - >
<依赖关系>
< dependency>
< groupId> org.aspectj< / groupId>
< artifactId> aspectjrt< / artifactId>
< version> $ {aspectj.version}< / version>
< /依赖关系>
< dependency>
< groupId> org.aspectj< / groupId>
< artifactId> aspectjtools< / artifactId>
< version> $ {aspectj.version}< / version>
< /依赖关系>
<! -
<依赖>
< groupId> org.springframework.security< / groupId>
< artifactId> spring-security-aspects< / artifactId>
< version> 3.0.5.RELEASE< / version>
< /依赖关系>
- >
< /依赖关系>
<执行次数>
<执行>
<目标>
< goal>编译< / goal>
< goal> test-compile< / goal>
< /目标>
< /执行>
< /执行次数>
<配置>
< 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>
<编码> utf-8< /编码>
< / configuration>
< / plugin>

Spring配置:

 <! - 打开AspectJ @Configurable支持。因此,任何时候你实例化一个对象时,
Spring都会尝试对该对象执行依赖注入。
这发生在通过new关键字实例化,以及通过反射。
这是可能的,因为AspectJ用于在编译时编织基于Roo的应用程序。
实际上,这个特性允许依赖注入系统中的任何对象,
这是一个非常有用的特性(没有@Configurable,你只能够从
获得依赖注入对象Spring或随后呈现给
a特定的Spring依赖注入方法)。 - >
< context:spring-configured />

< tx:注解驱动模式=aspectjtransaction-manager =transactionManager/>

<! - -
Spring Security:
需要Spring Security XSD的3.0.4版本:spring-security-3.0.4.xsd
- >


quick question:

I have webapplication (wicket+spring+jpa) and was thinking about rather unusual architecture design. Please check it out and give your comments.

Consider class Wrapper:

@Service
public class Wrapper {
    protected static EntityManager entityManager;

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

as you see I have now EntityManager injected statically.

Now consider simple entity DogEntity

@Entity
public class DogEntity {
   String name;
}

And for that entity we create wrapper 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);
  }
}

Now in my webapplication (in my controller) I can do something like this:

saveButton = new Button("save") {

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

From code point of view this architecture looks perfect. We have wrappers representing business objects. They all have persistent state, there are no stupid services in application called DogSaver with method save(DogEntity) which only call persist on entity manager. Code really gets a lot of readability and there some other advantages, but I dont wont go into details.

What really is my concern is this static EntityManager. I do not have enough knowledge about internals of Spring to know whether this approach is proper and safe. Are there situations where things mihgt get ugly? I know that EntityManare is stateless (according to JPA spec), it always takes persistence context from transaction, thus making it static does not seem a bad idea. But I fear that I might be messing something.

Any thoughts?

解决方案

You should have a look at Spring Roo. They have something simular (no DAOs or Services), but there EntityManager is not static.

They do the trick with the @Configurable annotation in Entities:

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

Anyway it has two or three drawbacks:

But it has also some nice effects: for example the persist and delete methods become very natural, they are just member of the entity:

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


To make a none Roo project aviable for @Configurable you need to at LEAST doing this:

extend the 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 config:

<!-- 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"> 
  -->

这篇关于在春天和不寻常的体系结构中静态访问实体经理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆