您如何处理在运行时与依赖注入框架一起创建的对象?
How do you handle objects created at runtime in conjunction with Dependency Injection frameworks?
我喜欢依赖注入框架,以及它们如何让我请求一切都以一个对象开始。所有连接都是在第一次请求 "master" 对象时进行的。
但是,有些对象应该在运行时创建,例如基于用户输入。有时那些新创建的对象应该在框架创建的其他对象之间共享。
我目前的方法是让 "uninitialized" 对象由框架注入。在运行时,我尽快使用 setter 方法设置对象。
我不喜欢这种方法的地方是,setter 方法实际上只被调用一次,以后再也不会被调用。这使我无法将字段声明为最终字段。我现在不知道如何在所有必要信息可用之前创建对象,同时又不会失去 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)
一种方法是使用工厂。
例如,假设您有这个 class...
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...
}
}
这就是你想要的吗?
希望对您有所帮助。
我在依赖注入方面的大部分经验都来自于 C#,但我相信无论使用何种语言,这个概念都是一样的。
我从发帖人那里了解到,他正试图 "persist" 依赖注入容器中的信息,以便稍后检索信息。
这种方法的问题在于,在多线程场景中,您用来保存信息的依赖项的值可能会被另一个线程覆盖。之所以会发生这种情况,是因为依赖项注入容器通常包含对象的单个实例,只要您需要,它就会 returned 给您。因此,您需要确保您的设计是线程安全的。
根据我的经验,使用依赖注入容器来维护状态是不好的。
您在依赖项注入容器中注册的是提供 "service" 且不保持任何状态的对象。
您用来保存信息的对象通常是业务对象。这些业务对象应该只用 "new" 实例化(没有依赖注入容器),以通常的方式填充它们(使用 setter 或初始化方法或构造函数)并作为操作签名的一部分传递您的服务公开。
注意:您可以将依赖项注册为 "transient",这会在您每次请求依赖项时告诉依赖项注入容器 return 一个新实例。这将避免显式使用 "new" 关键字的需要,并在使用模拟框架编写单元测试时为您提供更多控制。
希望对您有所帮助!
我喜欢依赖注入框架,以及它们如何让我请求一切都以一个对象开始。所有连接都是在第一次请求 "master" 对象时进行的。 但是,有些对象应该在运行时创建,例如基于用户输入。有时那些新创建的对象应该在框架创建的其他对象之间共享。
我目前的方法是让 "uninitialized" 对象由框架注入。在运行时,我尽快使用 setter 方法设置对象。
我不喜欢这种方法的地方是,setter 方法实际上只被调用一次,以后再也不会被调用。这使我无法将字段声明为最终字段。我现在不知道如何在所有必要信息可用之前创建对象,同时又不会失去 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)
一种方法是使用工厂。
例如,假设您有这个 class...
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...
}
}
这就是你想要的吗?
希望对您有所帮助。
我在依赖注入方面的大部分经验都来自于 C#,但我相信无论使用何种语言,这个概念都是一样的。
我从发帖人那里了解到,他正试图 "persist" 依赖注入容器中的信息,以便稍后检索信息。
这种方法的问题在于,在多线程场景中,您用来保存信息的依赖项的值可能会被另一个线程覆盖。之所以会发生这种情况,是因为依赖项注入容器通常包含对象的单个实例,只要您需要,它就会 returned 给您。因此,您需要确保您的设计是线程安全的。
根据我的经验,使用依赖注入容器来维护状态是不好的。
您在依赖项注入容器中注册的是提供 "service" 且不保持任何状态的对象。
您用来保存信息的对象通常是业务对象。这些业务对象应该只用 "new" 实例化(没有依赖注入容器),以通常的方式填充它们(使用 setter 或初始化方法或构造函数)并作为操作签名的一部分传递您的服务公开。
注意:您可以将依赖项注册为 "transient",这会在您每次请求依赖项时告诉依赖项注入容器 return 一个新实例。这将避免显式使用 "new" 关键字的需要,并在使用模拟框架编写单元测试时为您提供更多控制。
希望对您有所帮助!