Guice внедрение зависимостей для бинов сущностей - PullRequest
7 голосов
/ 18 июля 2010

Для расширенного доменного дизайна я хочу использовать Инъекцию зависимостей Guice в компоненты сущности JPA / Hibernate .Я ищу решение, похожее на аннотацию Spring @configurable для не-Spring компонентов.

Кто-нибудь знает библиотеку?Какие-нибудь примеры кода?

Ответы [ 3 ]

5 голосов
/ 28 июля 2010

Вы можете сделать это с AspectJ.

Создание аннотации @Configurable:

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

Создайте AspectJ @Apect, похожий на этот:

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

-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() {}
}
3 голосов
/ 18 июня 2011

Я нашел немного грязный обходной путь для этой проблемы.

Предполагается, что есть только два способа создания объекта сущности типа 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

1 голос
/ 18 июля 2010

Поскольку сущности создаются провайдером JPA, я не вижу, когда Guice вступит в игру. Возможно, взгляните на подход проекта Salve .

...