How to avoid Spring configuring bean in Java config - java

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.

Related

Using Sping Beans on abstract classes

I'm looking for a pattern to simplify bean creation for a team of developers.
For now, I've been trying to use abstract classes like this:
public abstract class BaseClass {
#Bean
public BeanA generateBeanA() {
...
return beanA;
}
#Bean
public BeanB generateBeanB() {
...
return beanB;
}
}
The idea behind: I provide the BaseClass and I'd like developers to extend it many times. For each extension, every beans should be generated. But this approach doesn't work : for each extension, developers have to redeclare beans for 2 reasons :
bean declaration is not inherited
to avoid name clashing, they have to name beans manually in each extension
Is there a better pattern that would allow the following?
centralized bean naming (ie: the developer declare a base name in the extension and every bean of the extension is renamed accordingly: ${baseName}${beanName} )
overriden beans would be declared (instead of parent version)
parent beans would be declared if not overriden
There are 3 ways to configure beans in Spring container:
Declare them using XML configuration.
Declare beans using the #Bean
annotation in a configuration class.
Mark the class with one of the
annotations from the org.springframework.stereotype package, and
leave the rest to component scanning.
So, the way you declare Spring bean is wrong.
IMHO, let the developers declare beans as they want, and they just #Autowired them or something.
Please continue by reading this

Singleton in Java and Spring [duplicate]

Could you please explain why Spring is creating two objects for the configuration of beans shown below, since by default spring default scope is singleton?
The Spring configuration is here:
<bean id="customer" class="jp.ne.goo.beans.Customer">
<property name="custno" value="100"></property>
<property name="custName" value="rajasekhar"> </property>
</bean>
<bean id="customer2" class="jp.ne.goo.beans.Customer">
<property name="custno" value="200"></property>
<property name="custName" value="siva"></property>
</bean>
Spring's default scope is singleton. It's just that your idea of what it means to be a singleton doesn't match how Spring defines singletons.
If you tell Spring to make two separate beans with different ids and the same class, then you get two separate beans, each with singleton scope. All singleton scope means is that when you reference something with the same id, you get the same bean instance back.
Here is how the Spring documentation defines singleton scope:
Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Spring container.
Singleton scope means using the same id retrieves the same bean, that is all. Testing that no two ids referenced the same class would get in the way of using maps as beans, and would be complicated by proxying things with BeanFactories.
For Spring to police this would involve a lot of work for little benefit. Instead it trusts the users to know what they're doing.
If you want a bean’s singleton-ness preserved across multiple names, that is do-able. You can have more than one name refer to the same bean, that is done by using an alias:
In a bean definition itself, you can supply more than one name for the bean, by using a combination of up to one name specified by the id attribute, and any number of other names in the name attribute. These names can be equivalent aliases to the same bean, and are useful for some situations, such as allowing each component in an application to refer to a common dependency by using a bean name that is specific to that component itself.
Specifying all aliases where the bean is actually defined is not always adequate, however. It is sometimes desirable to introduce an alias for a bean that is defined elsewhere. This is commonly the case in large systems where configuration is split amongst each subsystem, each subsystem having its own set of object definitions. In XML-based configuration metadata, you can use the element to accomplish this.
So if you add a name in the bean configuration:
<bean id="customer" name="customer2"
class="jp.ne.goo.beans.Customer">
</bean>
or create an alias for a bean defined elsewhere:
<alias name="customer" alias="customer2"/>
then "customer" and "customer2" will refer to the same bean instance.
Spring default scope is singleton and it will create one object for all instances unless you explicitly specify the scope to be prototype. You have not posted spring configuration. Please post it, it will give a better idea.
In Spring Singleton refers to One bean per Spring container where as in Java Singleton refers to one object per class loader.
So Spring singleton is not same as java singleton. Don't get confused between these two.
You're confusing two different concepts.
The word singleton in spring is used for a bean scope, meaning that the bean will be created only once for the whole application.
Singleton usual meaning refers to the GOF pattern. It is an object oriented pattern guarantying that only one instance of a class will exists (at least in the scope of the classLoader).
You are declaring two beans of the same class. That isn't the same.
#Component("springTestClass")
public class SpringTestClass{
private int randomNumber = 0;
public SpringTestClass(){
randomNumber = new Random().nextInt(2000);
}
public int getRandomNumber(){
return this.randomNumber;
}
}
And try to access this bean in two places the number will be the same. But what you have done was creating two separate beans.
If you want to check if this works try:
public class Main{
public static void main(String[] args){
ApplicationContext ctx = ....;
SpringTestClass testObject1 = (SpringTestClass)ctx.getBean("springTestClass");
SpringTestClass testObject2 = (SpringTestClass)ctx.getBean("springTestClass");
System.out.println(testObject1.getRandomNumber() == testObject2.getRandomNumber());
}
}
This code should return true if it is same instance;
But in SpringTestClass you can add #Scope("prototype") annotation.
The output will be false
Like others have mentioned, two beans should be created from the code you posted. Singletons are defined as follows (from the Spring documentation: Singleton Scope)
Only one shared instance of a singleton bean is managed, and all requests for beans with an id or ids matching that bean definition result in that one specific bean instance being returned by the Spring container.
To add clarity to this, the meaning behind "shared instance" is explained in the paragraph that follows the one above:
all subsequent requests and references for that named bean return the cached object
When a singleton bean is created, only one bean object is instantiated and cached. This refers only to the bean, not to whatever class the bean may be an instance of. For example,
<bean id="myBean" class="myPackage.myClass" />
<bean id="myOtherBean1 class="myPackage.myOtherClass1">
<property name="beanReference1" ref="myBean" />
</bean>
<bean id="myOtherBean2 class="myPackage.myOtherClass2">
<property name="beanReference2" ref="myBean" />
</bean>
In this made up configuration, "myOtherBean1" and "myOtherBean2" have references to the same "myBean" bean therefore the same "myPackage.myClass" instance. If you changed the code to add a second "myPackage.myClass" bean, it would be distinct from "myBean".
To fully understand this, also refer to the other Spring scope: the prototype. From the Spring documentation for Prototype Scope:
The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a request for that specific bean is made.
This means that if we were to use the same Spring XML as above, "myOtherBean1" and "myOtherBean2" would each receive their own distinct copies of "myBean" which is still just an instance of "myPackage.myClass".
Spring Singleton Bean Does not work like Java Singleton.
If we write
ApplicationContext ctx = new ClassPathXmlApplicationContext("MyConfig.xml");
Customer obj1= (Customer) ctx.getBean("customer");
Customer obj2 = (Customer) ctx.getBean("customer2");
System.out.println(obj1 == obj2);
System.out.println(obj1+ "::" + obj2);
If we see the output it will return 2 different Instance.
According to Spring Docs
Bean is singleton only one shared Instance will be managed, and all request beans with an ID or ID matching that bean definition. Here 2 different ID is available.
Spring container as managing Key value pair, Key as ID/Name and value is bean.
The following example shows a #Bean annotated method being called
twice:
#Configuration
public class AppConfig {
#Bean
public ClientService clientService1() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
#Bean
public ClientService clientService2() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
#Bean
public ClientDao clientDao() {
return new ClientDaoImpl();
}
}
clientDao() has been called once in clientService1() and once in
clientService2(). Since this method creates a new instance of
ClientDaoImpl and returns it, you would normally expect having 2
instances (one for each service). That definitely would be
problematic: in Spring, instantiated beans have a singleton scope by
default. This is where the magic comes in: All #Configuration classes
are subclassed at startup-time with CGLIB. In the subclass, the child
method checks the container first for any cached (scoped) beans before
it calls the parent method and creates a new instance. Note that as of
Spring 3.2, it is no longer necessary to add CGLIB to your classpath
because CGLIB classes have been repackaged under
org.springframework.cglib and included directly within the spring-core
JAR.
spring default scope is singleton. Once the bean will be created and same bean used throughout its lifecycle.

