We have a homepage that contains multiple components (widgets), kinda like a portal containing portlets. Some of these widgets will be delivered ad jars from other teams and some of those will require some custom beans to be managed by Spring. One solution might be to import spring contexts using the import statement with I wildcard (e.g. import all contexts in the classpath matching context-widget-*.xml).
However, I prefer a more programmatic solution where I check for each widget which context they need loaded (from the classpath). I did not find any blog or such that explains this but did find some posts on forums that explain that this would be a parent-child context and this will only be unidirectional; unfortunately in my case it needs to be bidirectional.
So after some browsing in the API I managed to come up with something working but I am not confident it is a good solution or it there are any pitfalls I did not think about. Perhaps there is another (better) solution for this scenario?
public class WidgetManager implements ApplicationContextAware
{
#Autowired
private WidgetService widgetService;
#Override
public void setApplicationContext(ApplicationContext parentApplicationContext) throws BeansException {
//I do need the parent context to have finished initializing beans
List<WidgetTO> widgets = widgetService.findAllWidgets();
List<String> contexts = newArrayListWithCapacity(widgets.size());
for (WidgetTO widget : widgets) {
if (isNotBlank(widget.getSpringContext())) {
contexts.add(widget.getSpringContext());
}
}
AbstractRefreshableWebApplicationContext parentContext = (AbstractRefreshableWebApplicationContext) parentApplicationContext;
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(contexts.toArray(new String[] {}), parentApplicationContext);
String[] singletonNames = context.getBeanFactory().getSingletonNames();
for (String s : singletonNames) {
//copy all singletons that don't already exist from child to parent
if (!parentContext.getBeanFactory().containsSingleton(s)) {
parentContext.getBeanFactory().registerSingleton(s, context.getBeanFactory().getSingleton(s));
}
}
}
}
This is actually exactly how I did it. We have been using this fashion for over 3 years and never had issues.
You might be able to use AutowireCapableBeanFactory. This class lets you add beans to your existing Spring context. It will instantiate beans and inject their dependencies.
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/factory/config/AutowireCapableBeanFactory.html
I'm not sure I understand the "bidirectional" context thing you're talking about. Do you need your primary context beans to have dependencies on beans from the "child"/additional contexts? If so, wildcard imports are probably your best bet, even if you don't prefer that solution.
It might be helpful if you explained in a little more detail your overall application lifecycle, describing the stages for your "parent"/primary context and your "child"/additional contexts.
Related
Say I have an EJB with the following configuration:
package com.main.notsimulated
#Singleton
#EJB(name = "java:/sample/MainOne", beanInterface = MainOne.class)
public class MainOne {}
This ejb needs to be present for some other deployables to work. However, using this MainOne modue is not very feasable for me in a testing env. Instead, I would rather inject my own custom version at runtime.
package com.main.simulated
#Singleton
#EJB(name = "java:/sample/MainOne", beanInterface = MainOne.class)
public class MainOne {}
(Note, these are two different jar files)
Hence, my idea here is, let's try to replace the currently deployed with a custom version on the fly. The reason I want to do this is because I do not want to change the nonsimulated version at all, nor effect the consumers of the ejb in any way. i.e All that the consumer currently does is look for that particular jndi name, and performs an indejection and a casting to a particular interface.
I have looked at this post in hopes of figuring out if my MainOne Class from com.main.simulated can evict the currently instantiated MainOne class. However, the the selected answer states it is not programatically possible to start or stop an ejb. I have also looked at this post, but this is more of a practical guide as to how we can inject these beans inour calls.
Hence, my question is, can my latter implementation (com.main.simulated) somehow "replace" the other bean, and ensure the com.main.notsimulated version is never executed?
Deploying two classes, with the same binding is obviously not possible. When trying to do so, one will get a binding exception. However, contrary to my original research, programatically binding a bean is entirely possible. Hence, the solution as to how one can "hijack" an old binding, and replace it with the new is as follows: (Note, replace the class names with what you need)
package com.main.simulated
#Startup
#Singleton
public class MainOne {
#PostConstruct
private void rebindClass() throws NamingException {
final Context context = new InitialContext();
context.rebind("java:/sample/MainOne", this);
}
// other methods that will be called
}
Three important things about this class are: Removal of the #EJB annotation, the #Startup annotation and the rebind of context. The #Startup ensures the #PostConstruct method gets called when our container loads our class. When this happens, the method rebinds a class for a value. Hence, this is the hijack location.
Hope this helps someone.
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've moved my code from Spring's XML configuration to Java Configuration. I have everything working, but I have a question about how I implemented prototype beans - mainly, while what I'm doing works, is it the best way to do this? Somehow it just feels off!
I wrote the bean class this way:
#Component
#Scope("prototype")
public class ProtoBean {
...
}
Then to use the bean - this is the part that I'm just not sure about, although it does work:
#Component
public class BeanUser implements ApplicationContextAware {
ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext context)throws BeansException
{
this.context = context;
}
public void getProtoBean() {
ProtoBean protoBean = context.getBean(ProtoBean.class);
}
}
This gets me a prototyped bean, and in unit tests I just mocked the context, called setApplicationContext with the mock, and had the getBean call of the mock return a mock ProtoBean. So all is well.
I did this in the XML by using a factory, but that didn't seem to work too well, so this is where I ended up. But is there a way to do this without the context? Or just a better way?
Thanks!
I don't think is so much an issue of Spring XML vs Java-base configuration, but one of matching dependency scopes. Since Spring can only do dependency injection on the singleton-scoped bean at creation time, you have to lookup the prototype-scoped bean on demand. Of course the current bean-lookup approach works, but creates a dependency on the ApplicationContext. I can suggest a few other possibilities but the root of the issue is really what is involved in producing a ProtoBean, and what trade-offs should you accept.
You could make BeanUser itself prototype-scoped, which would allow you to wire in the ProtoBean as a member. Of course the trade-off is you now have the same problem on the clients of BeanUser, but sometimes that would not be a problem.
Another path could be using something like a singleton-scoped ProtoBeanFactory to provide ProtoBean instances, and hiding dependency lookups within the ProtoBeanFactory.
Finally, you could use a scoped-proxy bean to effectively hide the factory. It uses AOP to do this, and isn't always clear to others what sort of voodoo you have going. With XML you'd use <aop:scoped-proxy/> on the bean declaration. For annotations you'd use:
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS, value = "prototype")
I'm just getting started with Spring IOC concept. I often see most of the examples found in the internet use the code to get the object.
ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) appContext.getBean("hello");
As a reference from these questions 1 and 2 in the stackoverflow. I've inferred that, it's not necessary to use appContext.getBean("hello") in the code which is considered to be the bad practice. Also, not recommended anymore. Correct me right here, If my inference is wrong.
Keeping that in view, I have made changes in my project accordingly.
Here's my applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="utilClassRef" class="org.hd.derbyops.DUtils" lazy-init="false" />
<bean id="appContext" class="org.hd.derbyops.ContextProvider" lazy-init="false">
<property name="utils" ref="utilClassRef" />
</bean>
</beans>
My contextProvider Class Code
public class ContextProvider implements ApplicationContextAware {
private static ApplicationContext ctx;
/**
* Objects as properties
*/
private static DUtils utils;
public void setApplicationContext(ApplicationContext appContext)
throws BeansException {
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
public static DUtils getUtils() {
return utils;
}
public void setUtils(DUtils dUtilsRef) {
utils = dUtilsRef;
}
}
For instance, consider a class A that depends on org.hd.derbyops.DUtils.
I'm using the following code line
ContextProvider.getUtils();
inorder to get DUtils Object in class A, thus avoiding usage of ApplicationContext.getBean() anywhere in my code.
Assume, if I have 10 classes and my class A is dependent on all of them, whose objects to be created and accessed without using ApplicationContext.getBean(). In that case also, as done above, I have a thought of creating properties of ContextProvider class followed by setter's and getter's of that property, where in get<PropertyName> is static. So that, I can use it wherever I'm in need of an object, like this
ContextProvider.get<PropertyName>;
Here's my brief question.
Firstly, Is my approach right? If it's right, loading all the beans at the start-up, wouldn't it be a performance killer? How would you do that in your applications without calling getBean atleast more than once?
If you were to design a web-application & you were to implement Spring IOC, without using ApplicationContext.getBean() in any of the code. How would you do that?
Note: with reference to the other questions tagged above
Calling ApplicationContext.getBean() is not Inversion of Control!
The simple answers are yes and no, no, and no. And finally, do a search online for spring MVC, as this probably does what you want.
So, your approach. Yes, you've got most of it right. However, it's considered very bad practice to use static methods for everything. And, you don't need to. Spring is based on the idea that you can simply create normal pojos, and spring will use them as singletons, and inject them into one another (it can also create objects on the fly, but I'm going for the common case here). If you use static classes and methods then:
You can't mock them for unit testing (you're using JUnit right?)
You can't use them with inheritance
Static initialisers are a great way to loose exceptions
etc, etc
So, yes to injection, and no to static stuff.
Next, performance. You're right in that it's a lot slower to use spring, but, if you do all your injection on startup it only happens once. Spring is meant for server side applications where there is likely to be a number of singleton classes passing data around. So, there might be a class to get stuff from a DB, one to process it, and one to display it, and spring is used to wire them together.
If you're using spring in an application where you start up repeatedly, like a command line app, then you are using it for the wrong sort of application, and you probably want to use a builder or something. Spring is meant for big enterprise apps that aren't restarted often.
Finally, if you simply inject all the dependencies for a class into it at startup, and you do this with all your classes, then you don't need to do any getBean stuff at all. Also, using the init-method and destroy-method attributes on a bean means that you can start up processes once spring has finished injecting dependencies. You need only load the context, and your app will spring (pun intended) into existence.
As for web projects, Spring MVC basically takes the whole inversion of control pattern and applies it to web applications. The spring stuff gets loaded by the container, and you can define the URLs to respond to using nothing more than bean names. And most of your code can stay as pojos. If you have something insanely complex, you may want to look at spring web flow, but I'd advise you to make sure that your spring foo is very strong before attempting that.
Here's my example for getting the first instance without actually calling getBean() on ApplicationContext.
public class Test{
// Declare private static variable so that we can access it in main()
private static Triangle triangle;
// Use constructor injection to set the triangle
public Test(Triangle triangle) {
Test.triangle = triangle;
}
public static void main(String[] args) {
// Specify the context file containing the bean definitions
// Spring automatically creates instances of all the beans defined
// in this XML file. This process is performed before you actually make
// a getBean("beanName") call.
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
// Use instance methods of triangle
Test.triangle.draw();
}
}
You can use another way:
In spring.xml (Your bean configuration XML file)
<bean class="com.example.Test" init-method="myMethod">
<constructor-args ref="triangle"/>
</bean>
Now for your main class
public class Test {
private final Triangle triangle;
public Test (Triangle triangle) {
this.triangle = triangle;
}
public static void main (String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
}
// Called by Spring immediately after the Triangle Bean has been created and
// all the properties for the bean have been set. This method name must match
// the one specified with destroy-method attribute in spring.xml
public void myMethod () {
triangle.draw();
}
}
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.