I've created an ApplicationContextInitializer implementation to load properties from a custome source (ZooKeeper) and add them to the ApplicationContext's property sources list.
All the documentation I can find relates to Spring web-apps, but I want to use this in a standalone message-consuming application.
Is the right approach to instantiate my implementation, create the context, then pass the context to my implementation 'manually'? Or am I missing some automatic feature fo the framework that will apply my initializer to my context?
I have found it simple enough to implement the SpringMVC's strategy for Initializing a context by initializing with a blank context. In normal application contexts, there is nothing which uses an ApplicationContextInitializer, thus you must execute it on your own.
No problem, though since within a normal J2SE application given you have ownership of the context loader block, you will have access to every stage of the lifecycle.
// Create context, but dont initialize with configuration by calling
// the empty constructor. Instead, initialize it with the Context Initializer.
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
MyAppContextInitializer initializer = new MyAppContextInitializer();
initializer.initialize( ctx );
// Now register with your standard context
ctx.register( com.my.classpath.StackOverflowConfiguration.class );
ctx.refresh()
// Get Beans as normal (e.g. Spring Batch)
JobLauncher launcher = context.getBean(JobLauncher.class);
I hope this helps!
If I understand the problem correctly, you can find the solution in Spring documentation Section 4. The IoC container
An example on how to start your app is here - 4.2.2 Instantiating a container
Also have a look at 5.7 Application contexts and Resource paths
Not sure about other versions, but in Spring 4:
AbstractApplicationContext ctx = new AnnotationConfigApplicationContext(yourConfig.class);
Related
I'm working with the developer of PF4J(Plugin Framework for Java) to provide better plugin functionality for Wicket. There is already a pf4j-spring and a pf4j-wicket project to provide some basic integration. In order to allow the #SpringBean or #Inject annotations to have access to plugin beans in a child context we need to be able to lookup the ApplicationContext associated with a specific class.
So for example, say I have a MyService bean in a child(plugin) ApplicationContext and that plugin also provides a panel that needs that via a #SpringBean annotation. Spring doesn't allow the parent ApplicationContext to see beans in a child context and for good reason. So we would get an exception saying that bean could not be found since #SpringBean only looks up beans in the parent context. We have code that we have developed that look up the child context like so:
SpringPlugin plugin = (SpringPlugin)PluginManager.whichPlugin(MyService.class);
ApplicationContext pluginContext = plugin.getApplicationContext();
How could I modify or provide this functionality in a custom version of SpringComponentInjector? It uses a ISpringContextLocator but that context locator does not specify the class for which it needs the ApplicationContext.
Any ideas on how this could be achieved?
Thanks for your help!
I'm afraid current SpringComponentInjector is not prepared for such usage. You will have to create your own version.
The problem that I see is that you will have to have either as many IComponentInstantiationListeners as plugins there are. Or create a composite ICIL that delegates to SpringBeanLocators for each plugin. I think the composite would be better. Then you'll have to make sure that a Panel in pluginA cannot use a bean located by SpringBeanLocatorB.
If you manage to do it and you find something in wicket-spring that could be made more generic to help make your version simpler then please let us know and we will consider your suggestion(s)!
Take a look at sbp. It is built on top of pf4j to support Spring Boot, and also provides mechanism of sharing beans between main application and plugins. It looks like:
#Override
protected SpringBootstrap createSpringBootstrap() {
return new SharedDataSourceSpringBootstrap(this, MdSimplePluginStarter.class)
.addSharedBeanName("objectMapper")
.addSharedBeanName("cacheService");
}
I keep on learning Spring and it is very difficult to figure out which implementation of ApplicationContext is intended for. I've standalone J2EE application and I don't interested in Web* or Portlet* implementations.
Can you provide me the brief list of possibilities (if isn't clear, see P.S. section of my question) and purposes of each implementation below:
ResourceAdapterApplicationContext
StaticApplicationContext
ClassPathXmlApplicationContext
FileSystemApplicationContext
P.S.
A don't ask you to provide me reference to the docs. For example:
ClassPathXmlApplicationContext Standalone XML application context,
taking the context definition files from the class path, interpreting
plain paths as class path resource names that include the package path
But from that definition its not clear that ClassPathXmlApplicationContext also implements AbstractRefreshableApplicationContext and can be used to change beans definition without stopping server.
I'm sorry you don't want references to the docs, but that's where all the information is.
StaticApplicationContext states
org.springframework.context.ApplicationContext implementation which
supports programmatic registration of beans and messages, rather than
reading bean definitions from external onfiguration sources. Mainly
useful for testing.
So you use it to register bean definitions directly
StaticApplicationContext context = new StaticApplicationContext();
context.registerBeanDefinition(beanName, beanDefinition);
This can be used in cases where your ApplicationContext needs to be dynamically changed. Note that you can pass a parent ApplicationContext to the StaticApplicationContext if you need both behaviors, ie. reading from XML/Java config and dynamically registering.
ClassPathXmlApplicationContext is one of the more common ApplicationContext implementations in my opinion. You simply point it to an XML (bean definition) resource on the classpath and it loads it up. The javadoc states
Useful for test harnesses as well as for application contexts embedded
within JARs.
You could therefore simply point to a resource on the classpath coming from a JAR and load that. It's simply enough to setup tests environments this way.
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("some-context.xml");
// boom you're ready to go
Note that Spring's JUnit support classes offer other (better) ways to setup testing environment.
But from that definition its not clear that
ClassPathXmlApplicationContext also implements
AbstractRefreshableApplicationContext and can be used to change beans
definition without stopping server.
That's what the javadoc is for.
FileSystemXmlApplicationContext is similar to the ClasspathXmlApplicationContext above, but it takes the configuration files from the file system instead of reading resources from the classpath.
ResourceAdapterApplicationContext states
org.springframework.context.ApplicationContext implementation for a
JCA ResourceAdapter. Needs to be initialized with the JCA
javax.resource.spi.BootstrapContext, passing it on to Spring-managed
beans that implement BootstrapContextAware.
I haven't worked with this one at all and I don't know where Resource Adapters are useful, but here are some more docs.
Just to add couple things to #Solitirios answer:
You forgot to mention several more context:
GenericApplicationContext
GenericXmlApplicationContext
AnnotationConfigApplicationContext
GenericWebApplicationContext
StaticWebApplicationContext
And many others.
In general, GenericApplicationContext is almost the same as StaticApplicationContext, the only difference between them in MessageSource support in StaticApplicationContext. Purpose for both of these classes is for small tests with tiny application context with couple beans.
GenericWebApplicationContext and StaticWebApplicationContext are also quite similar to each other, and typically they are used for emulation of Servlet container, e.g. tests or non-Servlet environment.
F.e. you can use something like this in your code (f.e. tests):
//create parent context
ApplicationContext xmlContext = new GenericXmlApplicationContext("classpath:/spring-*.xml");
//create mock servlet context
MockServletContext mockServletContext = new MockServletContext();
//create web context
GenericWebApplicationContext webContext = new GenericWebApplicationContext(mockServletContext);
//set attribute
mockServletContext.setAttribute(GenericWebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, webContext);
//set parent context
webContext.setParent(xmlContext);
//refresh context
webContext.refresh();
But there are couple contexts classes, which are worthy of attention. And considering your pre-requisites, I would choose one of them.
GenericXmlApplicationContext is very good alternative of ClassPathXmlApplicationContext and FileSystemXmlApplicationContext. Consider this example:
ApplicationContext context = new GenericXmlApplicationContext("classpath:some-context.xml");
is equivalent to
ApplicationContext context = new ClassPathXmlApplicationContext("some-context.xml");
or
ApplicationContext context = new GenericXmlApplicationContext("some-context.xml");
is equivalent to
ApplicationContext context = new FileSystemXmlApplicationContext("some-context.xml");
So GenericXmlApplicationContext looks more flexible.
AnnotationConfigApplicationContext is a context holder, if you don't want to keep your beans in XML-file.
//context creation
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
//context class
#Configuration
#ComponentScan("com.examples.services")
public class AppConfig {
#Bean
public DataSources dataSource() {
DataSource ds = new BasicDataSource();
//... init ds
return ds;
}
}
More information you can find here.
I am using Spring3.1
My application will have kind of bean-manager.
That manager will be able to retrieve request and on each request I need to create new instance of bean dynamically which will be initiate with it's own unique params.
The params will be retrieved via the request method.
This bean must be alive and work asynchronously. (For example it will listen to jms calls, execute methods by demand and so on..)
Moreover I want to have the option to destroy beans also.
Those bean could be resemble as sessions so when the user log off i will destroy those beans.
I understand that I have to create some kind of bean-list or beans pool and manage it with some kind of manager.
How can I create those beans dynamically and have them remain them alive until I destroy them?
Any idea how could I implement such thing?
Well in this sense, the easiest way would be to create a StaticApplicationContext setting its parent context as the common context (the one holding the beans you want to share over all). This you could reach by doing something like:
StaticApplicationContext innerContext = new StaticApplicationContext(parentContext);
after this, you probably want to declare the bean you want to instantiate over Spring in order to attach all the AOP stuff, Autowiring and other functionalities, therefore you will need to do something like:
innerContext.registerSingleton("beanName", beanClass);
After registering you could instantiate the bean like:
innerContext.getBean(beanClass);
Of course there is the implementation of scope Session for spring and therefore I advise you to check the WebApplicationContext documentation, method loadParentContext that you basically pass the ServletContext as paramenter.
I've also found many trouble in creating a bean dynamically at run-time and used it anywhere in application..
Here is complete code
static ApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] { "Spring-Question.xml" });
static StaticApplicationContext innerContext = new StaticApplicationContext(appContext);
Create the bean and set the values e.g.
innerContext.registerSingleton("beanName", Test.class);
Test test = innerContext.getBean(Test.class);
test.setA(3);
test.setB(4);
Then Re-Use the bean anywhere in application....
Test test = innerContext.getBean(Test.class);
System.out.println(test.setB(4));
I am learning Spring and I have a question regarding how you use it in standalone applications (and also when using it for making web applications). The examples I have been coded so far has used a simple main method where I retrieve beans by calling getBean on the. Context object. However, you probably want to do this in multiple classes so do you first get a context and then call getBean or are there other cleaner alternatives? Or is this the way you do it in standalone and web apps?
If you're calling context.getBean() everywhere, you're probably missing the whole point of Spring, which is a dependency injection framework.
In a standalone app, you typically call context.getBean() only once (or at least, very rarely), in order to get a "root" bean. This bean is injected by Spring with other beans, and so on.
In a web app, it all depends on which framework you use. But typically, you register a listener in the web.xml which loads the context for you, and controllers are created and/or injected by Spring.
You're on the right lines. Your main method will initialise your application context as you've discovered. The trick then is to use that app context to create the entry point to your application. That bean, having been created with spring will have been wired for you..
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationMain {
public static void main(String[] args) {
AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/META-INF/spring/applicationContext.xml");
MyApplication app = BeanFactoryUtils.beanOfType(ctx, MyApplication.class);
app.init();
}
}
One class (your main class, probably) has to be Spring-aware to create the context. All other classes can continue to be wired together via Spring and do not need to be Context-aware.
It kind of depends on the application you are writing, but you should limit getBean() invocations to minimum, preferably one. You are fetching the first bean directly from the context and put the rest of the logic in the beans themselves. Something along the lines:
Bootstrap boot = context.getBean(Bootstrap.class);
boot.start();
And all the rest of your application logic is taking place within start(). It can create threads, listen for events, etc.
I was wondering if there's a way to Load Springs application context without having to define it in a web.xml.
I see you can use:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
But if you wanted to use a bean you've got to getBean() to have access to it. I am thinking possibly there could be a way to load the context programmatically as would the definition in web xml, without having to call getBean.
Any ideas?
You can use:
ctx.getAutowireCapableBeanFactory().autowireBeanProperties(this,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
...where ctx is your ClassPathXmlApplicationContext to avoid the need to ever call getBean() - any spring bean fields on this will be autowired for you.
There is a way. You just have to read official documentation. The relevant part is here.
Edit: Sorry, misread your question. You can use
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
and load it using ServletContextListener at application startup. When your application starts, if you've configured your bean wiring properly, you shouldn't have to call getBean() to access all of your beans. Treat it like you're using Java SE.