I've learned:
The three commonly used implementation of 'Application Context' are −
FileSystemXmlApplicationContext − This container loads the definitions
of the beans from an XML file. Here you need to provide the full path
of the XML bean configuration file to the constructor.
ClassPathXmlApplicationContext − This container loads the definitions
of the beans from an XML file. Here you do not need to provide the
full path of the XML file but you need to set CLASSPATH properly
because this container will look bean configuration XML file in
CLASSPATH.
WebXmlApplicationContext − This container loads the XML file with
definitions of all beans from within a web application.
So how about Spring Boot? I've read some articles, how to get ApplicationContext:
> public class A implements ApplicationContextAware {
>
> private ApplicationContext applicationContext;
>
> #Override
> public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
> this.applicationContext = applicationContext;
> }
>
> }
But which exactly implementation of Application Context is used in Spring Boot?
The entry point of a Spring Boot application is a SpringApplication object. You can choose which implementation to use through its setApplicationContextClass(Class) method. Its javadoc states
Sets the type of Spring ApplicationContext that will be created. If
not specified defaults to DEFAULT_SERVLET_WEB_CONTEXT_CLASS for web
based applications or AnnotationConfigApplicationContext for non web
based applications.
which lists the defaults if you don't use that method, ie.
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
for web based applications and
org.springframework.context.annotation.AnnotationConfigApplicationContext
for non web based applications.
There's also a default for reactive web environments.
Spring boot creates a new type of ApplicationContext called WebServerApplicationContext which integrates with the embedded server. It further divides into two implementation categories , one for the Servlet Stack (ServletWebServerApplicationContext) and other is for the Webflux reactive stack (ReactiveWebServerApplicationContext).
The noticeable differences of this new context is that it will create and manage the embedded server during bootstrapping the context. So you can see this context will return a WebServer which has the following interface.
public interface WebServer {
void start() throws WebServerException;
void stop() throws WebServerException;
int getPort();
}
The WebServer can be a JettyWebServer ,NettyWebServer ,TomcatWebServer, UndertowWebServer or etc depending of which embedded server are found in the classpath.
It depends on your classpath, for example if you are creating a web application it will probably be an AnnotationConfigWebApplicationContext
Get you ApplicationContext and apply the method getClass() on it to check wich implmentation it is.
Related
Hope I am making sense... my understanding is that there are DispatcherServlet and ContextLoaderListener, and DispatcherServlet creates servlet application context. And ContextLoaderListener creates root application context, which belongs to the whole application (kind of a global thing). The idea is to put "web beans" in servlet context and "non-web beans" in root application context.
Now, my questions are:
is this root application context created no matter what? In other words, do I always get this root application context and servlet context, even I am not creating the root context explicitly? For example, if I use the simplest way to start the app,
#SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
does Spring boot framework still create the root context?
If I want to manually control/configure ContextLoaderListener, for example,
public class MyContextLoaderListener extends ContextLoaderListener { ... }
how can I accomplish that without using any web.xml configuration (use Java config only)?
Having been search on the Web, but still could not put a whole picture together.
Many thanks.
Hi i want to know what are the different ways to get ApplicationContext Object in Spring?
I know only one way that is,
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
is there any other ways? if it is please let me know.
Thanks.
You can also use annotation based configuration
#Configuration
public class Config {
#Bean
public Bean1 bean1() {
return new Bean1();
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
}
}
You can implement the interface ApplicationContextAware, like this :
public class MyClass implements ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
If you are using annotation, you could also autowire it
#Autowired
private ApplicationContext applicationContext;
Also, the code you wrote does not get an existing application context, it creates one.
Well, there are a lot of ways out there, I wonder whom would know them all...
But first, we need to make a difference between instanting a new context, or getting a running and existing application-context.
By new ***ApplicationContext a new context will be created. Therefore all Subclasses of org.springframework.context.ApplicationContext can be used to create a new ApplicationContext. You can find all implementing classes here. The new way to instantiate a spring-context is through AnnotationConfigApplicationContext.
Also, you can add a displatcher-servlet or an servlet-listener in your web.xml. Or use a framework like gemini-blueprint in an osgi-environment which starts all xml-files in meta-inf/spring. (e.g. eclipse virgo)
On the other hand, you can get an existing context (which means not a new one) through different ways:
ApplicationContextAware
Implement the ApplicationContextAware interface and you will get the context via setApplicationContext(ApplicationContext applicationContext) method.
Just add #Autowired private ApplicationContext applicationContext; to your spring bean. But make sure it is a spring bean.
In your web-application, you can get the context of your listener-context via ApplicationContextUtils.getWebApplicationContext( servletcontext)
There would a lot of more ways, but these are those which popped up in my mind quickly.
If you are referring to the possible way you can create an ApplicationContext and not to the ways such an instance can be passed through your code then I suggest taking a look at the Spring javadoc for ApplicationContext. So based on this the concrete implementations of this interface are:
org.springframework.context.annotation.AnnotationConfigApplicationContext
Standalone application context, accepting annotated classes as input - in particular #Configuration-annotated classes, but also plain #Component types and JSR-330 compliant classes using javax.inject annotations. Allows for registering classes one by one using register(Class...) as well as for classpath scanning using scan(String...).
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
This is essentially the equivalent of AnnotationConfigApplicationContext for a web environment.
org.springframework.context.support.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 (e.g. "mypackage/myresource.txt"). Useful for test harnesses as well as for application contexts embedded within JARs.
org.springframework.context.support.FileSystemXmlApplicationContext
Standalone XML application context, taking the context definition files from the file system or from URLs, interpreting plain paths as relative file system locations (e.g. "mydir/myfile.txt"). Useful for test harnesses as well as for standalone environments.
org.springframework.context.support.GenericApplicationContext
Generic ApplicationContext implementation that [...] does not assume a specific bean definition format
org.springframework.context.support.GenericXmlApplicationContext
Convenient application context with built-in XML support. This is a flexible alternative to ClassPathXmlApplicationContext and FileSystemXmlApplicationContext, to be configured via setters, with an eventual AbstractApplicationContext.refresh() call activating the context.
org.springframework.context.support.GenericGroovyApplicationContext
An ApplicationContext implementation that extends GenericApplicationContext. [...] Consider this as the equivalent of GenericXmlApplicationContext for Groovy bean definitions, or even an upgrade thereof since it seamlessly understands XML bean definition files as well.
org.springframework.web.context.support.GenericWebApplicationContext
Subclass of GenericApplicationContext, suitable for web environments.
org.springframework.web.context.support.GroovyWebApplicationContext
WebApplicationContext implementation which takes its configuration from Groovy bean definition scripts and/or XML files, as understood by an GroovyBeanDefinitionReader. This is essentially the equivalent of GenericGroovyApplicationContext for a web environment.
org.springframework.jca.context.ResourceAdapterApplicationContext
ApplicationContext implementation for a JCA ResourceAdapter. Needs to be initialized with the JCA BootstrapContext, passing it on to Spring-managed beans that implement BootstrapContextAware.
org.springframework.context.support.StaticApplicationContext
ApplicationContext implementation which supports programmatic registration of beans and messages, rather than reading bean definitions from external configuration sources. Mainly useful for testing.
org.springframework.web.portlet.context.StaticPortletApplicationContext
Static Portlet-based ApplicationContext implementation for testing. Not intended for use in production applications.
org.springframework.web.context.support.StaticWebApplicationContext
Static WebApplicationContext implementation for testing. Not intended for use in production applications.
org.springframework.web.portlet.context.XmlPortletApplicationContext
Portlet-based WebApplicationContext implementation which takes its configuration from XML documents, understood by an XmlBeanDefinitionReader.
org.springframework.web.context.support.XmlWebApplicationContext
WebApplicationContext implementation which takes its configuration from XML documents, understood by an XmlBeanDefinitionReader. This is essentially the equivalent of GenericXmlApplicationContext for a web environment.
Let's say I've create a annotation called #EnableFeauture which imports a bean configuration class EnableFeatureConfiguration. This annotation is typically placed on top of the dispatcher configuration. Must beans like view resolvers etc. belong to that dispatcher config but a few beans really belong to the root context.
How can I define those beans without the need for another annotation? My first thought was to autowire the WebApplicationContext and call context.getParentBeanFactory() to register beans but I'm not sure if this is the best way to achieve my goal. How is this typically done?
UPDATE
To clarify the problem a bit. I'm working on a project to integrate a template engine with Spring MVC. The project consists of the following categories / parts:
Configuration
Annotation e.g. EnableFeature (imports configuration)
View
ViewResolver
Template factory
Logically all class categories could exist in the web application context. However, the template factory could be used by other services as well (e-mail, etc.). Services that mostly exist in the root context. So what I'm basically asking is, how can I make the factory available to the root context in a clean way. I would like the configuration required to be as low as possible. As of now the setup only requires one annotation placed on top of the dispatcher configuration class.
It took me some time to clearly understand what you want to do and the implications beyond. Finding the root application context from the servlet one would be the easy part, context.getParentBeanFactory(), or directly context.getParent() gives it immediately in any ApplicationContextAware class, or through direct injection of the ApplicationContext.
The hard part, is that at the time of initialization of the servlet application context, the root application context has already been refreshed. If I look at what happens in Tomcat :
at deploy time the root application context is fully initialized and refreshed
next, at first request for the DispatcherServlet the child context is initialized with root context as parent.
That mean that when servlet context is initialized, it is way too late to inject beans in root context : all singleton beans have already been created.
There may be workaround, all with their own flaws :
register a new Configuration class in parent context and do a new refresh().IMHO, this would be the least bad solution as normally WebApplicationContextes support multiple refresh. The potentials problems are :
all other beans must be initialized once without the new beans : the configuration must be tolerant to non existing beans
other components (filters, security, DAO, etc.) may already be running, and they have to be thoroughly tested against a hot context refresh
create an intermediate ApplicationContext with current root as parent containing beans that should not go into servlet application context, and then create the servlet application context with this intermediate context as parent.
no problem for the root application context that is not even aware of the whole operation
but no bean of root context can be injected with any new bean
register all new beans directly in root context. Ok, all is fine for root initialization, and beans of servlet context will have access to all beans. But if one new bean need to be injected with a bean from servlet context, you will have to to it manually at servlet context initialization, with careful tests (or prayers) that it cannot be used before that ... and you will have some pollution of root context with beans only relevant for the servlet
use only only root context and an empty servlet context.
ok, each bean has access to any other one
but it breaks the separation between root and servlet context and adds some pollution to the root context
My conclusion is that having a single piece of configuration for 2 different application contextes is a little against Spring philosophy and I would advice you to keep with 2 separate configuration classes one for the root context and one for the servlet context. But if you wish, I can elaborate on the refreshing of root context from servlet context (1st solution).
If you want to inject beans into root context from a feature that would be declared in servlet context to have a single configuration point, you can use something like:
#Configuration
public class FeatureConfig implements ApplicationContextAware {
static boolean needInit = true;
#Override
// Register the configuration class into parent context and refreshes all
public void setApplicationContext(ApplicationContext ac) throws BeansException {
AnnotationConfigWebApplicationContext parent =
(AnnotationConfigWebApplicationContext) ((AnnotationConfigWebApplicationContext) ac).getParent();
if (needInit) { // ensure only one refresh
needInit = false;
parent.register(RootConfig.class);
parent.refresh();
((AnnotationConfigWebApplicationContext) ac).refresh();
}
}
#Configuration
#Conditional(NoParentContext.class)
// Can only be registered in root context
public static class RootConfig {
// configuration to be injected in root context ...
}
// special condition that the context is root
public static class NoParentContext implements Condition {
#Override
public boolean matches(ConditionContext cc, AnnotatedTypeMetadata atm) {
logger.debug(" {} parent {}", cc.getBeanFactory(), cc.getBeanFactory().getParentBeanFactory());
return (cc.getBeanFactory().getParentBeanFactory() == null);
}
}
// other beans or configuration that normally goes in servlet context
}
With such a #Configuration class it is enough to have a #import(FeatureConfig.class) annotation in a configuration class for the application context of the DispatcherServlet.
But I could not find any way to allow the configuration to happen before the normal servlet application context initialisation. An outcome is that any bean from the special configuration can only be injected in root context with a #Autowired(required=false), because the root context will be refreshed twice, first time without the special configuration class, second time with it.
As I understand all you have to do is to provide custom configuration that will be imported by annotating #Configuration class by #EnableFeature. Then you just have to include custom beans in your EnableFeatureConfiguration class.
#Configuration
public class EnableFeatureConfiguration {
#Bean
public MyBean myBean() {
return MyBean();
}
}
Then your EnableFeature looks like:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Import(EnableFeatureConfiguration.class)
public #interface EnableFeature {
}
And that's all. In project you have to use:
#Configuration
#EnableFeature
public class MySpringConfig {
}
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'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);