application context. What is this? - java

My colleagues very often use word "application context". In many articles this collocation used very often too.
My current understanding: application context is single xml file.
But I understand that if I was right, people wouldn't use "application context" instead of configuration xml file.
Can you help me to deal with this issue?

#feak gives a straight answer about the meaning of ApplicationContext in terms of Spring. In short, it is an object that loads the configuration (usually a XML file annotation based) and then Spring will start managing the beans and its benefits:
Beans declared in package
Beans declared by annotations
Constructor and method autowiring
Bean injection
Configuration, .properties and .yaml file loading
etc
To start an application context, you may use one of the following:
Manually load the application context at the beginning of your application. This is done for sample purposes or in standalone applications:
public class Foo {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("path/to/applicationContext.xml");
//use the context as you wish...
}
}
In case of Java web applications using Spring MVC, the DispatchServlet will load the application context for you, so you only have to create a springapp-servlet.xml file in WEB-INF folder of the application.
Note that an application context is associated to a single configuration (XML based or not). Period.
After understanding this, you could also understand that you can have more than a single application context per application. This is, having two or more ApplicationContexts in the same application. From the last example in the console application, this is easy to check:
public class Foo {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("path/to/applicationContext.xml");
ApplicationContext context2 =
new ClassPathXmlApplicationContext("path/to/applicationContext.xml");
//use the context as you wish...
}
}
Note that we have two application contexts using the same XML configuration. Can you do this? Yes, you're actually seeing it here. What's the difference, then? The main difference is that Spring beans singleton scopes are singleton per application context, this mean when retrieving a Bar bean that's configured in applicationContext.xml file from context will not be the same as retrieving it from context2, but several retrieves from context will return the same Bar bean instance.
Is this considered a good or bad practice? Neither, it will depend on the problem to be solved (in case of last example, I would say it is a bad practice). Most people would recommend having all your beans configured in a single place (via XML or another) and loaded by a single application context.

Let's understand this in simple words.
The ApplicationContext is the central interface within a Spring application that is used for providing configuration information to the application. It's created when the application starts running.
It provides the entire configuration needed by our application:
Bean Factory - Responsible for creation of java objects called beans. One example is components in the application.
Application listeners - all listeners needed for events.
WebServer information.
Application current environment specific information.
Resource pattern resolver - resource loader with path matcher.
Life cycle Processor.
Class Loader.
Start and shutdown monitor.
Servlet Context.
Reader and Scanner.
Logger
etc.
package com.srmhitter9062.spring;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
We can get some idea about the Application object in below snapshot.
In summary, we can say the Application context is a Configuration object created for application to run.
The applicationContext.xml defines the beans for the "root webapp context". It's a web aware ApplicationContext.
It is used to have beans that are shared between all servlets in a web application.
I hope this is helpful.

I guess that you colleagues meant the loaded spring application context, which allows access to:
configuration of application,
initialized beans,
application events api,
etc

From the javadoc:
Central interface to provide configuration for an application. This is
read-only while the application is running, but may be reloaded if the
implementation supports this.
An ApplicationContext provides: [...]

Related

Injecting singletons in to a Spring Boot Application Context

I want to inject some non-Spring managed beans in to a Spring Boot Application. I would have thought the way to do this would be something like:
GenericApplicationContext parentContext = new StaticApplicationContext();
parentContext.getBeanFactory().registerSingleton("pipeline", pipeline);
parentContext.refresh(); // seems to be required sometimes
ApplicationContext context = new SpringApplicationBuilder()
.sources(parentContext)
.child(DispatcherApplication.class)
.run();
However you can only pass in Class<?>... or Object... to the sources method on the builder and in the latter case the only values it recognises are:
Class - A Java class to be loaded by AnnotatedBeanDefinitionReader
Resource - An XML resource to be loaded by XmlBeanDefinitionReader, or a groovy script to be loaded by GroovyBeanDefinitionReader
Package - A Java package to be scanned by ClassPathBeanDefinitionScanner
CharSequence - A class name, resource handle or package name to loaded as appropriate.
So how do I either pass in a parent context instance, or inject singletons in to a Spring Boot application before startup?
TIA
You don't have to create application with your modified context using Application Builder.
Simply make sure you Autowire parentContext and register singleton on the factory derived from it
i couldn't get your parent context approach to work, for more or less the same reason you stated. instead, i:
annotate the bean with #Lazy and #Autowired
create an anonymous ApplicationListener
in the listener call getBeanFactory().registerSingleton()
add the listener to the app with setListener()
here's the stripped-down listener:
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
((GenericApplicationContext) (((ContextRefreshedEvent) event)
.getApplicationContext()))
.getBeanFactory().registerSingleton("legacyBean", obj);
}
}
i didn't find too much documentation on the application lifecycle, but at least most of what i'm doing is standard. however, it does rely on a cast of the context to GenericApplicationContext which "works for me" (Spring Boot 1.4.1) and seems safe, but in theory could change in future versions
my blog post with full source:
http://blog.nqzero.com/2018/01/integrating-spring-with-legacy-app.html

