Overriding the bean defined in parent context in a child context - spring

Our app has a requirement to support multi-tenancy. Each of the boarded customer might potentially override 1 or more beans or some properties of a bean defined at the core platform level (common code/definitions). I am wondering what is the best way to handle this.

Spring allows you to redefine the same bean name multiple times, and takes the last bean definition processed for a given name to be the one that wins. So for example, your could have an XML file defining your core beans, and import that in a client-specific XML file, which also redefines some of those beans. It's a bit fragile, though, since there's no mechanism to specifically say "this bean definition is an override".
I've found that the cleanest way to handle this is using the new #Bean-syntax introduced in Spring 3. Rather than defining beans as XML, you define them in Java. So your core beans would be defined in one #Bean-annotated class, and your client configs would subclass that, and override the appropriate beans. This allows you to use standard java #Override annotations, explicitly indicating that a given bean definition is being overridden.

Related

Spring - register Beans before everything else

I need to register a series of BeanDefinition(s) before every other Bean gets created. That's because those registered Bean(s) are needed for autowiring and ApplicationContext#getBean calls.
I cannot use #DependsOn, obviously.
Example:
final var beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(...);
beanDefinition.setLazyInit(true);
beanDefinition.setAbstract(false);
beanDefinition.setAutowireCandidate(true);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
beanDefinition.setScope(BeanDefinition.SCOPE_PROTOTYPE);
registry.registerBeanDefinition("...", beanDefinition);
Which point/interface/lister can I use to obtain this? Keep in mind I need an instance of BeanDefinitionRegistry.
Adding explanation as required.
Those definitions are created from a list of Classes gathered by scanning the classpath. Those classes are not Spring Bean(s) natively, so I need to integrate them into my ApplicationContext. Those classes, however, accepts constructor arguments which are Spring Beans.
That's why I'm setting
beanDefinition.setAutowireCandidate(true);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
Those new registered Beans are there used by other Bean(s) (native Beans).
You are trying to make the solution too complex. If your only goal is to have non #Component annotated classes be detected by component scanning and have them used as Spring Beans simply define a custom includeFilter for the #COmponentScan.
You can use a filter of type ASPECTJ or REGEX to match a package or type.
#ComponentScan(includeFilter = #Filter(type=REGEX, expression="com.foo.bar.*))
Something like that will automatically detect your beans (assuming they are in a packaged being scanned) and create spring beans out of them. If they have a single constructor that will automatically be used to create an instance.
Register a new BeanFactoryPostProcessor or BeanDefinitionRegistryPostProcessor bean in your context. This bean will get invoked after bean definitions are scanned but before actual beans are constructed:
Extension to the standard BeanFactoryPostProcessor SPI, allowing for the registration of further bean definitions before regular BeanFactoryPostProcessor detection kicks in. In particular, BeanDefinitionRegistryPostProcessor may register further bean definitions which in turn define BeanFactoryPostProcessor instances.

Inconvenient of #Value Annotation in Spring 3.0

