我开始使用Spring Boot并得到一个关于如何在不受Springs应用程序上下文管理的java对象中自动装配Spring Beans的问题。
场景:在我的Spring Boot应用程序中,我想编写一个计划任务,首先获取类型为" environment"的主数据列表。来自数据库。对于每个环境" object将执行多个异步Rest调用,返回一些JSON数据(此处为" applicationServerData")。这些数据应保存在本地,直到所有其他呼叫响应到达。经过一些处理后,结果将被写入数据库。
所以我想到创建一种能够在本地保存所请求数据的处理器类。对于每个环境,将使用new运算符创建一个新对象:
@Slf4j
public class EnvironmentProcessingServiceImpl implements
EnvironmentProcessingService {
@Autowired
private DataManagementFacade dataManagementFacade;
@Autowired
@Qualifier(value = "mock")
private ProductionDataClient productionDataClient;
private Environment environment;
private List<ApplicationServerDataHolder> applicationServerDataHolderList;
public EnvironmentProcessingServiceImpl(Environment environment) {
this.environment = environment;
this.applicationServerDataHolderList = new ArrayList<>();
}
现在的问题是,@Autowired
不会起作用,因为对象不是由Spring管理的,但我不能简单地将其设为@service
,因为如果我想保存数据我需要多个实例在同一个班。我读到了@Configurable
注释的解决方案。这是好习惯吗?
或者我应该将类设为@service
并创建另一个缓存所有数据的组件,并在任务完成后擦除以便下次运行时有空列表?
在这种情况下,您认为什么是良好做法。
答案 0 :(得分:1)
Spring中的@service可以限定为Prototype,@ Scope(“prototype”),请点击此处:http://www.mkyong.com/spring/spring-bean-scopes-examples/
答案 1 :(得分:0)
你想根据不同的情况得到不同的实例,我认为你应该为一个接口提供更多的Impl,对吧?您可以使用Autowired接口,但是您应该决定要获取哪个实例,Spring无法做出选择,它只是帮助管理beans.eg,当type = 0时,您获得bean A;当type =时1,你得到豆B;在你使用@Autowired之前,你的spring应该已经存放了bean。你可以使用的另一种方式,另一种方法你可以使用。而bean的范围是Singlton default.Just my answer。
答案 2 :(得分:0)
我在没有Boot部分的情况下使用Spring。如果你能以某种方式获得上下文对象,你可以做的一个技巧就是调用:
context.getAutowireCapableBeanFactory().autowireBean(bean);
在我们的项目中,我们有一个手工制作的上下文查找机制,我们大多不需要传递它。我实际上试图避免使用autowire来支持在@Configuration
类中注入事物并使它成为我处理Spring的唯一地方并且具有与Spring相关的导入。我们的球衣资源类是个例外。那些是由球衣而不是春天实例化的。我知道有一些精心设计的黑客可以修复并使两个框架相互配合。但我只是实现了一个静态方法,它返回静态单例上下文,如果它不存在则创建它。额外的好处是它大大减少了启动时发生的魔法量(春天很好,直到它不起作用,并没有告诉你原因)。
public class InbotSpringContextLoader {
private static final Logger LOG = LoggerFactory.getLogger(InbotSpringContextLoader.class);
private static AnnotationConfigApplicationContext context = null;
private static final AtomicBoolean contextCreated = new AtomicBoolean(false);
private static final Lock LOCK = new ReentrantLock();
public static ApplicationContext context() {
if(contextCreated.get()) {
return context;
} else {
LOCK.lock();
try {
if(!contextCreated.get()) {
// init SLF4j JUL bridge
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
context = new AnnotationConfigApplicationContext(RootConfig.class);
contextCreated.set(true);
}
return context;
} finally {
LOCK.unlock();
}
}
}
/**
* Use this from jersey resources and other places where getting the context is kind of sucky
*
* @param bean
* the bean where stuff needs to be injected
*/
public static void autowire(Object bean) {
InbotSpringContextLoader.context().getAutowireCapableBeanFactory().autowireBean(bean);
}
public static void destroy() {
if(context != null) {
context.close();
}
}
}
在我的资源构造函数中,我只是调用。
InbotSpringContextLoader.autowire(this);
答案 3 :(得分:0)
您可以从任何组件注入ApplicationContext:
@Autowired private ApplicationContext applicationContext;
然后你可以用它来获取一个bean:
Class<?> clazz = DemoBean.class;
DemoBean demoBean = (DemoBean)applicationContext.getAutowireCapableBeanFactory().autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
请注意,使用AUTOWIRE_NO时,任何使用@Autowired注释的成员变量仍将自动装配。