In the spring reference documentation
section 2.3 Usage scenarios, there is a paragraph that goes like this
Sometimes circumstances do not allow you to completely switch to a different framework. The Spring
Framework does
not
force you to use everything within it; it is not an
all-or-nothing
solution. Existing
front-ends built with Struts, Tapestry, JSF or other UI frameworks can be integrated with a Spring-
based middle-tier, which allows you to use Spring transaction features. You simply need to wire up your
business logic using an ApplicationContext
and use a WebApplicationContext
to integrate
your web layer.
Now I am not able to understand the last sentence. How can we wire up our business logic using an ApplicationContext and use a WebApplicationContext to integrate with web layer. How can we achieve this? And is the web-layer that they are talking about contains controllers and jsps?
As far as I remember if we needed any object in a class we simply autowire them and spring does the rest of the work.
Can someone please provide an explanation with examples. Please forgive my ignorances as I have just started to learn spring.
If a similar question is asked can someone please point me in the right direction
It is possible, even you can create more than one different context hierarchically.
I will give both answers, both hierarchic and non-hierarchic. I'll use java based configuration for both. I will give the answer for two context but you can implement this for many context.
1)Non-Hierarchic
Create two different context.xml, assume that context1.xml and context2.xml . context1.xml should be like this :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=..... some imports >
<context:annotation-config />
<context:component-scan base-package="desiredPackage1" />
<bean id="properties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>db.properties</value>
</list>
</property>
</bean>
<context:property-placeholder properties-ref="properties"/>
For context2.xml change only
<context:component-scan base-package="desiredPackage2" />
Then create a Configuration.java class like this:
public class Config {
public static void main(String[] args) throws Exception {
ApplicationContext desiredContext1 = new ClassPathXmlApplicationContext("file:////...path.../context1.xml");
ApplicationContext desiredContext2 = new ClassPathXmlApplicationContext("file:////...path.../context2.xml");
}
}
Now you have two different context, if you want to it hierarchically, change the main method like this :
2)Hierarchic
public class Config {
public static void main(String[] args) throws Exception {
ApplicationContext desiredContext1 = new ClassPathXmlApplicationContext("file:////...path.../context1.xml");
String[] congigPath = new String[1];
congigPath[0] = "file:////...path.../context2.xml";
ApplicationContext desiredContext2 = new ClassPathXmlApplicationContext(congigPath,desiredContext1);
}
}
In this case, desiredContext2 object could see desiredContext1 object but desiredContext1 object can not see desiredContext2 object.
If you want to use it when building your web-app use this annotations with you configuration class,
#Configuration
#ImportResource("context1.xml", "context2.xml")
public class Config { ....
I hope this will help to you.
You may setup two or even three different projects or modules each with their own context. For example a web project with WebApplicationContext which is rendering the views and calls business methods i.e. usinf restful web services from business tier. And setup a separate project or module to handle business which has its own context file and beans. And even a commons project to include shared beans between the web and business tier.
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 a developer working on a Java web application that is built on the Spring framework.
This application will be deployed to several different customers.
There is a class which contains some business logic that is different for each client.
From a Spring framework point of view, it is enough to simply wire in the appropriate class (as a bean) for each client.
However, the developers are not responsible for deployment of the application. The Operations team is responsible, and having them open up the WAR file and modify the spring configuration XML for each client deployment is probably too much to ask from them. Properties files are ok, but modifying internal files - probably not.
Has anyone else come up with a strategy for dealing with this?
Edit:
To give an example of what I'm talking about:
public interface IEngine {
void makeNoise();
}
public class Car {
public void setEngine(IEngine engine) {
this.engine = engine;
}
}
Customer A's business logic:
HeavyDutyEngine implements IEngine {
public void makeNoise() {
System.out.println("VROOOM!");
}
}
Customer B's business logic:
LightWeightEngine implements IEngine {
public void makeNoise() {
System.out.println("putputput");
}
}
In the Spring configuration XML:
For client A, it might look like this:
<bean id="hdEngine" class="HeavyDutyEngine" />
<bean id="lwEngine" class="LightWeightEngine" />
<bean id="car" class="Car">
<property name="engine" ref="hdDngine">
</bean>
For client B, it might look like this:
<bean id="hdEngine" class="HeavyDutyEngine" />
<bean id="lwEngine" class="LightWeightEngine" />
<bean id="car" class="Car">
<property name="engine" ref="lwEngine">
</bean>
To configure Spring for different environments, you can use the concept called spring "profiles". (introduced in Spring 3.1)
You have different ways so enable/disable this properties. For example java properties parameter.
But because you are using a WAR, and therefore some Servlet container, I would recommend to put this configuration in the Servlet container.
In a tomcat for example, you can put this line in the context.xml (global or application specific) to enable a profile
<Parameter name="spring.profiles.active" value="myProfile"/>
You can move some configuration to DB, if you are using one.
And you can use something like this
ref="{ref-name}"
where ref-name can be resolved using properties file(default) by configuring PropertyPlaceholderConfigurer.
Or you can write your own wrapper over PropertyPlaceholderConfigurer which will take the values from DB table which is external to you deployable WAR file.
In one of mine project, we used this method to resolve custom dependencies. The wrapper which looks up the DB used to take first priority and if the DB doesn't have the key/value pair, then properties file (bundled in the WAR) was used to resolve dependencies.
This will also allow you to change some value externally from DB, however with IBM Websphere we need to recycle the server for changes to take place.
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.
I am maintaining a large Java EE system. Most of the business logic is converted from EJB:s into POJO:s configured in several spring context configuration files. EJB:s are mostly used as Facades, that looks up the business logic spring beans from a context composed of all spring context configuration files mentioned earlier. For this we use the AbstractStatelessSessionBean provided with the spring framework.
All these configuration files have the default-lazy-init=true directive, which means that the business logic beans are not created until they are actually used by the system. This is preferable most of the time since republishing in developer mode becomes faster.
But when large merges are made, we are having problems finding all the configuration errors, such as missing dependencies.
My idea is to write some form of integration test, with the purpose of finding those errors. This means, i think, that I need to find a way to override all default-lazy-init=true declarations when creating the application context.
Is there any way of doing this programmatically, or perhaps with some test-only context file that includes all the actual context files?
Let's say currently you have a single applicationContext.xml file containing all bean definitions:
<beans default-lazy-init="true">
<!-- all your beans -->
</beans>
Rename it to applicationContext-main.xml or something and remove default-lazy-init="true" attribute. Now create two applicationContext.xml files:
<beans default-lazy-init="true">
<import resource="applicationContext-core.xml"/>
</beans>
and:
<beans default-lazy-init="false">
<import resource="applicationContext-core.xml"/>
</beans>
As you can see the only difference is the value of default-lazy-init. During development your team can use the former version of applicationContext.xml that includes all the beans with lazy-init. On staging and testing environments switch it to the latter so that all beans included in applicationContext-core.xml are created eagerly.
I believe that the best way is to control lazy init of beans is to leave the default-lazy-init out of all config files except the topmost as Tomasz Nurkiewicz suggests. I did however in this case need a quick and dirty fix to verify all bean definitions. (It is a bit of a process to change the lazy init policy.)
I came up with a simple BeanFactoryPostProcessor which seems to do the job:
public class NonLazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
for (String beanName : beanFactory.getBeanDefinitionNames()) {
beanFactory.getBeanDefinition(beanName).setLazyInit(false);
}
}
}
If included in a context file, it will override the lazy init flag set by any included context files.
<beans default-lazy-init="false">
<bean class="example.NonLazyInitBeanFactoryPostProcessor" />
<import resource="applicationContext-core.xml"/>
</beans>
If I try to create a context from the above xml, configuration errors previously hidden by lazy initialization will show up immediately as exceptions.
There is one 'but' in this PostProcessor
for (String beanName : beanFactory.getBeanDefinitionNames()) {
beanFactory.getBeanDefinition(beanName).setLazyInit(false);
}
This for loop will iterate only over top most beans not including e.g internal(local) bean defintions ...
You can't access the scanner from the context - it's completely private, but since you can step into the source code, you can see what's required to set up your own. I used Spring's own ReflectionTestUtils to set my own configured scanner in the context:
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
BeanDefinitionDefaults defaults = new BeanDefinitionDefaults();
defaults.setLazyInit(true);
scanner.setBeanDefinitionDefaults(defaults);
ReflectionTestUtils.setField(context, "scanner", scanner);
context.scan("com.some.path");
You can do this anywhere you have access to the Application Context before the component scan takes place.
As I understand it, Spring MVC application has two distinct contexts, the application context and the web context, which are controlled by applicationContext.xml and dispatcher-servlet.xml, respectively.
Inside my controllers, how do I go about loading a bean into either of these contexts?
Note that I am aware of Getting Spring Application Context. That would answer my question for a stand alone application. Where I would use a factory to load the application context from the xml file, but this seems like the wrong way to go about loading beans in Spring MVC.
Matt is absolutely correct. You should not need with any kind of bean-loading/instantiating code in your MVC application, otherwise you're doing something wrong. You define your beans inside the according spring XML configuration files.
<bean id="pinboardServiceTarget" class="com.lifepin.services.PinboardService">
<property name="pinboardEntryDao" ref="pinboardEntryDAO"/>
</bean>
...
<bean id="pinboardEntryDAO" class="com.lifepin.daos.PinboardEntryDAO">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Your PinboardService class (this is just from an application I wrote recently) will have a property IPinboardEntryDAO like
public class PinboardService implements IPinboardService{
private IPinboardEntryDAO pinboardEntryDao;
...
public void setPinboardEntryDAO(IPinboardEntryDAO dao){
this.pinboardEntryDao = dao;
}
public IPinboardEntryDAO getPinboardEntryDAO(){
...
}
...
}
public class PinboardEntryDAO implements IPinboardEntryDAO{
...
}
Note that inside the the PinboardService class I'm using the DAO interface, not the implementation itself, while in the configuration I'm then injecting the real implementation PinboardEntryDAO. This is a very good practice for separating the different layers (presentation, service and data layer).
Although a Spring MVC application has two distinct contexts, the web context has access to all the beans loaded in the application context. The application context however cannot access beans in the web context. This is used to enforce separation of concerns, e.g. business rules class does not need to know about the HTTP session. So if you have a bean you need access to from both contexts it will have to be declared within the application context.
Any dependencies that your Controller has (such as on service-layer classes, DAOs, etc) should be expressed as normal - through injection, either constructor injection or setter injection.
The context where the controller is mapped just wires it up with any dependencies it needs as normal. The Controller code never needs to work with Spring directly to get any beans, it is wired up with them.
You should use dependency injection and your config files to load beans into your controllers, but if you do need to access the application context directly, any Controller that extends AbstractController (or any of its descendents) has access to the getApplicationContext() method.
In stand alone application we can user context.Refresh() it will reloading/re-instantiating the new requested beans the old beans will have the old instance only.
In web applications we need to overwrite the ContextLoaderListener and call the contextInitialized()
You need to import the file containing the bean definitions of the service layer(say, service-context.xml) into the new project. It can be done as:
<import resource="classpath:service-context.xml"/>