在我目前的项目中,我正在处理实现巨大接口的EJB。 实现是通过业务委托完成的,该委托实现相同的接口并包含真实的业务代码。
正如一些文章所建议的那样
这个'命令模式'的使用顺序是
问题发生在第4步。:
现在我正在使用spring上下文从命令中的上下文中获取bean, 但我想将依赖注入命令。
这是一个用于说明目的的天真用法。我在有问题的地方添加了评论:
public class SaladCommand implements Command<Salad> {
String request;
public SaladBarCommand(String request) {this.request = request;}
public Salad execute() {
//this server side service is hidden from client, and I want to inject it instead of retrieving it
SaladBarService saladBarService = SpringServerContext.getBean("saladBarService");
Salad salad = saladBarService.prepareSalad(request);
return salad;
}
}
public class SandwichCommand implements Command<Sandwich> {
String request;
public SandwichCommand(String request) {this.request = request;}
public Sandwich execute() {
//this server side service is hidden from client, and I want to inject it instead of retrieving it
SandwichService sandwichService = SpringServerContext.getBean("sandwichService");
Sandwich sandwich = sandwichService.prepareSandwich(request);
return sandwich;
}
}
public class HungryClient {
public static void main(String[] args) {
RestaurantService restaurantService = SpringClientContext.getBean("restaurantService");
Salad salad = restaurantService.execute(new SaladBarCommand(
"chicken, tomato, cheese"
));
eat(salad);
Sandwich sandwich = restaurantService.execute(new SandwichCommand(
"bacon, lettuce, tomato"
));
eat(sandwich);
}
}
public class RestaurantService {
public <T> execute(Command<T> command) {
return command.execute();
}
}
我想摆脱像SandwichService sandwichService = SpringServerContext.getBean("sandwichService");
这样的电话
并改为注入我的服务。
如何以最简单的方式做到这一点?
答案 0 :(得分:3)
您可以使用Spring @Configurable批注允许AspectJ将Spring bean注入不是由Spring创建的对象中。看看here
答案 1 :(得分:2)
这不是理解的问题 DI如何运作
我同意纪尧姆的观点,因为我遇到了同样的情况。
主要问题是实例化和对象生命周期。
该命令可以多次创建,例如相同的方法。 并以编程方式。
Spring,作为容器,假定您要使用作用域(session,prototype = thread scope),应用程序范围创建对象一次......
因此命令不是由spring创建的,它应该使用spring创建的服务。 但是该命令中没有注入该服务。
谢谢
答案 2 :(得分:2)
在服务器端,在RestaurantService中,执行以下操作:
实现ApplicationContextAware接口 - 这将导致Spring将应用程序上下文的引用注入到RestaurantService中。
在RestaurantService.execute(Command)方法中,执行以下操作:
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
beanFactory.autowireBeanProperties(command, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
command.execute();
最后,在您的应用程序上下文中,声明每个具有注入依赖项的Command对象的实例。
这应该具有允许您在客户端上创建对象,序列化它们,将它们发送到服务器以及在使用它们之前注入依赖项的效果。在接收物体时而不是在使用物体之前进行注射可能更清洁。
如何使用AutowireCapableBeanFactory还有一些其他选项 - 此示例使用适当的类查找bean定义,并设置应用程序上下文中定义的属性。如果您可以将每个Command实现与应用程序上下文中的名称相关联,则可以使用configureBean(Object,String)来支持回调。
答案 3 :(得分:1)
我在过去构建了一些非常相似的东西,除了我们没有像你现在那样使用命令模式。在您的情况下,您的命令似乎什么也不做,只是实际查找和运行服务方法,所以为什么不简单地将该服务方法作为API而不是完全使用命令模式。然后,您可以通过Spring Remoting将服务调用连接到EJB,并且所有Spring细节都可以保留在特定于协议的层(Servlet,EJB,MDB ......)中,并且您的代码仍然无法忽略它周围发生的事情
我们的基础设施如下所示。 (对于那些抱怨EJB存在的人来说,这不是整个基础架构,出于安全性和性能原因,我们使用EJB到EJB调用来进行服务交互)。
Eclipse Rich Client - &gt; (Spring Remoting - HTTP) - &gt; Servlet - &gt; (本地接口) - &gt; EJB - &gt;服务实施
Servlet - 使用Spring上下文查找本地EJB接口,并使用RemoteInvocation对象(由Spring Remoting从HttpProxyFactoryBean生成和发送)以及服务接口的名称调用通用EJB接口的公共调用方法。
EJB - 根据其接口名称(也是bean名称)查找服务,并使用RemoteInvocationExecutor通过RemoteInvocation对象调用服务实现上的方法。
现在EJB能够绑定到多个服务(尽管我们使用一对一的部署模型)。您可以使用Spring Remoting对来自不同应用程序的服务进行基于Http,EJB或JMS的调用。没有服务器部署的测试是微不足道的,因为您只需将测试直接连接到实现。
注意:如果有机会,我会尝试添加一些代码段。
答案 4 :(得分:0)
如果通过Spring ApplicationContext将SimpleCommand注入到类中(实际上应该是这样),那么你只需要将它的依赖关系表达为构造函数参数或setter并注入它们。
如果不了解谁在使用SimpleCommand,它来自何处,等等,很难再提供更多细节。
答案 5 :(得分:0)
public class SampleCommand implements Command {
private final String parameter;
private final ServiceBean service;
//the client build the command using a parameter
public SampleCommand(ServiceBean service, String parameter) {
this.parameter = parameter;
this.service = service;
}
//this code will be executed by the server
public Object execute() {
//do something using the parameter and return the result
return service.doSomethingWith(parameter);
}
}
您可以使用或不使用Spring注入服务:
<bean id="sampleCommand" class="package.SampleCommand">
<constructor-arg ref="serviceBean" />
<constructor-arg value="Param" />
</bean>
一些调用应用程序:
ServiceBean service = ServiceProxy.getService(SampleCommand.class);
Command command = new SampleCommand(service, "Param");
依赖注入不依赖于框架。