chicken and egg Spring bean binding

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.

How to turn Spring #Autowired required property to false for test?

I've been using the #Required annotation up to now to ensure DI of my beans in a Spring configured application.
To enable the annotation, you need to declare a RequiredAnnotationBeanPostProcessor bean in your configuration.
In your test configuration you just don't declare it, so that if some beans are not needed you don't have to have them in your config.
I want to switch to less XML and use #Autowired annotation, but it is by default required=true, which is fine for the runtime configuration.
But I need #Autowired to be required=false for testing purpose only - while keeping it required for runtime.
Is that possible at all? I can't find a way to declaratively turn the required property to false.
cheers
You probably solved it already but this trick might be useful for others.
As far as I understood without context:annotation-driven being present #Autowired annotations should not be processed but this is clearly not the case so I might misunderstood something.
However, I needed a quick solution... This somewhat dirty trick negates required value for all classes making optional what was required before. Adding it to my test context solved my problem but it is useful only if all autowirings are required in your business classes.
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor">
<property name="requiredParameterValue" value="false" />
</bean>
I worked out a solution that works for JavaConfig configurations
#ContextConfiguration(initializers={DisableAutowireRequireInitializer.class})
public class TestCase {
// Some tests
}
public class DisableAutowireRequireInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
// Register the AutowiredAnnotationBeanPostProcessor while initalizing
// the context so we get there before any #Autowire resolution happens
// We set the "requiredParameterValue" so that #Autowire fields are not
// required to be resolved. Very useful for a test context
GenericApplicationContext ctx = (GenericApplicationContext) applicationContext;
ctx.registerBeanDefinition(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME,
BeanDefinitionBuilder
.rootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class)
.addPropertyValue("requiredParameterValue", false)
.getBeanDefinition());
}
}
You can use the same technique as you did with #Required - don't register the AutowiredAnnotationBeanPostProcessor in your test context, but leave it in your live context.
This is usually registered by adding <context:annotation-driven/>, rather than being declared manually.

