实体 bean 的 Guice 依赖注入?

发布于 2024-09-10 04:57:33 字数 154 浏览 6 评论 0原文

对于丰富的域驱动设计,我想在 JPA/Hibernate 实体 bean 上使用 Guice 依赖注入。我正在寻找与非 Spring bean 的 Spring @configurable 注释类似的解决方案。

有人知道图书馆吗?有代码示例吗?

For a rich domain driven design I want to use Guice dependency injection on JPA/Hibernate entity beans. I am looking for a similar solution as the Spring @configurable annotation for non-Spring beans.

Does anybody know of a library? Any code examples?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

红焚 2024-09-17 04:57:33

您可以使用 AspectJ 来完成此操作。

创建 @Configurable 注释:

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

创建一个与此类似的 AspectJ @Aspect:

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

为您的注入器创建(并使用)一个持有类:

public final class InjectorHolder {

    private static Injector injector;

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

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

配置 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>

使用方面jweaver 启动您的 VM:

-javaagent:lib/aspectjweaver.jar

注释您的域类:

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

    public User() {}
}

You can do this with AspectJ.

Create the @Configurable annotation:

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

Create an AspectJ @Aspect similar to this:

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

Create (and use) a holding class for your injector:

public final class InjectorHolder {

    private static Injector injector;

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

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

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

Start your VM with aspectjweaver:

-javaagent:lib/aspectjweaver.jar

Annotate your domain classes:

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

    public User() {}
}
小耗子 2024-09-17 04:57:33

我为这个问题找到了一个有点肮脏的解决方法。

假设只有两种方法来创建 T 类型的实体对象:

  • javax.inject.Provider 获取一个
  • 从实体管理器查询它(这将调用 @PostLoad 带注释的方法)。

进一步假设您有所有实体的基础结构基类,您只需向该实体添加一个实体侦听器即可。在这个例子中,我使用静态注入——也许有更好的方法。

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

在您的模块设置中,您只需要调用 requestStaticInjection(PersistentDomainObject.class);

现在您只需创建实体类,例如

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

    @Inject
    private transient MyDomainService myDomainService;

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

坏事,您必须相信没有人会创建 MyDomainEntity 自己处理,但会向 Provider 请求。这可以通过隐藏构造函数来提供。

亲切的问候,

阿维

I found a bit dirty workaround for this problem.

Assuming there are only two ways to create an entity object of type T:

  • Obtaining one from a javax.inject.Provider<T>
  • Quering it from the entity manager (which will call @PostLoad annotated methods).

Further assuming you have a infrastructural baseclass for all of your entities, you can just add an entity listener to this entity. In this example I use static injection - maybe there is a nicer way.

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

In your module setup you just need to call requestStaticInjection(PersistentDomainObject.class);

Now you simply can create entity classes like

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

    @Inject
    private transient MyDomainService myDomainService;

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

Bad thing about it, you have to trust in that noone will create a MyDomainEntity on his own but will ask a Provider<MyDomainEntity>for it. This could be provided by hiding the constructor.

Kind regards,

avi

苍暮颜 2024-09-17 04:57:33

由于实体是由 JPA 提供者创建的,因此我看不到 Guice 何时发挥作用。也许可以看看 Salve 项目的方法。

Since entities are created by the JPA provider, I fail to see when Guice will come in play. Maybe have a look at the approach of the Salve project though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文