如何处理在运行时创建的对象与依赖注入框架一起使用?

时间:2015-04-15 18:58:40

标签: java design-patterns dependency-injection

我喜欢依赖注入框架以及它们如何允许我从一开始就请求一个对象。所有接线都是在第一次请求时进行的,即#34; master"宾语。 但是,有些对象应该在运行时创建,例如基于用户输入。有时,这些新创建的对象应该在框架创建的其他对象之间共享。

我目前的做法是"未初始化"框架注入的对象。在运行期间,我尽快使用setter方法设置对象。

我不喜欢这种方法的方法是,setter方法实际上只被调用一次,然后再也不会被触及。这使我无法将字段声明为final。我现在不知道如何在不丢失DI框架的所有好处之前创建对象,而不会丢失所有必要的信息。

我是DI的新手。这有什么好的模式吗?


示例:

// The service is used through out the application
interface Service {
  makeRequest()
}

用户输入凭据后我想要做什么:

new ConcreteService(username, password)
// but now I need to inject the concrete servive manually everywhere I need it!

我目前正在做的事情:

interface Service {
   makeRequest()
   setCredentials(username, password)
}
// service can be injected by framework, but I don't like setter methods
// that much (and they can pollute the interface)

2 个答案:

答案 0 :(得分:1)

我在依赖注入方面的大部分经验都是使用C#,但我相信无论使用何种语言,这个概念都是一样的。

我从原始海报中了解到的是,他试图“坚持”#34;依赖注入容器内的信息,以便稍后检索信息。

这种方法的问题在于,在多线程场景中,您使用的用于保留信息的依赖关系可能会被另一个线程覆盖其值。这可能发生,因为依赖注入容器通常包含对象的单个实例,只要您需要它就会返回给您。因此,您需要确保您的设计是线程安全的。

根据我的经验,使用依赖注入容器来维护状态是不好的。

您在依赖注入容器中注册的是提供"服务的对象"并且不维持任何州。

用于保存信息的对象通常是业务对象。这些业务对象应该用" new"来实例化。 (没有依赖注入容器),以通常的方式填充它们(使用setter或初始化方法或构造函数),并将其作为服务公开的操作的签名的一部分传递。

注意:您可以将您的依赖关系注册为" transient"这将告诉依赖注入容器每次请求依赖时返回一个新实例。这样可以避免使用" new"关键字显式,并在使用模拟框架编写单元测试时给予更多控制。

希望这有帮助!

答案 1 :(得分:0)

你可以做的一种方法是使用工厂。

例如,假设你有这门课程......

public class UserBean {

    private int userId;
    private UserService userService;
    // other resources / dependency fields etc

    public UserBean(int userId, UserService userService, ...other dependencies...) {
        this.userService = userService;
        this.userId = userId;
        this.... = ...
    }

    // ...getter for userId maybe etc...

    // Some method that uses the user's data AND the component/service you want to inject from Spring...
    public void incrementHitCount() {
        userService.incrementHitCount(userId);
    }
}

...其中“userService”是您希望由IoC容器管理的内容。如果你有一个组件需要创建其中一个,例如....

@Component
public class UserHitCountIncrementerThing {
    public ResponseBean doThatThing(HttpServletRequest request) {
         int userId = request.<get the user Id from it...>
         UserBean userbean = new UserBean(userId, /* need dependencies here! */);
         ...do stuff...
    }
}

你可以在这个bean的所有服务中@Autowire,或者你可以创建一个工厂,只有@Autowire,例如......

@Component
public class UserBeanFactory {
    @Autowired
    private UserService userService
    //...other @Autowired dependencies...

    public UserBean createUser(int userId) {
       return new UserBean(userService, ...etc..., userId);
    }
}

现在只需在需要的地方使用它,例如......

@Component
public class UserHitCountIncrementerThing {
    @Autowired
    private UserBeanFactory userFactory;

    public ResponseBean doThatThing(HttpServletRequest request) {
         int userId = request.<get the user Id from it...>
         UserBean userbean = userFactory.createUser(userId);
         ...do stuff...
    }
}

这是你得到的吗?

希望这有帮助。