Guice 实例化对象后调用 init 方法

发布于 2024-08-18 12:48:17 字数 105 浏览 6 评论 0原文

是否可以告诉 Guice 在之后调用某个方法(即 init()) 实例化给定类型的对象?

我在 EJB 3(和 Spring)中寻找类似于 @PostConstruct 注释的功能。

Is it possible to tell Guice to call some method (i.e. init()) after
instantinating an object of given type?

I look for functionality similar to @PostConstruct annotation in EJB 3 (and Spring).

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

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

发布评论

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

评论(8

蹲墙角沉默 2024-08-25 12:48:17

您只需将 @Inject 注释添加到 init() 方法中即可。实例化对象后它将自动运行。

You can just add the @Inject annotation to your init() method. It will get run automatically after the object is instantiated.

梨涡 2024-08-25 12:48:17

事实上,这是可能的。

您需要定义一个 TypeListener 才能运行该功能。模块定义中的内容大致如下:

bindListener(Matchers.subclassesOf(MyInitClass.class), new TypeListener() {
    @Override
    public <I> void hear(final TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
        typeEncounter.register(new InjectionListener<I>() {
            @Override
            public void afterInjection(Object i) {
                MyInitClass m = (MyInitClass) i;
                m.init();
            }
        });
    }
});

Actually, it is possible.

You need to define a TypeListener to get the functionality going. Something along the lines of the following in your module definition:

bindListener(Matchers.subclassesOf(MyInitClass.class), new TypeListener() {
    @Override
    public <I> void hear(final TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
        typeEncounter.register(new InjectionListener<I>() {
            @Override
            public void afterInjection(Object i) {
                MyInitClass m = (MyInitClass) i;
                m.init();
            }
        });
    }
});
风透绣罗衣 2024-08-25 12:48:17

guiceyfruit 执行您对使用 @PostConstruct 注释的方法的操作或实现 spring 的 InitializingBean。也可以编写自己的侦听器来执行此操作。下面是一个在创建对象后调用公共 init() 方法的示例。

import com.google.inject.*;
import com.google.inject.matcher.*;
import com.google.inject.spi.*;

public class MyModule extends AbstractModule {
  static class HasInitMethod extends AbstractMatcher<TypeLiteral<?>> {
    public boolean matches(TypeLiteral<?> tpe) {
      try {
        return tpe.getRawType().getMethod("init") != null;
      } catch (Exception e) {
        return false;
      }
    }

    public static final HasInitMethod INSTANCE = new HasInitMethod();
  }

  static class InitInvoker implements InjectionListener {
    public void afterInjection(Object injectee) {
      try {
        injectee.getClass().getMethod("init").invoke(injectee);
      } catch (Exception e) {
        /* do something to handle errors here */
      }
    }
    public static final InitInvoker INSTANCE = new InitInvoker();
  }

  public void configure() {
    bindListener(HasInitMethod.INSTANCE, new TypeListener() {
      public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
        encounter.register(InitInvoker.INSTANCE);
      }
    });
  }
}

guiceyfruit does what you're after for methods annotated with @PostConstruct or implementing spring's InitializingBean. It's also possible to write your own listeners to do this. Here's an example that calls a public init() method after objects are created.

import com.google.inject.*;
import com.google.inject.matcher.*;
import com.google.inject.spi.*;

public class MyModule extends AbstractModule {
  static class HasInitMethod extends AbstractMatcher<TypeLiteral<?>> {
    public boolean matches(TypeLiteral<?> tpe) {
      try {
        return tpe.getRawType().getMethod("init") != null;
      } catch (Exception e) {
        return false;
      }
    }

    public static final HasInitMethod INSTANCE = new HasInitMethod();
  }

  static class InitInvoker implements InjectionListener {
    public void afterInjection(Object injectee) {
      try {
        injectee.getClass().getMethod("init").invoke(injectee);
      } catch (Exception e) {
        /* do something to handle errors here */
      }
    }
    public static final InitInvoker INSTANCE = new InitInvoker();
  }