spring-boot - Which piece of code actually register dispatcher servlet for springMVC?

I am trying to find out in spring-boot, which implementation of WebApplicationInitializer actually register the dispatcher servlet.
I didn't found any piece code from SpringBootServletInitializer or its parent types did that.
Instead, AbstractDispatcherServletInitializer does the job, but it's abstract, I can't find any of its concrete implementation with help of Eclipse.
So, which piece of code from which class is actually invoked to register the dispatcher servlet for springMVC?
This is a subsequent question of: How does spring-boot able to serve specific url?
Below is the description of Spring Boot initialization steps that eventually register DispatcherServlet.
Example Code
#EnableAutoConfiguration
public class TestSpring {
public static void main(String[] args) throws Exception {
SpringApplication.run(TestSpring.class, args);
}
}
Spring Boot Initialization Steps
Here are the steps:
SpringApplication.run() creates EmbeddedWebApplicationContext application context;
Calls its refresh() method;
Refresh process reads annotations of the starting class TestSpring. It looks for import annotations. EnableAutoConfiguration is one of them. For an import annotation the refresh process gets the corresponding class from the annotation value and invokes its selectImports() method;
In case of #EnableAutoConfiguration the corresponding class is EnableAutoConfigurationImportSelector whose selectImports() loads tons of other import selectors from the META-INF/spring.factories;
This process continues recursively. Also, all bean definitions, that are inside these import selectors, are read. I.e. it includes beans defined by a method with the #Bean annotation, i.e. beans that require the Spring context to call the corresponding method automatically to instantiate them;
The resfresh() continues and reaches onRefresh(), the createEmbeddedServletContainer() method is called inside;
Among read bean defitions at the previous step, beans implementing ServletContextInitializer are searched for and instantiated. One of them is the bean, defined by the DispatcherServletAutoConfiguration.DispatcherServletRegistrationConfiguration#dispatcherServletRegistration() method of ServletRegistrationBean type that extends ServletContextInitializer. As you can guess from the name of the class, such initializers add a given servlet (in this case DispatcherServlet) to a given ServletContext, when their onStartup() method is invoked;
A tomcat embedded server is created (not started completely yet). All found ServletContextInitializers at the previous step are passed to this tomcat initialization - this is where the onStartup() methods of those ServletContextInitializers are called and DispatcherServlet gets created and registered as servlet;
End of onRefresh() of application context;
The finishRefresh() is called where tomcat is finally started by TomcatEmbeddedServletContainer.start();
End of refresh() of application context and other final initialization steps;
The app is running.
When you look for something Spring Boot does during auto-configuration, you should look in the *AutoConfiguration classes. In this case, DispatcherServletAutoConfiguration.
If you want to deploy the Spring Boot application as a traditional WAR, then the Servlet 3.0 specification details how service providers can set it up so that the 3.0 compliant servlet container will automatically bootstrap any web assets (Servlet, Filter, ServletContextInitializer's) into the servlet container. The "magic" is accomplished in the spring-web dependency. If you un'jar it, you'll find file "spring-web/META-INF/services/javax.servlet.ServletContainerInitializer". Open the file and you'll see single line "org.springframework.web.SpringServletContainerInitializer". This class delegates to all classes that implement WebApplicationInitializer, more specifically their onStartup(ServletContext servletContext) method. There's one such concrete class I'm aware of in Spring Boot, namely SpringBootServletInitializer.

Run code after Spring context has been initialized in web app deployed on Tomcat

I have a web application which I package as a war and I deploy on tomcat 7.
This is a Spring MVC application that I want to add a Quartz scheduler to it. I want to run code that will make use of various Spring beans and populates the scheduler with Jobs that are configured dynamically so I need access to various Beans in code like
#Autowired
private CronDAO cronDAO;
public void loadCronJobs(final Scheduler scheduler) {
LOGGER.info("Vas[{}]: Loading Cron Schedule...", vasName);
final List<Cron> crons = cronDAO.fetchAll();
final Long cronSid = cron.getSid();
final String directive = cron.getDirective();
final String expression = cron.getCronExpression();
...
}
Normally I would put the initialization code for the scheduler in the main function of the application and would use Autowired beans for my application logic. Now with the application server initializing the application I cannot do this.
I tried to add my code to the startup function of the servlet but the Spring context is not yet ready so the autowired beans (the DAO in this example) fail to load.
public class MyWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
CronManager cron = new CronManagerImpl();
cron.loadCronJobs();
}
}
Is there a way to run code (not only quartz related) when the application start in the container but the Spring context to be complete?
You can write a 'ServletContextListener' and register it in the web.xml. In your implementation you can rely on spring frameworks WebApplicationContextUtil to get a handle to the spring application context.
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.springframework.web.context.support.WebApplicationContextUtils;
public class QuartzInitiator implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) {
WebApplicationContextUtils.getRequiredWebApplicationContext(servletContextEvent.getServletContext())
.getAutowireCapableBeanFactory().autowireBean(this);
//your logic
}
}
Autowired fields would be correctly initialized by the Util.
Spring is great at avoiding you do deal with low level questions.
At higher level you have :
a number of beans declared in Spring application context
an initialization procedure that must be run
after the beans have been initialized
before the rest of code is run
Well simply declare a new bean in which you inject all the other beans, and do your initialization in the init-method of that last bean. Spring guarantees that this method is called at context initialization time after all dependant beans have been initialized.
That way is totally independant of whether your application is a web application or not : is becomes spring framework's problem and no longer yours.

