在独立的JavaSpring应用程序中摆脱getBean(非web应用程序,无容器)
在web应用程序中,我们实际上不需要这样做在独立的JavaSpring应用程序中摆脱getBean(非web应用程序,无容器),java,spring,Java,Spring,在web应用程序中,我们实际上不需要这样做 ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml"); ctx.getBean("beanId"); 因为一般做法是加载上下文文件,并使用web.xml中的ContextLoaderServlet将所有bean与依赖项一起注入,如下所示 <context-param> <param-name>contextConf
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-context.xml");
ctx.getBean("beanId");
因为一般做法是加载上下文文件,并使用web.xml中的ContextLoaderServlet将所有bean与依赖项一起注入,如下所示
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-context.xml /WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- or use the ContextLoaderServlet instead of the above listener
<servlet>
<servlet-name>context</servlet-name>
<servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
-->
上下文配置位置
/WEB-INF/spring-context.xml/WEB-INF/applicationContext.xml
org.springframework.web.context.ContextLoaderListener
然而,在一个没有容器的独立java应用程序中,我最终执行了ctx.getBean(“xyz”)。有没有一个干净的方法可以做到这一点,无法找到一个例子在线
我查了一下,它谈到使用SingletonBeanFactoryLocator,但它最终使用了context.getBean()
我还研究了ServiceLocatoryFactoryBean,但这也是通过使用代理按需获取Bean
我正在寻找一种解决方案,从我的独立java应用程序的main()程序加载上下文文件(所有bean),这样我就不想按需获取bean
示例代码:
public interface IReader {
public String read();
}
public class TextFileReader implements IReader {
private StringBuilder builder = null;
private Scanner scanner = null;
public TextFileReader(String fileName) throws FileNotFoundException {
scanner = new Scanner(new File(fileName));
builder = new StringBuilder();
}
public String read() {
while (scanner.hasNext()) {
builder.append(scanner.next());
builder.append(",");
}
return builder.toString();
}
}
public class SpringNoConextDataReaderClient {
private IReader reader = null;
public void setReader(TextFileReader reader) {
this.reader = reader;
}
private String fetchDataOne() {
return reader.read();
}
private String fetchDataTwo() {
return reader.read();
}
public static void main(String[] args) {
final ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
String fetchedData = context.getBean(SpringNoConextDataReaderClient.class).fetchDataOne(); // <-- reader is injected as TextFileReader in fetchDataOne which reads the file
SpringNoConextDataReaderClient client = new SpringNoConextDataReaderClient();
client.fetchDataOne(); // <-- reader is null and throws NPE, probably its lifetime ended with previous call?
System.out.println("Example 1.1: Got data without context: " + fetchDataOne);
}
}
公共接口IReader{
公共字符串读取();
}
公共类TextFileReader实现IReader{
私有StringBuilder=null;
专用扫描仪=空;
公共TextFileReader(字符串文件名)引发FileNotFoundException{
扫描仪=新扫描仪(新文件(文件名));
生成器=新的StringBuilder();
}
公共字符串读取(){
while(scanner.hasNext()){
append(scanner.next());
生成器。追加(“,”);
}
返回builder.toString();
}
}
公共类SpringNoConextDataReaderClient{
专用IReader reader=null;
public void setReader(TextFileReader){
this.reader=读取器;
}
私有字符串fetchDataOne(){
返回reader.read();
}
私有字符串fetchDataTwo(){
返回reader.read();
}
公共静态void main(字符串[]args){
final ApplicationContext context=new ClassPathXmlApplicationContext(“spring context.xml”);
字符串fetchedData=context.getBean(SpringNoConextDataReaderClient.class).fetchDataOne()在一个独立的应用程序中,您需要自己创建一个ApplicationContext
的实例,并使用它来加载至少一个bean。但是您加载的一个bean可以使用所有的Spring魔法,如@Autowired
等,并且不再需要使用getBean
。因此,您可以使用一个引导bean来加载getBean
然后让这一个bean执行其他所有操作。类似于:
@Component
public class Main
{
@Autowired
protected MyDependencyClass2 someClass1;
@Autowired
protected MyDependencyClass2 someClass2;
// ...
// or if you need an entity manager
@PersistenceContext
protected EntityManager em;
// etc.
protected void mainInternal(String[] args)
throws Exception
{
// do everything here
// all dependencies are initialized
// ...
}
public static void main(String[] args)
throws Exception
{
// Bootstrap Spring and let it create and configure beans.
final ApplicationContext context =
new ClassPathXmlApplicationContext("spring-context.xml");
context.getBean(Main.class).mainInternal(args);
}
}
注意:通常,使用或的变体(采用类
参数)更安全
如果您只是调用newmain()
,依赖项将不会被初始化。Spring不知道您使用new
创建的实例,只知道它自己创建的实例。这是Spring的一个关键概念。它不仅创建类的实例,还管理它与其他bean的依赖项,可以使用方面等处理创建的实例。这不是在您使用new
创建的实例上可能会出现这种情况
这里的要点是,如果您将所有代码从main
移动到main internal
,那么您所需的所有依赖项都将被初始化。不仅main
,而且它的依赖项、它们的依赖项等也将被初始化。因此,如果您的应用程序是使用Spring正确构建的,并且它只使用Spring管理依赖项,那么功能(如@Autowired
),然后您将获得与web应用程序中类似的环境
因此,在本例中,正确的过程是:生成Main
的应用程序启动依赖项所需的所有bean。它们将与其所有依赖项一起初始化,您可以在Main internal
或它调用的任何程序中安全地使用它们
编辑:评论您的示例。正如我所解释的,Spring只管理它创建的对象,而不是您使用new
创建的对象
SpringNoConextDataReaderClient client = new SpringNoConextDataReaderClient();
因此,client
将不由Spring管理,也不会设置或解析它的依赖项
另外,您的示例设计得不好。Spring的主要思想是管理程序组件,并原则上将它们连接在一起。在大多数情况下,这些程序组件都是在应用程序的整个生命周期中存在的。(也可以使用寿命较短的组件,例如一个HTTP请求或一个HTTP会话作用域,但这超出了本问题的范围。)重要的一点是,此类单例组件在初始化后不应更改其内部状态
另一方面,Spring并不是用来管理您的数据对象,例如IReader
IReader
不是程序的组件,而是您创建、读取文件并随后处理的对象。更好的设计是:
- 有一个单例bean,可以按需为您提供
IReader
,比如
public class TextFileReaderProvider {
public IReader createReader() { ... }
}
- 将此提供程序连接到SpringNoContextDataReaderClient中
public class SpringNoConextDataReaderClient {
@Autowired
protected TextFileReaderProvider readerProvider;
public SomeResult doMyComputation() {
IReader r = readerProvider.createReader();
try {
// compute the result
return theResult;
} finally {
r.close();
}
}
}
(或者代替@Autowired
在XML中手动配置依赖项)
- 在
main
中,让Spring为您获取一个SpringNoContextDataReaderClient
的实例,并在此基础上调用domaycompution()
这样的设计会使您将软件分成不同的组件,这些组件可以在整个应用程序中重用,并且不会出现并发问题。1.我正在寻找一种解决方案,在这种解决方案中,我们可以始终存在初始化的依赖项,例如:在我的main方法中,我会……main m=new main();m.main internal()
我看不到依赖项已初始化
public class SpringNoConextDataReaderClient {
@Autowired
protected TextFileReaderProvider readerProvider;
public SomeResult doMyComputation() {
IReader r = readerProvider.createReader();
try {
// compute the result
return theResult;
} finally {
r.close();
}
}
}