Spring boot injection of inherited class - java

I'm developing upon a java core library were change is held to a minimum, it holds a class Foo, where Foo is used by a spring rest interface and autowired into the rest interface.
I have to extend Foo to override one of it's method that is called upon Foo.init(), to alter the initiation a bit.
My FooExtend is autowired from another class in my project, and I'm hoping to get these two to reference the same object, the FooExtend object, but at the moment I get one Foo object and one FooExtend. How should I solve this? Examples below
#Component
public class Foo{
#PostConstruct
private void init() {
startStuff();
}
protected void startStuff(){
//Stuff done here
}
}
#Component
public class FooExtend extends Foo{
#PostConstruct
private void init() {
//Nothing is done here
}
#Override
protected void startStuff(){
//Different altered stuff is done here
}
}

Try to exclude the Foo class from scan
#ComponentScan(value = {'your.package.here'}, excludeFilters = {
#ComponentScan.Filter(classes = { Foo.class })
})

There are 2 possible answers depending on your requirements:
1) You want to register both Foo and FooExtend in your Spring context.
In such case you can use #Qualifier annotation to inject one instance or another:
#Autowired
#Qualifier("fooExtend")
Foo foo;
2) You only want to register FooExtend in your Spring context.
#ComponentScan(value = {'your.package.here'}, excludeFilters = {
#ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class))
}
However it is required that Foo and FooExtend are in different packages so that FooExtend is NOT exluded by the above filter.

Related

How does spring identity/autowires beans when they have multiple interfaces?

Suppose I have interface foo and bar, then have multiple classes that implements both of them:
public interface InterfaceFoo{
int getFoo()
}
public interface InterfaceBar{
int getBar()
}
public class FooBarOne implements InterfaceFoo, InterfaceBar{
public int getFoo() { ... }
public int getBar() { ... }
}
public class FooBarTwo implements InterfaceFoo, InterfaceBar{
public int getFoo() { ... }
public int getBar() { ... }
}
Then I create beans for both of these classes:
#Configuration
#ComponentScan
public class Config {
#Bean
fooBarOne getFooBarOne() { return new FooBarOne(); }
#Bean
fooBarTwo getFooBarTwo() { return new FooBarTwo();}
}
Finally another bean which #Autowries in a list of all implementations of foo
#Configuration
#ComponentScan
public class FooConfig {
#Bean
#Autowired
public List<InterfaceFoo> fooFetcher(List<<InterfaceFoo>> listFoos) {
return listFoos;
}
}
My question is, how does Spring identify/autowire beans when they have multiple implementations of an interface? The above pseudo code seems to work, however, if I change the return type of the bean from the concrete class to an ibar, it is not picked up by the autowire:
#Configuration
#ComponentScan
public class Config {
#Bean
InterfaceBar getFooBarOne() { return new FooBarOne(); }
#Bean
InterfaceBar getFooBarTwo() { return new FooBarOne(); }
}
From the example above, spring does not pick these beans up when autowiring for implementations of ifoo. Switching the return type to ifoo works, which implies to me that spring looks at the return type of the bean rather than that of the returned object? Even though fooBarOne and fooBarTwo both implement foo and bar, do I need to return either the concrete class or interface ifoo if I want the autowire for List to pick it up?
Spring's default autowire mode is by type, so it makes sense that if you create two beans of type iBar, they will not be autowired as iFoo, even though the concrete classes are also instances of iFoo. Spring does not know about all of the interfaces that a class implements, it only knows of the type of beans that were created in its context.
When you attempt to autowire List<<iFoo>>, Spring will look in its context for all the beans of type iFoo to inject, which you have none.
Also, please read up on the Java naming conventions, you probably want your interfaces to just be Foo and Bar https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html
When declaring beans with #Bean-annotated methods, Spring assigns return type of the method as bean type, i.e. saves class name (ibar.class.getName()) to BeanDefinition, along with other object metadata. From now, spring does not care whether your class implements other interfaces, it just has your object and assigned type.
When autowiring, spring filters beans that match bean type and name constrains, provided by type of bean to be constructed
In this case, when trying to create List<iFoo>, spring can hook beans with type iFoo or types extending/implementing it, but not ibar, because ibar is not related to iFoo
If you need just List<iFoo>, and you are not using fooBarOne/fooBarTwo beans, practically it does not matter if you declare bean as iFoo or fooBarOne. But in general, you should prefer using interfaces over implementations, it will help to keep Dependency Inversion in your code.
And, always name your classes with capital letter.