I'm wondering if I add a #Value annotation on a property, the class who contains this property cannot be used by another one with a different value, Example :
MyClassUtil.java had
#Value("${some.value}")
private int _myProperty;
And of course there is one module.properties who contain :
some.value=10
Another class ClassA.java wants to use this class with value 10. Ok, no problem.
But another class ClassB.java wants to use this class but with another value : 20. I cannot do this if I'm not mistaken.
Because before #Value era, I could declare two beans in the moduleContext.xml without any problem.
So, is #Value pushes you to do some strong coupling ?
You are right that the annotation configuration can not be instance specific. It is important to understand the concept of bean definitions in bean factory.
Manual bean definition:
Single <bean> element in your XML config leads to a single bean definition. Multiple <bean> mean multiple definitions (regardless of a bean type).
Single #Bean method within #Configuration class leads to a single bean definition. Multiple #Bean methods mean multiple definitions (regardless of a bean type).
However when using component scan, classes annotated with #Component-like annotations are auto-registered as a single bean definition. There is no way you can register bean multiple times via component scan.
Similarly, annotation configurations (#Value, #Autowired, etc.) are type-wide. Your bean instances are always augmented and processed with the same effect (e.g. injecting the same value). There is no way you can alter annotation processing behaviour from instance to instance.
Is this tight coupling? It is not in its general understanding - bean factory (Spring) is still free to inject whatever it thinks is suitable. However it is more of a service lookup pattern. This simplifies your life when working with domain specific singletons. And most beans in an application context tend to be singletons, many of them domain specific (controllers, services, DAOs). Framework singletons (non-project specific reusable classes) should never use annotation based configuration - in this scope, it is an unwanted tight coupling.
If you need different bean instances, you should not use annotation configuration and define your beans manually.

In spring batch framework, what is the difference between 'lazy-init=true' and 'scope=step'?

When I defined a 'MethodInvokingFactory' bean with 'scope=step', I got an error that the type of the bean can't be determined. It worked fine when I replaced 'scope=step' with 'lazy-init=true'. As per my knowledge, both are used for the late binding of the beans, except for that one difference. Are there any other differences between these two ways? Also, is my usage correct?
Please let me know your thoughts about this.
To answer to your question from low-level perspective:
lazy-init="true" means that bean will not be instantiated when the context is created, but will be created when it is referred e.g. by another bean. I think this is clear, also from #AravindA comment.
Scoped bean works in different manner. When context is created this bean is wrapped into additional proxy object (by default created by CGLIB), which is passed to the bean that refers it (this proxy is by default singleton, e.g. shared). So each time the method is invoked on the proxy in runtime Spring intersects the call, requests the factory to return the instance of the bean and invokes the method on that bean. The factory in its turn may lookup for "real" bean instance e.g. in HTTP request ("request" scope) or HTTP session ("session" scope) and/or create new instance if necessary. Late instantiation allows to initialize the scoped bean with "runtime" (scope) values, e.g. values from HTTP request/session which are obviously undefined when context was created. In particular "step"-scoped beans are bound to thread local (remember that steps are run in parallel for partitioning). So, scoped beans are dereferred when you call a method on them. Finally one can easily break this elegant Spring "ideology" by calling any method on scoped bean just after it is set to another bean (e.g. in the setter) :)
One thing to understand about lazy-initialization is that even though a bean
definition may be marked up as being lazy-initialized, if the lazy-initialized
bean is the dependency of a singleton bean that is not lazy-initialized, when the
ApplicationContext is eagerly pre-instantiating the singleton, it will have to
satisfy all of the singletons dependencies, one of which will be the
lazy-initialized bean!
Using a scope of Step is required in order to use late binding since the bean
cannot actually be instantiated until the Step starts, which allows the
attributes to be found. Because it is not part of the Spring container by
default, the scope must be added explicitly, either by using the batch namespace
or by including a bean definition explicitly for the StepScope (but not both):
<bean class="org.springframework.batch.core.scope.StepScope" />
Read here and here for more info
The scope="step" has nothing to do with Lazy initialization . It is use for late binding of parameters inside a "Step" .
the step scope is specifically for latebinding of job/step attributes and not really for late-binding of beans, meaning the spring bean context/factory will enhance stepscoped beans and look for attributes to set, e.g.
value="#{jobParameters[input.file.name]}

Spring Bean Inheritance - Scope, autowire, depends-on, etc

From Spring documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-child-bean-definitions:
The remaining settings are always taken from the child definition: depends on, autowire mode, dependency check, singleton, scope, lazy init.
I think there is a good reason for not inheriting these settings, but can't think of one. What are the reasons?
I think it's because it would cause more confusion. Imagine the time spent debugging why your bean is not in the default (singleton) scope. Or the case when the child bean is injected into a bean that the parent depends-on. You will get a circular dependency without being able to notice it.
Bean inheritance is only in terms of properties injected, and not in terms of bean settings.
One of the main reasons is that Spring is used to inject implementations. Usually, extended classes are the implementations and it's natural to pick up the configuration details from their definitions.
Other practical reason is that annotations are not inherited. If an interface has annotated methods this annotation is not automatically visible in the implementing/extending classes without some reflection gymnastics.

object creation in spring

If I am using spring frame work in my application does creating an object like this Test test = new Test() a bad way for creating an instance? Should I always use the bean config to get the objects/bean that I need? If yes, does that means I should have all the object/bean definition in spring applicationContext xml file?
If you want your object to be managed by Spring (this means that dependencies are injected, among other things) you have to use the ApplicationContext.
Calling Test test = new Test() isn't illegal, or even bad practice. It just means that Spring will have no awareness of this object, and it won't bother autowiring it's dependencies, or doing anything else that you'd expect Spring to do.
You don't necessarily need to use the applicationContext.xml file for ALL of your bean declarations. Many people favor annotations, which allow you to declare beans outside of the applicationContext.xml file.
It's worth nothing that Spring-managed beans are by default singletons (think of Servlets). If you want stateful beans that are Spring aware, you could use an ObjectFactoryCreatingFactoryBean to do something like this:
#Autowired
private ObjectFactory myWidgetFactory;
public void doStuff() {
Widget w = myWidgetFactory.getObject();
}
You can read more about this behaviour here:
http://static.springsource.org/spring/docs/3.0.x/api/org/springframework/beans/factory/config/ObjectFactoryCreatingFactoryBean.html
For me there's a big difference between objects that represent components of my application -- services, controllers, DAOs, utilities, etc. -- and objects that represent entities within my application -- Person, Order, Invoice, Account, etc. The former type of objects should absolutely be managed by Spring and injected. The latter type are typically created on the fly by the application, and that frequently will involve calling new. This is not a problem.
Test test = new Test() a bad way for
creating an instance?
Yes it is bad practice.
Should I always use the bean config
to get the objects/bean that I need?
Yes, if you are using Spring for dependency injection.
If yes, does that means I should have
all the object/bean definition in
spring applicationContext xml file?
Always! You could use Annotations too.

Resources