Spring- How to use Spring Dependency Injection to write a Standalone Java Application

I want to write a standalone application with IOC, how do I use springs dependency injection in there? I'm using JIdea. There is spring 2.5 support but I want to use spring 3.0 here is the way I tried!
I experience in using Spring MVC we can inject dependencies there in a WebApplicationContext but how do I inject dependencies in a standalone application
I tried this
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"com\\ttg\\xmlfile.xml"});
but I cannot see that the dependencies are injected by the beans defined there (in the XML file)
I put the above code in the main method and two bean definitions for two Objects,in one Java class's constructor I used the other class's object - which was injected to this object - and called a method on that which will print some thing but it didn't worked I thought that the above code creates all the dependencies and injects them but it doesn't seem like that
How do I properly use Springs IOC, dependency injection in my stand alone app which does not contain a WebApplicationContext?
Please mention steps.
suppose you have:
class Bean1 {
Bean2 bean2;
}
class Bean2 {
String data;
}
the context.xml file
<bean id="bean1" class="Bean1">
<property name="bean2" ref="bean2" />
</bean>
<bean id="bean2" class="Bean2" />
then this should be true
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"context.xml"});
Bean1 bean1 = (Bean1) context.getBean("bean1");
// bean1.bean2 should not be null here.
you can use autowiring support provided by spring, in order to inject dependencies (and possibly apply post processors) to an object that is not part of the application context.
In your case, this object is your standalone application.
Here is the way to achieve this. In this example, I use #Autowired (for b1), traditional DI (for b2) and initialization hook for b3. The autowiring support with annotations assumes you have defined the appropriate spring post-processor in your application context (e.g. by declaring <context:annotation-config/>).
public class StandaloneApp implements InitializingBean {
#Autowired private Bean1 b1;
private Bean2 b2;
private Bean3 b3;
public void afterPropertiesSet() throws Exception {
this.b3 = new Bean3(b1, b2);
}
public void setB2(Bean2 b2) {
this.b2 = b2;
}
public static void main(String... args) {
String[] locations = // your files relative to the classpath
ApplicationContext ac = new ClasspathXmlApplicationContext(locations);
// or use FileSystemXmlApplicationContext if the files are not in the classpath
StandaloneApp app = new StandaloneApp();
AutowireCapableBeanFactory acbf = ac.getAutowireCapableBeanFactory();
acbf.autowireBeanProperties(app, AUTOWIRE_BY_NAME, false);
acbf.initializeBean(app, "standaloneApp"); // any name will work
}
}
In this example, all b1, b2 and b3 should be non-null (assuming b1 and b2 beans exist in your application context).
I haven't tested it (might not even compile due to some typo), but the idea is in the last 3 lines. See the javadocs for AutowireCapableBeanFactory and mentionned methods to see exactly what happens.
If you prefer (mostly) pure java, you can use java config:
#Configuration
pubic class MyConfig {
#Bean
public Bean1 bean1() { return new Bean1(); }
#Bean
public Bean2 bean2() { return new Bean2(bean1()); }
}
And then to instantiate:
ApplicationContext ctx =
new AnnotationConfigApplicationContext(MyConfig.class);
Keep in mind there's some things that pure annotation driven configuration doesn't yet support (such as things like tx:annotation-driven), which you might need some xml glue code for.
<beans>
<tx:annotation-driven />
<context:annotation-config/>
<bean class="MyConfig"/>
</beans>
And then use a standard xml based way of creating the ApplicationContext (like ClasspathXmlApplicationContext, or the spring web context loader, etc...).
How did you confirm that your beans aren't being wired correctly? One common issue is the xml config file not being in the right place. Can you give us some more information like your project layout and the code you use to obtain the beans from the container?
If you add log4j logging to your app, you should see a cascade of messages coming out that will tell you a lot about what Spring is and is not doing. If you don't have that feedback, you're in the dark. You might be able to ferret out the answer just by getting more information out of Spring from log4j.
Are you calling context.getBean("beanName") to get a reference to the bean or are you doing a new SomeClass()? If you do it through getBean() then the injected properties should be set.
Also, be sure to use the same bean factory (ClassPathXmlApplicationContext instance) for retrieving all your beans. This should most likely be static final and used by the entire application.
you can use the command #Autowired

Categories