  public void configure() {
    bindListener(HasInitMethod.INSTANCE, new TypeListener() {
      public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
        encounter.register(InitInvoker.INSTANCE);
      }
    });
  }
}
番薯 2024-08-25 12:48:17

如果您想在实例构造之后调用方法,则意味着构造后方法调用实际上是实例创建的一个步骤。在这种情况下,我会推荐抽象工厂设计模式来解决这个问题。
代码可能看起来像这样:


class A {
    public A(Dependency1 d1, Dependency2 d2) {...}

    public postConstruct(RuntimeDependency dr) {...}
}

interface AFactory {
    A getInstance(RuntimeDependency dr);
}

class AFactoryImpl implements AFactory {
    @Inject
    public AFactoryImpl(Dependency1 d1, Dependency2 d2) {...}

    A getInstance(RuntimeDependency dr) {
        A a = new A(d1, d2);
        a. postConstruct(dr);
        return a;
    }
}

// in guice module
bind(AFactory.class).to(AFactoryImpl.class)

If you'd like to call a method after the construction of an instance, it means the post-construct method call is actually a step of the instance creation. In this case, I would recommend abstract factory design pattern to solve this problem.
The code may look like something like this:


class A {
    public A(Dependency1 d1, Dependency2 d2) {...}

    public postConstruct(RuntimeDependency dr) {...}
}

interface AFactory {
    A getInstance(RuntimeDependency dr);
}

class AFactoryImpl implements AFactory {
    @Inject
    public AFactoryImpl(Dependency1 d1, Dependency2 d2) {...}

    A getInstance(RuntimeDependency dr) {
        A a = new A(d1, d2);
        a. postConstruct(dr);
        return a;
    }
}

// in guice module
bind(AFactory.class).to(AFactoryImpl.class)
楠木可依 2024-08-25 12:48:17

GWizard 包含一个模块 (gwizard-services),它以 Guice 友好的格式提供 Guava 服务。 Guava 服务为您提供并行线程中的生命周期管理。

https://github.com/stickfigure/gwizard

GWizard includes a module (gwizard-services) which provides Guava services in a Guice-friendly format. Guava services give you lifecycle management in parallel threads.

https://github.com/stickfigure/gwizard

望喜 2024-08-25 12:48:17

如果您需要使用其他对象初始化一个对象,并且在两个对象都准备好之后(如果您需要向另一个对象注册一个对象并且它们也相互依赖,就是这种情况),您可以轻松地这样做:

public final class ApplicationModule extends AbstractModule {

  @Override
  protected void configure() {
    requestStaticInjection(ApplicationModule.class);
  }

  @Inject
  static void injectApplication(
      ReslSession reslSession,
      Set<Saga> sagas,
      Set<Reaction> reactions
  ) {
    sagas.forEach(reslSession::registerSaga);
    reactions.forEach(reslSession::registerReaction);
  }

}

In case you need to initialize an object using other objects and after both are ready (which is the case if you need to register one with the other and they also depend on each other) you can easily do it like this:

public final class ApplicationModule extends AbstractModule {

  @Override
  protected void configure() {
    requestStaticInjection(ApplicationModule.class);
  }

  @Inject
  static void injectApplication(
      ReslSession reslSession,
      Set<Saga> sagas,
      Set<Reaction> reactions
  ) {
    sagas.forEach(reslSession::registerSaga);
    reactions.forEach(reslSession::registerReaction);
  }

}
找个人就嫁了吧 2024-08-25 12:48:17

根据 Geoff 的回答,您可以“使可调用”@PostConstruct 方法:

public class GuiceExample {
    @Inject
    private IDataManager dataManager;

    public GuiceExample() {
        System.out.println("Constructor");
    }