Why does my direct autowire property injection turns into null? [duplicate]

This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 7 months ago.
So I try to inject an interface implemention through a field. But can't figure it out why it's null.
Package
com.a
Interfacex
com.b
Interfaceximpl
Interfacex.java
public interface Interfacex {
void doA ();
}
Interfaceximpl.java
#Component
public class Interfaceximpl implements interfacex {
#Override
void doA(){
// do something
}
}
Main.java
public class Main {
#Autowired
Interfacex interfacex;
public static void main (String args[]){ //....}
}
This interfacex seems to be null.
#Configuration
#ComponentScan("com")
public class AppConfig { // nothing here}
There is no such setter injection in my case. I just inject the interfacex with #Autowired. Why is it null?.
Are you really placing the #Autowired on the field of the main class or its just an illustration? If you do - it won't work because the class on which #Autowired can happen must be by itself managed by Spring. And in this case its obviously not, because its a special class - an entry point of the application...
I suggest to use something like this instead:
#Component
public class EntryPoint {
#Autowired
Interfacex interfacex;
public void foo() {
// interfacex shouldn't be null
// because everything is managed by spring now
interfacex.doA();
}
}
public class Main {
public static void main(..) {
ApplicationContext ctx = ...
EntryPoint ep = ctx.getBean(EntryPoint.class);
ep.foo();
}
}
#Autowired annotation will not be recognized and acted upon by spring unless the class is a bean.
In this case, the 'Main' class is not a bean. So, #Autowired will do nothing.
You need to make 'Main' a bean. One way to do that is to add #Component annotation to that class.
Also, this seems like just something you are trying out to understand the working. In that case, you can try my above suggestion.
If you are doing this for prod, then you should change the class structure, class and variable names and the way you are creating beans.

How does Spring "magically" know which Bean type to use?

Using Spring 5, I was puzzled as to how exactly the AnnotationConfigApplicationContext "magically" knows to use the correct implementation of my interface, since the references are to the interface not the implementing class.
Illustration
Note: Irrelevant code such as imports and unrelated behaviour has been ommitted
An interface CleaningTool and two implementing classes Broom and VacuumCleaner, with variations on the interface's method doCleanJob()
public interface CleaningTool {
void doCleanJob();
}
public class Broom implements CleaningTool {
#Override
public void doCleanJob() {
System.out.println("Sweep sweep sweep");
}
}
public class VacuumCleaner implements CleaningTool {
#Override
public void doCleanJob() {
System.out.println("Zoom zoom zoom");
}
}
Then, my AnnotationConfigApplicationContex uses my class AppConfig thusly:
#Configuration
public class AppConfig {
#Bean
public CleaningTool broom(){
return new Broom();
}
#Bean
public CleaningTool vacuum(){
return new VacuumCleaner();
}
}
Finally, in my MainApp class, where I invoke the AnnotationConfigApplicationContext's getBean() method, is where I tested this puzzling phenomenon which I, at first, expected not to work:
public class MainApp {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
CleaningTool vacuum = ctx.getBean(VacuumCleaner.class);
vacuum.doCleanJob();
}
}
Console output: Zoom zoom zoom
Even though my reference types in both my AppConfig and MainApp were CleaningTool, Spring somehow knew to seek out the Bean that matched the class VacuumCleaner.class, in such a way that the VacuumCleaner's behaviour was used.
How does this "magic" work?
#Configuration is meant to provide a tool to define beans.
Spring creates these beans (instances of classes) and stores them in the ApplicationContext.
You can think of the Application Context as a map that contains mapping between ids / classes of actual beans to the actual instances of corresponding singletons.
So when spring starts it creates both Broom and VacuumCleaner and places both of these beans into application context.
Then the application context is "ready" and you call the following line:
CleaningTool vacuum = ctx.getBean(VacuumCleaner.class);
Note, that you don't ask for the interface CleaningTool but for concrete class VacuumCleaner. In this case spring goes to its internal mappings and just retrieves the value (actual object) by concrete class. No magic here :)

Spring: Choosing constructor while Autowiring a Component

I've a Component as follows:
#Component
class A(){
private s;
public A(){}
public A(String s){this.s=s;}
}
Here is the other class Where I'm auto wiring the above class:
#Component
class B(){
#Autowire
private A a;
}
In the above autowiring, I need to use the parameterized constructor. How can I pass the constructor args?
You can't, at least not via #Autowired in B but there are other ways to do it:
Wire the parameter into A's constructor:
One constructor is annotated with #Autowired because:
As of Spring Framework 4.3, the #Autowired constructor is no longer
necessary if the target bean only defines one constructor. If several
constructors are available, at least one must be annotated to teach
the container which one it has to use.
#Component
class A(){
private s;
public A(){}
#Autowired
public A(#Value("${myval}") String s){this.s=s;}
}
Expose A as a #Bean
Straight from the docs:
#Configuration
public class AppConfig {
#Bean
public A a(#Value("${myval}") String s) {
return new A(s);
}
}
Construct A in B using an initialization callback
Docs
#Component
class B(){
private A a;
#Value("${myval}")
private String myval;
#PostConstruct
private void init()
{
a = new A(myval);
}
}
There is a concept of prototype bean which I think you require in your case. #Component will create a singleton bean and changing it in one place will change in all parent classes where this was injected.
You need to understand how to inject a prototype bean in singleton bean.
Follow this example
https://stackoverflow.com/a/25165971/949912
Just use setters instead of constructor.
If you want to create object by yourself with new keyword then this object will not be managed by container.

Inject spring bean dynamically

In a java-spring web-app I would like to be able to dynamically inject beans.
For example I have an interface with 2 different implementations:
In my app I'm using some properties file to configure injections:
#Determines the interface type the app uses. Possible values: implA, implB
myinterface.type=implA
My injections actually loaded conditionally relaying on the properties values in the properties file. For example in this case myinterface.type=implA wherever I inject MyInterface the implementation that will be injected will be ImplA (I accomplished that by extending the Conditional annotation).
I would like that during runtime - once the properties are changed the following will happen (without server restart):
The right implementation will be injected. For example when setting myinterface.type=implB ImplB will be injected where-ever MyInterface is used
Spring Environment should be refreshed with the new values and re-injected as well to beans.
I thought of refreshing my context but that creates problems.
I thought maybe to use setters for injection and re-use those setters once properties are re-configured. Is there a working practice for such a requirement?
Any ideas?
UPDATE
As some suggested I can use a factory/registry that holds both implementations (ImplA and ImplB) and returns the right one by querying the relevant property.
If I do that I still have the second challenge - the environment. for example if my registry looks like this:
#Service
public class MyRegistry {
private String configurationValue;
private final MyInterface implA;
private final MyInterface implB;
#Inject
public MyRegistry(Environmant env, MyInterface implA, MyInterface ImplB) {
this.implA = implA;
this.implB = implB;
this.configurationValue = env.getProperty("myinterface.type");
}
public MyInterface getMyInterface() {
switch(configurationValue) {
case "implA":
return implA;
case "implB":
return implB;
}
}
}
Once property has changed I should re-inject my environment. any suggestions for that?
I know I can query that env inside the method instead of constructor but this is a performance reduction and also I would like to think of an ider for re-injecting environment (again, maybe using a setter injection?).
I would keep this task as simple as possible. Instead of conditionally load one implementation of the MyInterface interface at startup and then fire an event that triggers dynamic loading of another implementation of the same interface, I would tackle this problem in a different way, that is much simpler to implement and maintain.
First of all, I'd just load all possible implementations:
#Component
public class MyInterfaceImplementationsHolder {
#Autowired
private Map<String, MyInterface> implementations;
public MyInterface get(String impl) {
return this.implementations.get(impl);
}
}
This bean is just a holder for all implementations of the MyInterface interface. Nothing magic here, just common Spring autowiring behavior.
Now, wherever you need to inject a specific implementation of MyInterface, you could do it with the help of an interface:
public interface MyInterfaceReloader {
void changeImplementation(MyInterface impl);
}
Then, for every class that needs to be notified of a change of the implementation, just make it implement the MyInterfaceReloader interface. For instance:
#Component
public class SomeBean implements MyInterfaceReloader {
// Do not autowire
private MyInterface myInterface;
#Override
public void changeImplementation(MyInterface impl) {
this.myInterface = impl;
}
}
Finally, you need a bean that actually changes the implementation in every bean that has MyInterface as an attribute:
#Component
public class MyInterfaceImplementationUpdater {
#Autowired
private Map<String, MyInterfaceReloader> reloaders;
#Autowired
private MyInterfaceImplementationsHolder holder;
public void updateImplementations(String implBeanName) {
this.reloaders.forEach((k, v) ->
v.changeImplementation(this.holder.get(implBeanName)));
}
}
This simply autowires all beans that implement the MyInterfaceReloader interface and updates each one of them with the new implementation, which is retrieved from the holder and passed as an argument. Again, common Spring autowiring rules.
Whenever you want the implementation to be changed, you should just invoke the updateImplementations method with the name of the bean of the new implementation, which is the lower camel case simple name of the class, i.e. myImplA or myImplB for classes MyImplA and MyImplB.
You should also invoke this method at startup, so that an initial implementation is set on every bean that implements the MyInterfaceReloader interface.
I solved a similar issue by using org.apache.commons.configuration.PropertiesConfiguration and org.springframework.beans.factory.config.ServiceLocatorFactoryBean:
Let VehicleRepairService be an interface:
public interface VehicleRepairService {
void repair();
}
and CarRepairService and TruckRepairService two classes that implements it:
public class CarRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a car");
}
}
public class TruckRepairService implements VehicleRepairService {
#Override
public void repair() {
System.out.println("repair a truck");
}
}
I create an interface for a service factory:
public interface VehicleRepairServiceFactory {
VehicleRepairService getRepairService(String serviceType);
}
Let use Config as configuration class:
#Configuration()
#ComponentScan(basePackages = "config.test")
public class Config {
#Bean
public PropertiesConfiguration configuration(){
try {
PropertiesConfiguration configuration = new PropertiesConfiguration("example.properties");
configuration
.setReloadingStrategy(new FileChangedReloadingStrategy());
return configuration;
} catch (ConfigurationException e) {
throw new IllegalStateException(e);
}
}
#Bean
public ServiceLocatorFactoryBean serviceLocatorFactoryBean() {
ServiceLocatorFactoryBean serviceLocatorFactoryBean = new ServiceLocatorFactoryBean();
serviceLocatorFactoryBean
.setServiceLocatorInterface(VehicleRepairServiceFactory.class);
return serviceLocatorFactoryBean;
}
#Bean
public CarRepairService carRepairService() {
return new CarRepairService();
}
#Bean
public TruckRepairService truckRepairService() {
return new TruckRepairService();
}
#Bean
public SomeService someService(){
return new SomeService();
}
}
By using FileChangedReloadingStrategy your configuration be reload when you change the property file.
service=truckRepairService
#service=carRepairService
Having the configuration and the factory in your service, let you can get the appropriate service from the factory using the current value of the property.
#Service
public class SomeService {
#Autowired
private VehicleRepairServiceFactory factory;
#Autowired
private PropertiesConfiguration configuration;
public void doSomething() {
String service = configuration.getString("service");
VehicleRepairService vehicleRepairService = factory.getRepairService(service);
vehicleRepairService.repair();
}
}
Hope it helps.
If I understand you correctly then the goal is not to replace injected object instances but to use different implementations during interface method call depends on some condition at run time.
If it is so then you can try to look at the Sring TargetSource mechanism in combination with ProxyFactoryBean. The point is that proxy objects will be injected to beans that uses your interface, and all the interface method calls will be sent to TargetSource target.
Let's call this "Polymorphic Proxy".
Have a look at example below:
ConditionalTargetSource.java
#Component
public class ConditionalTargetSource implements TargetSource {
#Autowired
private MyRegistry registry;
#Override
public Class<?> getTargetClass() {
return MyInterface.class;
}
#Override
public boolean isStatic() {
return false;
}
#Override
public Object getTarget() throws Exception {
return registry.getMyInterface();
}
#Override
public void releaseTarget(Object target) throws Exception {
//Do some staff here if you want to release something related to interface instances that was created with MyRegistry.
}
}
applicationContext.xml
<bean id="myInterfaceFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="MyInterface"/>
<property name="targetSource" ref="conditionalTargetSource"/>
</bean>
<bean name="conditionalTargetSource" class="ConditionalTargetSource"/>
SomeService.java
#Service
public class SomeService {
#Autowired
private MyInterface myInterfaceBean;
public void foo(){
//Here we have `myInterfaceBean` proxy that will do `conditionalTargetSource.getTarget().bar()`
myInterfaceBean.bar();
}
}
Also if you want to have both MyInterface implementations to be Spring beans, and the Spring context could not contains both instances at the same time then you can try to use ServiceLocatorFactoryBean with prototype target beans scope and Conditional annotation on target implementation classes. This approach can be used instead of MyRegistry.
P.S.
Probably Application Context refresh operation also can do what you want but it can cause other problems such as performance overheads.
This may be a duplicate question or at least very similar, anyway I answered this sort of question here: Spring bean partial autowire prototype constructor
Pretty much when you want a different beans for a dependency at run-time you need to use a prototype scope. Then you can use a configuration to return different implementations of the prototype bean. You will need to handle the logic on which implementation to return yourself, (they could even be returning 2 different singleton beans it doesn't matter) But say you want new beans, and the logic for returning the implementation is in a bean called SomeBeanWithLogic.isSomeBooleanExpression(), then you can make a configuration:
#Configuration
public class SpringConfiguration
{
#Bean
#Autowired
#Scope("prototype")
public MyInterface createBean(SomeBeanWithLogic someBeanWithLogic )
{
if (someBeanWithLogic .isSomeBooleanExpression())
{
return new ImplA(); // I could be a singleton bean
}
else
{
return new ImplB(); // I could also be a singleton bean
}
}
}
There should never be a need to reload the context. If for instance, you want the implementation of a bean to change at run-time, use the above. If you really need to reload your application, because this bean was used in constructors of a singleton bean or something weird, then you need to re-think your design, and if these beans are really singleton beans. You shouldn't be reloading the context to re-create singleton beans to achieve different run-time behavior, that is not needed.
Edit The first part of this answer answered the question about dynamically injecting beans. As asked, but I think the question is more of one: 'how can I change the implementation of a singleton bean at run-time'. This could be done with a proxy design pattern.
interface MyInterface
{
public String doStuff();
}
#Component
public class Bean implements MyInterface
{
boolean todo = false; // change me as needed
// autowire implementations or create instances within this class as needed
#Qualifier("implA")
#Autowired
MyInterface implA;
#Qualifier("implB")
#Autowired
MyInterface implB;
public String doStuff()
{
if (todo)
{
return implA.doStuff();
}
else
{
return implB.doStuff();
}
}
}
You can use #Resource annotation for injection as originally answered here
e.g.
#Component("implA")
public class ImplA implements MyInterface {
...
}
#Component("implB")
public class ImplB implements MyInterface {
...
}
#Component
public class DependentClass {
#Resource(name = "\${myinterface.type}")
private MyInterface impl;
}
and then set the implementation type in properties file as -
myinterface.type=implA
Be aware that - if interesting to know about - FileChangedReloadingStrategy makes your project highly dependent on the deployment conditions: the WAR/EAR should be exploded by container and your should have direct access to the file system, conditions that are not always met in all situations and environments.
You can use Spring #Conditional on a property value. Give both Beans the same name and it should work as only one Instance will be created.
Have a look here on how to use #Conditional on Services and Components:
http://blog.codeleak.pl/2015/11/how-to-register-components-using.html
public abstract class SystemService {
}
public class FooSystemService extends FileSystemService {
}
public class GoSystemService extends FileSystemService {
}
#Configuration
public class SystemServiceConf {
#Bean
#Conditional(SystemServiceCondition.class)
public SystemService systemService(#Value("${value.key}") value) {
switch (value) {
case A:
return new FooSystemService();
case B:
return new GoSystemService();
default:
throw new RuntimeException("unknown value ");
}
}
}
public class SystemServiceCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return true;
}
}

Categories