Startup the Spring application by #Configuration

I found this piece of code in my codebase. Actually the class:
package my.services.config;
#Configuration
#ImportResource("classpath:spring/*.xml")
#ComponentScan("my.services.jms.server")
public class MyServicesConfiguration {
#Bean
public ApplicationLifecycle lifecycle() {
return new MyServicesLifecycle();
}
}
I'm trying to understand:
So, it uses all spring/*.xml files/beans before/while staring up, then it injects ApplicationLifecycle bean into the spring context (along with other beans from spring/*xml and from beans from 'my.services.jms.server' packages). So, in the end we gonna have one global context with all beans (?)
The question: How does it possible to launch this application (if, as I understand this class is only one entry point to the app) ?
It's gonna be some main(String[] args) {} function that would able to launch it by 'my.services.config' path, let's say, as an argument.
So, in the end we gonna have one global context with all beans (?)
That's right. From Spring perspective #Configuration class is just a different way to define beans, equivalent to XML. Both Java configuration and XML configuration is merged and treated equally later.
And this is how you can start you context from withing main():
ApplicationContext ctx =
new AnnotationConfigApplicationContext(MyServicesConfiguration.class);
and later:
ApplicationLifecycle applicationLifecycle =
ctx.getBean(ApplicationLifecycle.class);

Spring: how to get hold of Application context in Webapp and Standalone program

I'm new to the Spring Framework. We want to introduce it (3.1) in a web application, currently using struts in the web layer, service facades and business objects in the business layer and self-written JDBC DAOs in the persistence layer (all of it closely coupled!)
I created several .xml configurations, one for the servlet config, scanning the com.mydomain.web package only. Another one on the service layer appContext-service.xml which scans com.mydomain.bs and .bo packages and one for the DAO layer appContext-persistence.xml scanning the .dao package.
We have four Eclipse projects with appropriate project dependencies: Web, Business, Common (contains domain objects, DTOs, Exceptions, etc), DataAccess.
I want to use annotations where possible and already created a MVC controller, a new service with interface and a new dao with interface, using the JDBC template, which all works great.
Now my questions are:
We can't re-write all the code at once, we're talking about a larger code base here. But what do I do, when the newly created service is also needed from services and business objects that are not (yet) Spring aware? They're not beans or not being created by Spring. How would I get hold of my service bean?
We have several standalone applications for batch processing, cleaning up the file system and database tables periodically, etc. They're triggered by cron (UNIX cron) and therefore have their own JVM. How would I best use Spring services here, given the different .xml configurations?
Does my setup make any sense at all?
Thanks for any insight.
It's very common that one let spring handle the lifecycle of all the beans, otherwise it might get a bit tricky. The objects that are not spring beans are hopefully initialized somewhere. Make that initializer a spring bean and make it application context aware
public class SpringContextHolder implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
public void init(){
ServiceBean1 srv1 = (ServiceBean1)applicationContext.getBean("serviceBean1");
myNonSpringObject.setService1(srv1); // Or something
}
}
Setting up a standalone spring app is very easy. Just create a Spring XML and wire your beans (either via scanning/annotations or XML). It is not really recommended to do this in the main method, but you could easily figure out how to get this setup in your standalone application. Keep in mind that your application itself should not really do much lifecycle logic but let Spring do that.
public class StandaloneSpringApp{
public static void main(String[] args){
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
SomeBeanType bean = (SomeBeanType)ctx.getBean("SomeBeanName");
bean.doProcessing(); // or whatever
}
}
Your setup makes perfect sense, even though I cannot visualize your entire scope, your approach is a good starting point for a large modularized spring application.

Categories

Resources