Guice call init method after instantinating an object

前端 未结 8 1184
半阙折子戏
半阙折子戏 2020-11-28 06:21

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 annot

8条回答
  •  萌比男神i
    2020-11-28 07:13

    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  void hear(TypeLiteral type, TypeEncounter encounter) {
                            encounter.register(PostConstructAnnotationInvoker.INSTANCE);
                        }
                    });
                }
            });
    
            GuiceExample example = injector.getInstance(GuiceExample.class);
        }
    
        private static class HasPostConstructAnnotationMatcher extends AbstractMatcher> {
            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 {
            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");
    }
    

    提交回复
    热议问题