Ok, so here is my use case:
I have the following classes each encapsulating an instance of the next one in line. So:
A -> B -> C -> D
eg: In class A, I have an instance of class B and in class B I have an instance of C and so on.
Well, I am trying to convert the loading\initialization\injection logic to a hybrid Spring system. The general idea being that B, C and D will need to more or less be ApplicationContextAware. By that I mean, that they will not actually implement that interface, but instead require the ApplicationContext as a constructor parameter. This way, in the hybrid approach (where the developer does not use Spring to initialize the instance) they must at least pass in the ApplicationContext so that additional beans may be wired. The problem is, that in order for the Spring container to load the beans, I now have to pass in the ApplicationContext in the XML. But as far as I can tell, there is no nice way to do this.
I tried something like this:
public class ApplicationContextPlaceholder implements ApplicationContextAware {
private ApplicationContext _applicationContext;
public void setApplicationContext( final ApplicationContext applicationContext ) throws BeansException {
_applicationContext = applicationContext;
}
public ApplicationContext getApplicationContext() {
return _applicationContext;
}
}
<bean id="a" class="com.company.A">
<constructor-arg>
<bean id="applicationContext" class="com.company.ApplicationContextPlaceholder" />
</constructor-arg>
</bean>
But obviously this doesn't make any sense, since ApplicationContextPlaceholder isn't really an ApplicationContext. I've also looked for ways to reference the context inside the XML, but I'm not finding anything.
Does anyone know of an elegant solution to this type of problem?
EDIT #1:
I was thinking about it, and I could have ApplicationContextPlaceholder also implement ApplicationContext and just delegate to the injected context and then it occurred to me that maybe, just maybe this was already in Spring...but as far as I can tell, no.
EDIT #2:
The reason each class needs an ApplicationContext is that if a dev wishes to override one of the classes in the chain (say, C for sake of argument). In this instance the child class of C will still need to load D via Spring.
Unless a class is providing additional plumbing functionality, you should avoid exposing the ApplicationContext. Quoting the Spring reference: in general you should avoid it, because it couples the code to Spring and does not follow the Inversion of Control style.
If you are providing additional functionality (maybe, for example, a factory class that uses the ApplicationContext to assemble objects), then it's prudent to implement ApplicationContextAware since your functionality is already tied to Spring.
If you've considered your dependency injection alternatives and have decided on injecting the ApplicationContext in your beans, your ApplicationContextPlaceholder class (I would stay away from a Placeholder prefix to avoid any confusion with Spring property placeholders) is certainly a solution. (Since it is your own class, why not extend ApplicationObjectSupport for additional functionality.)
This class will need to be defined and initialized in your configuration, for example:
<bean id="appCtxHolder" class="ApplicationContextHolder" />
Because ApplicationContextHolder implements ApplicationContextAware, Spring will inject the ApplicationContext into appCtxHolder when it is initialized. You can use it for constructor injection like:
<bean id="a" class="com.company.A">
<constructor-arg>
<bean factory-bean="appCtxHolder" factory-method="getApplicationContext" />
</constructor-arg>
</bean>
ApplicationContextPlaceholder could have everything static. In that case, you don't need to pass ApplicationContext around, when a API requests for a certain bean, you could check if its null and if it is, load it using the ApplicationContext from ApplicationContextPlaceholder. That's assuming a setter based injection, if you are doing constructor based, you could init beans in the contructor too.
Related
I have a Spring webapp running on Java 5. This is was my applicationContext.xml file:
<bean id="child1" class="foo.ChildOne" />
<bean id="child2" class="foo.ChildTwo" />
<bean id="main" class="foo.Main">
<property name="childrenList">
<list value-type="foo.IChildren">
<ref bean="child1" />
<ref bean="child2" />
</list>
</property>
</bean>
Both ChildOne and ChildTwo classes implement the IChildren interface. And in my Main class, I have defined a childrenList which gets populated with child1 and child2 beans. Easy, right?
But in the future, there might be no child1, and instead, we will maybe have a child81 based on another unknown class. And it still has to work without touching the current code or XML files, only through configuration. This child81 would be defined on its own applicationContext file (in a JAR), and we will list the bean names in a database field (child2,child81,etc).
I guess that's not a good design pattern; most likely it's a terrible, horrible, painful, you-better-run-while-you-can design, which will haunt me in the years to come. But I didn't define it, and I can't change it, so please lets assume it's OK for the purpose of this question.
Instead of injecting the beans myself using the applicationContext.xml, I have to retrieve them somehow, in runtime. I can't use autowiring either, because I don't know what class the beans are, all I know is all of their classes implement IChildren.
So I have made my main bean class ApplicationContextAware and I have added this method:
public void loadChildren() {
if (childrenList == null) {
childrenList = new LinkedList<IChildren>();
for (String name : theListOfBeanNames) {
childrenList.add((IChildren) context.getBean(name));
}
}
}
It works alright; each bean is defined in its own applicationContext, and then I retrieve them by name. But... when do I call loadChildren()? So far, I'm doing it in the first line of each one of my methods. Since there is a null-check, it will initialize the list only once. But surely, there must be an easier/cleaner/better way of doing this?
I don't think I can just use the init-method="loadChildren" property in my applicationContext, because then it would fail if my main bean is being loaded before all the children have been... and I can't control the loading order. Or can I?
This is from my web.xml file:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/application-context/applicationContext-*.xml
,classpath*:WEB-INF/application-context/applicationContext-children.xml
</param-value>
</context-param>
(We use the "classpath* notation" to load every applicationContext-children.xml file from within the JARs). If I invert the order and place the children XML before the main ones, would it ensure they will be loaded in that specific order? No matter what version of what application server we use?
I've also seen a #PostConstruct annotation which would be useful if I could add it to my loadChildren method. But when would it be called then? I've read that it's after the injections have been done, but... only for the current bean, right? It doesn't ensure that all the other beans are already loaded?
Is there any other option?
Spring can do this for you:
#Component
public class MyComponent {
#Autowired
private final List<IChildren> children;
...
}
That will autowire in everything than implements IChildren.
Mr Spoon's answer does exactly what I asked, so I'm marking it as the correct answer. However, I forgot to mention that the children order in the list does matter, so I still can't use autowiring. Here is what I ended up doing instead, in case anybody else finds it useful.
As stated in the answers to this question, another option is to catch the ContextRefreshedEvent by implementing the ApplicationListener<ContextRefreshedEvent> interface. That ensures that the loadChildren method is executed only after all the initialization is done.
Since we are using a very old Spring version (2.0.7), our ApplicationListener interface is slightly different, for example it doesn't support generic types. So, instead of doing this, my class looks like this:
public class Main implements ApplicationListener {
public void loadChildren(ApplicationContext context) {
//...
}
public void onApplicationEvent(ApplicationEvent ev) {
if (ev instanceof ContextRefreshedEvent) {
loadChildren(((ContextRefreshedEvent) ev).getApplicationContext());
}
}
}
In a modular Spring configured application, we use factory beans to provide bean instances across module boundaries.
For example, one module A may expose a bean instance by the name name. Another module B can then consume that bean via a declaration of the style
<bean id="nameBean" class="com.zfabrik.springframework.ComponentFactoryBean">
<property name="componentName" value="A/name" />
<property name="className" value="a.AInterface" />
</bean>
Note that modules have separated class loader hierarchies and the actual implementation class of A/name may not be visible in B. As if in OSGI (although this is NOT OSGi).
My goal is to provide A/name in a programmatic application context in B. However when trying
#Configuration
public static class AppContext {
#Bean AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
(lookup does the actual instance retrieval) I see that Spring is trying to configure the returned instance. For example, it will attempt to resolve #Autowired properties of A/names's implementation class - which does not make sense in the context of B (and the deal of the lookup is to provide something fully configured anyway). Even, if I try
#Configuration
public static class AppContext {
#Bean(autowire=Autowire.NO) AInterface nameBean() {
return lookup("A/name",AInterface.class);
}
}
it will go about configuring the returned instance.
How can I provide a bean to the application context without spring touching its implementation instance?
EDIT: As suggested by Sotirios Delimanolis, returning the FactoryBean does AFAICT avoids Spring configuration of the returned instance.
The alternative code would look like this:
#Configuration
public static class AppContext {
#Bean FactoryBean<AInterface> nameBean() {
return new ComponentFactoryBean("A/name",AInterface.class);
}
}
It's not as cool as an #UntouchedBean annotation because of the FactoryBean in the return type, but it solves the problem.
#Sotirios: Please suggest as answer so that I can tag your suggestion accordingly.
/EDIT
Ok, just so it can be closed. The suggested and accepted answer is to return the factory bean.
I have a java class lets say 'class1' which basically holds a ConcurrentHashMap (to be used as a cache) and some functions to update and remove the entries in the map.This class is not designed to be a singleton class.
I was having a discussion with a colleague, but couldnt really decide due to a couple of posts i read on the internet.I am asking if it is okay to do this-
<bean id="reqrespCacheMgr1" class="gravity.applications.RFQService.reqrespgtwy.utility.ReqRespCacheManager" scope="singleton">
</bean>
<bean id="reqrespCacheMgr2" class="gravity.applications.RFQService.reqrespgtwy.utility.ReqRespCacheManager" scope="singleton">
</bean>
<bean id="reqrespCacheMgr3" class="gravity.applications.RFQService.reqrespgtwy.utility.ReqRespCacheManager" scope="singleton">
</bean>
I am basically trying to create 3 singleton instances of the same class..I think it doesnt really spoil the meaning of singleton-ness because we are talking about singleton scope in the spring bean factory context and not the class loader context.. I know there are alternate ways to do this.. Like having 3 concurrenthash maps in the same class and using only one singleton bean reference ,there by trying to create update and remove methods for 3 maps in the same class.
I hope i didnt make it confusing but all i wanna know is which is a good approach.I am afraid im making an improper use of design patterns..
Let me know if the question is unclear
It seems you need not a singleton but prototype
<bean id="reqrespCacheMgr" class="gravity.applications.RFQService.reqrespgtwy.utility.ReqRespCacheManager" scope="prototype" />
class B1 {
#Autowire
ReqRespCacheManager cacheManager;
}
class B2 {
#Autowire
ReqRespCacheManager cacheManager;
}
class B3 {
#Autowire
ReqRespCacheManager cacheManager;
}
All 3 beans will get a new instance of ReqRespCacheManager
Looks OK to me, as long as you only need to use those 3 instances for the entire lifecycle of your application. Are you aware that autowiring a single property wont work for this type?
You will need to use #Qualifier to assign a specific instance into your application beans:
public class FooBean {
#Inject
#Qualifier("reqrespCacheMgr3")
ReqRespCacheManager cacheManager;
}
Alternatively, you can collect all three into a single bean by injecting a List component of your type.
#Inject
List<ReqRespCacheManager> caches;
Hope that helps! Good luck, and dont forget to think 2 steps ahead.
I am asking this Question in reference to my question:
spring singleton scope
Spring singleton is defined in reference manual as per container per bean.
per container means if we do like:
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml")
MyBean myobj=(MyBean)context.getBean("myBean"); //myBean is of singleton scope.
MyBean myobj1=(MyBean)context.getBean("myBean");
Beans.xml:
<bean id="myBean" class="MyBean"/>
Then myobj==myobj1 will come out to true.Means both pointing to same instance.
For per bean part of phrase per container per bean i was somewhat confused. Am i right in following for per bean :
If we do like
ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml")
MyBean myobj=(MyBean)context.getBean("myBean");
MyBean myobj1=(MyBean)context.getBean("mySecondBean");
Beans.xml:
<bean id="myBean" class="MyBean"/>
<bean id="mySecondBean" class="MyBean"/>
Then myobj==myobj1 will come out to false. Means then they are two different instances?
That is correct.
If it helps, you can also think of Spring beans as Instances that you would've otherwise created manually in your Java code using the constructor.
By defining the bean in the Spring XML file, that bean (Instance) gets registered with Spring's App Context and then that instance can be passed around to the other areas of the code.
By creating a new bean, you are effectively creating a new instance. So potentially you could create any number of beans (Instances) of the same class
myBean is a Spring singleton in the sense of every call to beans.getBean("myBean") will allways return the same instance. And mySecondBeanhaving a different id is another Spring singleton. You can have different singleton beans of same class in the same ApplicationContext .
Yes, you're right. Testing it would have told you.
Forgive me if I don't get the terminology correct.
My situation is thus:
I have a class, let's call it TheClass. Inside this class is a TheData object.
I have XML to set up the TheData bean, like so:
<bean id="theData" class="com.abc.TheData">
<property name="field" value="value1" />
</bean>
and a setter inside TheClass like so:
public void setTheData(TheData theData)
{
this.theData = theData;
}
My problem is that if I don't also create the TheClass bean in the XML (and thus can't let it get autowired), it won't know to autowire the theData field (right?). And due to certain restrictions, I can't configure TheClass in the XML (and thus later have it autowired). So, my question is, how can I make this work? I'm a bit of a novice so if I'm missing something, feel free to point it out.
If you can get hold of the Spring context, cast it to AutowireCapableBeanFactory, and pass your instance of TheClass to the autowireBean(Object) method. Spring will then try to apply its autowiring rules to that object.
You'd need to add #Autowired to the setTheData method, though.
You could use #Resource or #Component.
I just now saw this question and thought I might add one more method of doing what you want (although the AutowireCapableBeanFactory would be my choice).
You can leverage the #Configurable annotation in the manner that is described in this blog post
You should be able to just use the #Autowired annotation on your instance variable that your setter is setting, without having to declare a TheClass bean in your XML. That is:
public class TheClass {
#Autowired
private TheData theData;
}