[New to Spring]
There is a service that is Spring enabled and does some stuff. When this service starts up, it loads the Spring Application context and everyone is happy.
Now, I need to create a library that will be used by the above mentioned service and I want to Springify this library package as well. But then, when/how does this library's application context get initialized? Am stumped!
I assume many people must have done this. What is the best practice?
I was thinking, may be a static block in the library's entry point interface is the right place to initialize the application context? (so, it gets init only once)
Is that the right approach? Is it even going to work or am missing I something? Appreciate your help.
You can give as many applicatoin context xml files as you want, If you are using the library in a web application,
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:context1.xml
classpath:context2.xml
...
</param-value>
</context-param>
basically you need to provide the relative path classpath:<relativepathofcontextfile>.
If it is inside a jar file and your jar is in classpath the above one works.
If it is for standalone, You can use ClassPathXmlApplicationContext.
public class SomeClass {
private static final ApplicationContext ac=
new ClassPathXmlApplicationContext("classpath:context1.xml");
public static void main(String[] args) {
MyIntf bean= (MyIntf) ac.getBean("myBean");
bean.myMethod();
}
}
No, with using static block you are enforcing Spring context to load disregard the fact that it might be loaded yet in another classloader. So the good approach would be to provide some factory method to get business objects, which will track if the context is loaded yet and create one if necessary. Or use pre-existing context.
Also it might be a good idea to review Service Locator pattern and http://docs.oracle.com/javase/1.4.2/docs/guide/jar/jar.html#Service%20Provider
Related
I have been trying to wrap my head around IoC and dependency injection. I think I am starting to understand the benefit of dependency injection in large apps. If I'm correct in understanding, dependency injection is beneficial when you have consistent interfaces, as you'll be able to only change an implementation without having to change your whole app.
What I don't understand is where XML comes into all of this (And I know there are other IoC methods like annotations now, but unless the answer is "XML sucks and you should use annotations", let's not go there yet).
What is the difference between managing this:
public class MyApp {
public static void main(String[] args) {
ItemFinder theQuarterFinder = new QuarterItemFinder();
FortuneService theFortune = new HappyFortuneService(theQuarterFinder);
Coach theCoach = new WrestlingCoach(theFortune);
System.out.println(theCoach.getDailyWorkout());
System.out.println(theCoach.getDailyFortune());
System.out.println(theCoach.getItem());
}
}
And managing this with an xml:
public class HelloSpringApp {
public static void main(String[] args) {
//Load spring configuration file
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
//Retrieve bean from spring container
Coach theCoach = context.getBean("myCoach", Coach.class);
System.out.println(theCoach.getDailyWorkout());
System.out.println(theCoach.getDailyFortune());
System.out.println(theCoach.getItem());
context.close();
}
}
<bean id="myItemFinder" class="com.luv2code.springdemo.QuarterItemFinder">
</bean>
<bean id="myFortune"
class="com.luv2code.springdemo.HappyFortuneService">
<constructor-arg ref="myItemFinder" />
</bean>
<bean id="myCoach" class="com.luv2code.springdemo.WrestlingCoach">
<constructor-arg ref="myFortune" />
</bean>
If I were to change the itemFinder implementation, I would be changing exactly the same amount of code, only doing it in an XML file vs the main app function. Is that really preferable? Trying to track down refs in XML seems worse to deal with than just changing one of the "new" calls in MyApp.
If I'm understanding correctly, both examples do dependency injection. One just moves the logic out of app and into an XML file. and creates Spring Beans. But we are kinda making beans even without an XML context, correct?
Here's an excerpt from section 12.2.1 of Dependency Injection Principles, Practices, and Patterns which explains the advantages and disadvantages of using (XML) configuration files.
12.2.1 Configuring containers with configuration files
When DI Containers first appeared back in the early 2000s, they all used XML as a configuration mechanism — most things did back then. Experience with XML as a configuration mechanism later revealed that this is rarely the best option.
XML tends to be verbose and brittle. When you configure a DI Container in XML, you identify various classes and interfaces, but you have no compiler support to warn you if you misspell something. Even if the class names are correct, there’s no guarantee that the required assembly is going to be in the application’s probing path.
To add insult to injury, the expressiveness of XML is limited compared to that of plain code. This sometimes makes it hard or impossible to express certain configurations in a configuration file that are otherwise trivial to express in code [...]
The advantage of configuration files, on the other hand, is that you can change the behavior of the application without recompilation. This is valuable if you develop software that ships to thousands of customers, because it gives them a way to customize the application. But if you write an internal application or a website where you control the deployment environment, it’s often easier to recompile and redeploy the application when you need to change the behavior.
To summarize: (XML) configuration files are (only) valuable in late-binding scenarios, where the types are unknown at compile-time, which most likely happens when allowing an application to be extended using plug-ins.
I am trying to use the picoContainer in my project.
I know very little about it but want to give it a shot.
As I understand, I have to create a picoContainer and registercomponents with it.
I did this
public static PicoContainer getPicoContainer(){
final MutablePicoContainer pico = new DefaultPicoContainer();
pico.registerComponentImplementation(X.class);
pico.registerComponentImplementation(A.class);
pico.registerComponentImplementation(C.class);
pico.registerComponentImplementation(V.class);
pico.registerComponentImplementation(T.class);
pico.registerComponentImplementation(D.class);
return pico;
}
Now my problem is that for any component to get the other component, it needs a handle on pico.
To access any component it needs to do this
A juicer = pico.getComponent(A.class);
So, in the constructor for each of them, I need to pass in the pico object? I can easily replace this with a factory. What's the point then? I'm sure i'm missing something here.
Would appreciate any help.
Common pattern is to have somewhere a factory for the main container.
For stand-alone app it probably will be "public static void main()" entry point, for web app it will be front controller servlet or filter or context listener (pico has support class for listener case).
So at the entry point you configure the container in a way you mentioned above "public static PicoContainer getPicoContainer()" then you need to pass control to an entry point in the container. The nice way is to have at least one container's component to implement lifecycle interface (http://picocontainer.codehaus.org/lifecycle.html) then you start() the container and have everything wired up.
In normal case you should never access the container itself beside entry configuration and such things as special factories or transaction demarcation etc.
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: [...]
I have a Spring web application with two contexts: one (applicationContext) built by ContextLoaderListener and a second (webContext) built by DispatcherServlet.
Within the applicationContext is a bean (org.springframework.security.authentication.DefaultAuthenticationEventPublisher) that fires spring context events.
But the receiver for the event is defined in the webContext. And that receiver did not get the event. (If put the receiver for test purpose in the applicationContext then it get the event, but I can not do this, because I need the webContexts for its functionality.)
So my question is, how to bridges the events from the applicationContext to webContext?
I had the same problem, solved mine by moving the beans creating the event to web-context. However you can solve your problem by manually wiring your event listener, something like this (this code is not compiled therefore it is untested):
#Component
public class BeanInWebContext implements ApplicationListener<SomeEvent> {
#Autowired
private ApplicationContext webContext;
#PostConstruct
public void registerAsListener() {
// get parent context
AbstractApplicationContext appContext = (AbstractApplicationContext) webContext.getParent();
// register self as a listener, this method is in AbstractApplicationContext
appContext.addApplicationListener(this);
}
#Override
public void onApplicationEvent(SomeEvent event) {
}
}
I think the actual answer is that you may want to configure your app differently (so that you only have one context)
I think in your web.xml you need to do something like this :
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:/META-INF/applicationSpringConfig.xml
</param-value>
</init-param>
</servlet>
But to answer the deeper question. Someone else points out that you can use includes in your spring file (indeed in the above you can have more than one springconfig specified in your dispatcher servlet).
But when you include other context files you do not share instances of beans, only definitions.
Modularising Spring applications has been the only real downside of spring in comparison with EJB etc. That led spring into using OSGi.
And the answer to your underlying question of how to share spring context, officially you share spring bean instances between contexts using OSGi (spring dm)
Try moving the event publisher to the web context file, where it should have visibility over the whole application context. A similar issue occurs when configuring method security in the parent application context. The parent application context (loaded by ContextLoaderListener) isn't aware of the child (web) context.
You can also use a single application context for the entire application if you don't really need the parent-child relationship between the two. Often it just gets in the way and it is easier if all beans were defined in the same space.
As stated in documentation for the spring framework the simple ApplicationEvent mechanism is only designed to be used within the same application context, I am not aware that it is possible to propagate events to child contexts.
If you need a more advanced solution you might look into using a more enhanced solution like Java Message Service or Spring Integration.
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#context-functionality-events
We can use the import tag to import/bridge the 2 different contexts created in a way the visibility of the events/beans are available and shared.
<import resource="applicationContext_name.xml"/>
In this import the context xml which is configured to be created from ContextLoaderListener in the context xml of the DispatcherServlet.
I am extracting some functionality from an existing program into a separate library.
This program uses Spring for dependency injection and other tasks and I'd like to keep using it in the library as well.
This library needs to monitor the filesystem for changes, so it will kick off some kind of separate thread to do this.
I don't really know what my options are for initialisation of the library:
How do I initialise the library's context? I cannot assume that library users will make use of Spring too, but I can distribute Spring with the library.
How do I manage my filesystem monitoring thread? Is it good design to expect the program to instantiate a main class of the library and the call init or something like that?
How do I initialise the library's context? I cannot assume that
library users will make use of Spring too, but I can distribute Spring
with the library.
I am writing a library using Spring context as well and I did something like that, assuming your library is called FooLib, has two services called FooService and BarService and a class called SpringContext that configures your spring context through java config:
public final class FooLib {
private static ApplicationContext applicationContext;
private FooLib() {
}
public static FooService getFooService() {
return getApplicationContext().getBean(FooService.class);
}
public static BarService getBarService() {
return getApplicationContext().getBean(BarService.class);
}
private static ApplicationContext getApplicationContext() {
if (applicationContext == null) {
applicationContext = new AnnotationConfigApplicationContext(SpringContext.class);
}
return applicationContext;
}
}
Then a client can use BarService this way:
BarService barService = FooLib.getBarService();
How do I manage my filesystem monitoring thread? Is it good design to
expect the program to instantiate a main class of the library and the
call init or something like that?
You can start your monitoring subsystem statically within Spring context, inside the SpringContext class, for example.
#Configuration
#ComponentScan(basePackages = "com.yourgroupid.foolib")
public class SpringContext {
#Bean
public MonitoringSystem monitoringSystem() {
MonitoringSystem monitoringSystem = new MonitoringSystem();
monitoringSystem.start();
return monitoringSystem;
}
}
That should be enough because Spring creates its beans eagerly by default.
Cheers
How do I initialise the library's context? I cannot assume that library users will make use of Spring too, but I can distribute Spring with the library.
It's up to your library to instantiate spring the way you need it. This is typically done in your interface entrypoint which delegates to a routine using e.g., ClassPathXmlApplicationContext to configure spring. A sample could be
public class SpringContextLoader {
private static ApplicationContext ctx = null;
public static void init() {
if (ctx == null) {
ctx = ClassPathXmlApplicationContext("classpath:/applicatonContext.xml");
}
}
}
How do I manage my filesystem monitoring thread? Is it good design to expect the program to instantiate a main class of the library and the call init or something like that?
In this case you will probably provide a non-daemon thread, e.g., a thread which must be terminated manually for the application to exit cleanly. Hence you should provide start and stop mechanisms. In your case these probably better be called registerEventListener and unregisterAllEventListener (since I'm guessing you want to pass filesystem events to the client ... ). Another alternative could be to use quartz scheduling with spring.
How do I initialise the library's context? I cannot assume that library users will make use of Spring too, but I can distribute Spring with the library.
You can use a PropertyPlaceholderConfigurer to read configuration settings from a (possibly external) property file, which can be edited by the users. This way users aren't exposed to the details of Spring, not even to XML config files.
How do I manage my filesystem monitoring thread? Is it good design to expect the program to instantiate a main class of the library and the call init or something like that?
I recommend using the Java concurrency framework, specifically a ScheduledExecutorService to run monitoring task(s) at specified intervals. However, you may want to hide this implementation detail from the users of your library, by only exposing some init method to pass in the desired timer interval.
As far as I know, it is not possible to configure your library to start a thread automatically, you have to define a class as starting point. Using Maven you can create an executable jar:
http://maven.apache.org/plugins/maven-shade-plugin/examples/executable-jar.html
In your main class, simple use:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:myspring-context.xml");
context.registerShutdownHook();
For threads, you can try either implementing the runnable interface, and initialize a bean which starts the threads using spring task executors. A more elegant solution that I can suggest is however creating your thread as a pojo and then using spring task scheduler, as follows:
<bean id="threadPojo" class="com.mydomain.ThreadPojo">
</bean>
<task:scheduled-tasks scheduler="mydomainTaskScheduler">
<task:scheduled ref="threadPojo" method="process" fixed-delay="${delay-pool}"/>
</task:scheduled-tasks>
<task:scheduler id="mydomainTaskScheduler" pool-size="${my-pool-size}" />
I hope it will be helpful.