英文:
How to use @Autowired service, in an object created with the factory / strategy pattern (created at runtime)?
问题
考虑一个名为Action
的接口,以及两个实现类:StupidAction
和SmartAction
。
SmartAction
需要使用另一个服务,但由于Action
是在运行时创建的,所以@Autowired
注释不起作用(服务为null)。
在Spring中使用策略模式是否有问题?是否有一个好的解决方案来解决这个问题?
我可以将"StupidAction"也设置为一个服务,并且不实例化它。我也可以将自动装配的服务传递给"doSomething"方法的参数中。但这两种解决方案都不太理想。
一些代码示例:
public interface Action {
void doSomething();
}
public class StupidAction implements Action {
@Autowired
private MyService myService; // 这是null的,因为StupidAction是在运行时实例化的。
public void doSomething() {
myService.changeSomething();
}
}
// 伪代码
@RestController
@RequestMapping(path = "/")
public class WorkflowController {
@GetMapping("")
ResponseEntity someAPI() {
Action action = new SmartAction(); // 在运行时创建
action.doSomething(); // NullPointerExc
}
}
英文:
Consider an interface Action
, and 2 implementing classes: StupidAction
and SmartAction
.
SmartAction
needs to use another service, but because an Action
is created at runtime, the @Autowired
annotation doesn't work (the service is null).
Is it wrong to use the Strategy pattern with Spring? Is there a nice solution for this issue?
I could set "StupidAction" as a service as well, and not instantiate it. I could as well pass the autowired services to "doSomething" in method parameters. But both solutions are really dirty.
Some code example:
public interface Action {
void doSomething();
}
public class StupidAction implements Action{
@Autowired
private MyService myService; // THIS IS NULL. because StupidAction is instanciated at runtime.
public void doSomething(){
myService.changeSomething()
}
}
//Pseudo code
@RestController
@RequestMapping(path = "/")
public class WorkflowController {
@GetMapping("")
ResponseEntity someAPI() {
Action action = new SmartAction(); //create on runtime
action.doSomething(); //NullPointerExc
}
}
答案1
得分: 0
你可以使用BeanFactory按名称动态从上下文中获取bean:
@Service
public class Service {
@Autowired BeanFactory beanFactory;
public void foo(){
DynamicBean bean = beanFactory.getBean("bean_name", DynamicBean.class);
}
}
英文:
You can get the bean from the context by name dynamically using BeanFactory:
@Service
public class Service {
@Autowired BeanFactory beanFactory;
public void foo(){
DynamicBean bean = beanFactory.getBean("bean_name", DynamicBean.class)
}
}
答案2
得分: -2
您可以从一个实现了ApplicationContextAware接口的Util服务中获取Bean。
@Service
public class BeanUtility implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T extends Object> T getMyBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
控制器实现如下:
@RestController
@RequestMapping(path = "/")
public class WorkflowController {
@Autowired
BeanUtility beanUtility;
@GetMapping("action")
ResponseEntity someAPI() {
MyService myService = BeanUtility.getMyBean(MyService.class); // 使用工具类获取所需的Bean
Action action = new SmartAction(myService); // 基于构造函数的依赖注入
return new ResponseEntity<String>(action.doSomething(), HttpStatus.CREATED);
}
}
接下来是SmartAction类的实现如下:
@Service
public class SmartAction implements Action{
private MyService myService;
public SmartAction(MyService myService){
this.myService = myService;
}
@Override
public String doSomething() {
return "智能操作:" + myService.changeSomething();
}
}
英文:
You can get the bean from a Util service which is ApplicationContextAware.
@Service
public class BeanUtility implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static <T extends Object> T getMyBean(Class<T> beanClass) {
return context.getBean(beanClass);
}
}
The controller implementation as follows:
@RestController
@RequestMapping(path = "/")
public class WorkflowController {
@Autowired
BeanUtility beanUtility;
@GetMapping("action")
ResponseEntity someAPI() {
MyService myService = BeanUtility.getMyBean(MyService.class); // use the util class to get a Bean of your choice
Action action = new SmartAction(myService); // Constructor based DI
return new ResponseEntity<String>(action.doSomething(), HttpStatus.CREATED);
}
}
Followed by the implementation of SmartAction class as below:
@Service
public class SmartAction implements Action{
private MyService myService;
public SmartAction(MyService myService){
this.myService = myService;
}
@Override
public String doSomething() {
return "Smart action : " + myService.changeSomething();
}
}
专注分享java语言的经验与见解,让所有开发者获益!
评论