2010-07-17 35 views
7

Đối với thiết kế định hướng tên miền phong phú, tôi muốn sử dụng Chèn phụ thuộc vào guice trên các hạt thực thể JPA/Hibernate. Tôi đang tìm một giải pháp tương tự như chú thích Spring @configurable cho các bean không phải Spring.Tiêm phụ thuộc vào guice cho đậu thực thể?

Có ai biết thư viện không? Bất kỳ ví dụ mã nào?

Trả lời

5

Bạn có thể thực hiện việc này với AspectJ.

Tạo chú thích @Configurable:

@Retention(RetentionPolicy.RUNTIME) 
@Target({ElementType.TYPE}) 
public @interface Configurable { 
} 

Tạo một AspectJ @Aspect tương tự như sau:

@Aspect 
public class ConfigurableInjectionAspect { 
    private Logger log = Logger.getLogger(getClass().getName()); 

    @Pointcut("@within(Configurable) && execution(*.new(..)) && target(instantiated)") 
    public void classToBeInjectedOnInstantiation(Object instantiated) {} 

    @After(value = "classToBeInjectedOnInstantiation(instantiated)", 
      argNames = "instantiated") 
    public void onInstantiation(Object instantiated) { 
     Injector injector = InjectorHolder.getInjector(); 
     if (injector == null) { 
      log.log(Level.WARNING, "Injector not available at this time"); 
     } else { 
      injector.injectMembers(instantiated); 
     } 
    } 
} 

Tạo (và sử dụng) một lớp giữ cho vòi phun của bạn:

public final class InjectorHolder { 

    private static Injector injector; 

    static void setInjector(Injector injector) { 
     InjectorHolder.injector = injector; 
    } 

    public static Injector getInjector() { 
     return injector; 
    } 
} 

Định cấu hình META-INF/aop.xml:

<aspectj> 
    <weaver options="-verbose"> 
     <include within="baz.domain..*"/> 
     <include within="foo.bar.*"/> 
    </weaver> 
    <aspects> 
     <aspect name="foo.bar.ConfigurableInjectionAspect"/> 
    </aspects> 
</aspectj> 

Bắt đầu VM của bạn với aspectjweaver:

-javaagent:lib/aspectjweaver.jar 

Chú thích các lớp miền của bạn:

@Entity 
@Table(name = "Users") 
@Configurable 
public class User { 
    private String username; 
    private String nickname; 
    private String emailAddress; 
    @Inject 
    private transient UserRepository userRepository 

    public User() {} 
} 
1

Vì các thực thể được tạo bởi nhà cung cấp JPA, tôi không thấy khi nào Guice sẽ đến chơi. Có lẽ có một cái nhìn tại cách tiếp cận của dự án Salve mặc dù.

+0

Cảm ơn, một giải pháp codeweaving như Salve thực sự có thể làm các trick. Tôi đã thử Salve, nhưng nó có tài liệu giới hạn và tôi không thể làm cho nó làm bất cứ điều gì (thậm chí không phải là một thông báo lỗi). Chỉ cần hy vọng cho một số mã mẫu đơn giản, ví dụ với AspectJ hoặc AOP tốt hơn. – Kdeveloper

+0

@Kdeveloper: Tôi không có kinh nghiệm với Salve nên tôi không thể giới thiệu nó nhưng nó có thể cung cấp cho bạn một số ý tưởng để thực hiện một cái gì đó tương tự đó là lý do tại sao tôi đề cập đến nó –

3

Tôi tìm thấy một workaround bẩn chút cho vấn đề này.

Giả sử chỉ có hai cách để tạo ra một đối tượng thực thể của kiểu T:

  • Lấy một từ một javax.inject.Provider<T>
  • quering nó từ người quản lý thực thể (mà sẽ gọi @PostLoad phương pháp chú thích).

Giả sử bạn có cơ sở hạ tầng cơ sở hạ tầng cho tất cả các thực thể của mình, bạn chỉ có thể thêm người nghe thực thể vào thực thể này. Trong ví dụ này tôi sử dụng tiêm tĩnh - có thể có một cách đẹp hơn.

@MappedSuperclass 
public abstract class PersistentDomainObject<K extends Serializable & Comparable<K>> 
    implements Comparable<PersistentDomainObject<K>>, Serializable { 

    private static transient Injector injector; 

    @PostLoad 
    private final void onAfterLoaded() { 
     injector.injectMembers(this); 
    } 

    @EmbeddedId 
    private K id; 

    public K getId() { return id; } 

    // ... compareTo(), equals(), hashCode(), maybe a @Version member ... 
} 

Trong thiết lập mô-đun của bạn, bạn chỉ cần gọi requestStaticInjection(PersistentDomainObject.class);

Bây giờ bạn chỉ có thể tạo các lớp thực thể như

@Entity 
public class MyDomainEntity extends PersistentDomainObject<SomeEmbeddableIdType> 
    implements HatLegacyId { 

    @Inject 
    private transient MyDomainService myDomainService; 

    private String name; 
    // ... common stuff 
} 

điều Bad về nó, bạn phải tin tưởng vào không ai đó sẽ tạo a MyDomainEntity riêng của mình nhưng sẽ yêu cầu Provider<MyDomainEntity> cho nó. Điều này có thể được cung cấp bằng cách ẩn hàm tạo.

Trân trọng!

avi

+0

Mặc dù tiêm tĩnh bằng cách nào đó nản lòng, thêm một phụ thuộc như AspectJ tại thời điểm này không phải là giá cả phải chăng cho dự án của tôi. Hơn nữa, giải pháp phù hợp với vấn đề của tôi và khá sạch sẽ. – Iacopo

Các vấn đề liên quan