    @PostConstruct
    private void init() {
        dataManager.printData();
    }

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new AbstractModule() {

            @Override
            protected void configure() {
                bind(IDataManager.class).to(DataManager.class);
                bindListener(HasPostConstructAnnotationMatcher.INSTANCE, new TypeListener() {

                    @Override
                    public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
                        encounter.register(PostConstructAnnotationInvoker.INSTANCE);
                    }
                });
            }
        });

        GuiceExample example = injector.getInstance(GuiceExample.class);
    }

    private static class HasPostConstructAnnotationMatcher extends AbstractMatcher<TypeLiteral<?>> {
        private static final HasPostConstructAnnotationMatcher INSTANCE = new HasPostConstructAnnotationMatcher();

        @Override
        public boolean matches(TypeLiteral<?> t) {
            return Arrays.stream(t.getRawType().getDeclaredMethods()).anyMatch(GuiceExample::hasPostConstructAnnotation);
        }

    }

    private static boolean hasPostConstructAnnotation(Method method) {
        Annotation[] declaredAnnotations = method.getAnnotations();
        return Arrays.stream(declaredAnnotations).anyMatch(a -> a.annotationType().equals(PostConstruct.class));
    }

    private static class PostConstructAnnotationInvoker implements InjectionListener<Object> {
        private static final PostConstructAnnotationInvoker INSTANCE = new PostConstructAnnotationInvoker();

        @Override
        public void afterInjection(Object injectee) {
            //@formatter:off
            Arrays.stream(injectee.getClass().getDeclaredMethods())
            .filter(GuiceExample::hasPostConstructAnnotation)
            .forEach(m -> {
                try {
                    m.setAccessible(true);
                    m.invoke(injectee);
                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            });
            //@formatter:on
        }

    }

    public static interface IDataManager {
        void printData();
    }

    public static class DataManager implements IDataManager {

        @Override
        public void printData() {
            System.out.println("I print data.");
        }

    }
}

此外,您还可以多个 @PostConstruct 方法,但您将不知道它们将按什么顺序调用

@PostConstruct
private void init() {
    dataManager.printData();
}

@PostConstruct
private void init2() {
    System.out.println("Other init method");
}

Based on Geoff's answer you can "make callable" @PostConstruct method:

public class GuiceExample {
    @Inject
    private IDataManager dataManager;

    public GuiceExample() {
        System.out.println("Constructor");
    }

    @PostConstruct
    private void init() {
        dataManager.printData();
    }

    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new AbstractModule() {

            @Override
            protected void configure() {
                bind(IDataManager.class).to(DataManager.class);
                bindListener(HasPostConstructAnnotationMatcher.INSTANCE, new TypeListener() {

                    @Override
                    public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
                        encounter.register(PostConstructAnnotationInvoker.INSTANCE);
                    }
                });
            }
        });

        GuiceExample example = injector.getInstance(GuiceExample.class);
    }

    private static class HasPostConstructAnnotationMatcher extends AbstractMatcher<TypeLiteral<?>> {
        private static final HasPostConstructAnnotationMatcher INSTANCE = new HasPostConstructAnnotationMatcher();

        @Override
        public boolean matches(TypeLiteral<?> t) {
            return Arrays.stream(t.getRawType().getDeclaredMethods()).anyMatch(GuiceExample::hasPostConstructAnnotation);
        }

    }

    private static boolean hasPostConstructAnnotation(Method method) {
        Annotation[] declaredAnnotations = method.getAnnotations();
        return Arrays.stream(declaredAnnotations).anyMatch(a -> a.annotationType().equals(PostConstruct.class));
    }

    private static class PostConstructAnnotationInvoker implements InjectionListener<Object> {
        private static final PostConstructAnnotationInvoker INSTANCE = new PostConstructAnnotationInvoker();

        @Override
        public void afterInjection(Object injectee) {
            //@formatter:off
            Arrays.stream(injectee.getClass().getDeclaredMethods())
            .filter(GuiceExample::hasPostConstructAnnotation)
            .forEach(m -> {
                try {
                    m.setAccessible(true);
                    m.invoke(injectee);
                } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                    e.printStackTrace();
                }
            });
            //@formatter:on
        }

    }

    public static interface IDataManager {
        void printData();
    }

    public static class DataManager implements IDataManager {

        @Override
        public void printData() {
            System.out.println("I print data.");
        }

    }
}

Also, you can have multiple @PostConstruct method but you will not know in which order they are going to be invoked:

@PostConstruct
private void init() {
    dataManager.printData();
}

@PostConstruct
private void init2() {
    System.out.println("Other init method");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文