将CDI上下文bean注入现有的非上下文bean的正确方法?

时间:2014-11-05 15:20:51

标签: java java-ee cdi java-ee-6 destroy

以下是我用于将CDI上下文bean注入非上下文对象的代码。

    // My controller is Non-contextual bean
    public class MyController extends Controller {

        @Inject
        ModelBinder modelBinder;

        @Inject
        ApplicationConfig applicationConfig;

        private CreationalContext<Controller> creationalContext;

        public void setCreationalContext(CreationalContext<Controller> creationalContext) {
            this.creationalContext = creationalContext;
        }

        public CreationalContext<Controller> getCreationalContext() {
            return creationalContext;
        }

        // Other fields
    }

初始化MyController的代码

    // Create Non-contextual bean
    MyController controller = new MyController();

    AnnotatedType<?> at = beanManager.createAnnotatedType(controller.getClass());
    InjectionTarget<Controller> it = (InjectionTarget<Controller>)beanManager.createInjectionTarget(at);

    CreationalContext<Controller> creationalContext = beanManager.createCreationalContext(null);

    // Perform inject
    it.inject(controller, creationalContext);

    // Store creationalContext related
    controller.setCreationalContext(creationalContext);

销毁MyController的代码

    // controller is instance of MyController
    AnnotatedType<?> at = beanManager.createAnnotatedType(controller.getClass());
    InjectionTarget<Controller> it = (InjectionTarget<Controller>)beanManager.createInjectionTarget(at);

    it.dispose(controller);

    controller.getCreationalContext().release();

今天,我的团队负责人与我讨论过他说:因为ModelBinder,ApplicationConfig是CDI应用程序范围bean所以我不必编写代码销毁Controller和他建议的代码如下:

    // New MyController
    public class MyController extends Controller {

        @Inject
        ModelBinder modelBinder;

        @Inject
        ApplicationConfig applicationConfig;

        // Do not need to store creationalContext
        //private CreationalContext<Controller> creationalContext;

        //public void setCreationalContext(CreationalContext<Controller> creationalContext) {
        //  this.creationalContext = creationalContext;
        //}

        //public CreationalContext<Controller> getCreationalContext() {
        //  return creationalContext;
        //}

        // Other fields
    }

初始化MyController的新代码

    // Create Non-contextual bean
    MyController controller = new MyController();

    AnnotatedType<?> at = beanManager.createAnnotatedType(controller.getClass());
    InjectionTarget<Controller> it = (InjectionTarget<Controller>)beanManager.createInjectionTarget(at);

    CreationalContext<Controller> creationalContext = beanManager.createCreationalContext(null);

    // Perform inject
    it.inject(controller, creationalContext);

    // Do not need to store creationalContext related
    // controller.setCreationalContext(creationalContext);

销毁MyController的新代码

    // No need code to destroy the controller

任何人都有任何想法?非常感谢你!

2 个答案:

答案 0 :(得分:4)

从CDI 1.1开始,提供了Unmanaged帮助程序类以便于处理非上下文实例,以便您可以编写:

Unmanaged<MyController> unmanaged = new Unmanaged<MyController>(MyController.class);
UnmanagedInstance<MyController> instance = unmanaged.newInstance();
MyController controller  = instance.produce().inject().postConstruct().get();
... // Use the controller instance
instance.preDestroy().dispose();

该版本使用CDI.current()来检索BeanManager,但如果需要可以提供它:

Unmanaged<MyController> unmanaged = new Unmanaged<MyController>(beanManager, MyController.class);

更多信息可以在obtaining non-contextual instance中的CDI规范中找到。

答案 1 :(得分:0)

我认为这里真正的问题是为什么你需要实例化你的控制器而不是获得托管引用?

您可以使用@Dependent范围的bean来实现与Unmanaged正在处理的相同的事情。您甚至可以使用工厂模式来委派一些工作。支持你有这个注入点:

@Inject @Any
private Instance<MyController> myControllerProvider;

在您的商业方法中,当您需要参考时,您可以

MyController controller = myControllerProvider.get();

这将为您提供托管参考。我注意到你使用的是静态类 - 这意味着它不是顶级类。 CDI会要求它作为顶级课程。