【发布时间】:2011-06-18 20:37:51
【问题描述】:
对于富域驱动设计,我想在 JPA/Hibernate 实体 bean 上使用 Guice 依赖注入。我正在寻找与非 Spring bean 的 Spring @configurable 注释类似的解决方案。
有人知道图书馆吗?有代码示例吗?
【问题讨论】:
标签: hibernate jpa domain-driven-design aop guice
对于富域驱动设计,我想在 JPA/Hibernate 实体 bean 上使用 Guice 依赖注入。我正在寻找与非 Spring bean 的 Spring @configurable 注释类似的解决方案。
有人知道图书馆吗?有代码示例吗?
【问题讨论】:
标签: hibernate jpa domain-driven-design aop guice
您可以使用 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>
使用 aspectjweaver 启动您的 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() {}
}
【讨论】:
我为这个问题找到了一个有点肮脏的解决方法。
假设只有两种方法可以创建T类型的实体对象:
javax.inject.Provider<T> 获取一个
@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<MyDomainEntity>。这可以通过隐藏构造函数来提供。
亲切的问候,
avi
【讨论】:
由于实体是由 JPA 提供者创建的,我看不到 Guice 什么时候会发挥作用。不妨看看Salve 项目的方法。
【讨论】: