I have an interface
#Component("a")
#Scope("prototype")
Public interface A{
.....
}
and the b class that implement interface a
public class B implement A{
...
}
and Junit test class
public class PartyTest {
private static BeanFactory factory = null;
#BeforeClass
public static void loadSpring() {
ClassPathXmlApplicationContext applicationContext =
new ClassPathXmlApplicationContext(new String[]{"/spring/mainContext.xml"});
factory = (BeanFactory) applicationContext;
}
#Test
public void personSaveTest() {
A a = (A) factory.getBean("a");
}
}
it throws
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'a' is defined.
My question is, Why i cannot load interface? And if I use #Component("b") on the top of class b it can load class B but it can not load interface A.
Spring managed components are "real instances" of something, so they must always be instances of a concrete implementation (which must be concrete class). You cannot make instances of interfaces or abstract classes.
Note, that this has nothing to do with the type (what might have confused you): Of course, such instances are of any type in the type hierarchy up from the concrete class. In your example, an instance of B is of type B and A.
Spring need a concrete "thing" in order to create a bean. So #Component is misplaced (should be on B). Same goes for #Scope which target a future bean (so something concrete).
Related
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 :)
I have a parameterized class that implements the FactoryBean interface:
public class DogFactory<T extends Dog> implements FactoryBean<T> {
// ...
}
What I want is to use this factory for spawning objects of different classes (all of these classes extend Dog). So I imagined that I could do something like the following:
public class ShepherdService {
private DogFactory<Shepherd> shepherdFactory;
public ShepherdService(
#Autowired
DogFactory<Shepherd> shepherdFactory
) {
this.shepherdFactory = shepherdFactory;
}
// ...
}
Alas, I get the following error: Couldn't autowire. No beans of DogService<Shepherd> type found. :-(
How to inject it and use as DogFactory<Shepherd> or DogFactory<Corgi> (not just DogFactory)?
And another question. I also need to pass the Shepherd.class (or Corgi.class) to this bean, so it could "know" at run-time, objects of what exactly class should it produce. Is there a way to do that?
Or should I forget about FactoryBean and instantiate the factory as a regular class? Of course, I could do it this way:
DogFactory<Shepherd> shepherdFactory = new DogFactory<Shepherd>(Shepherd.class);
It would work perfectly, but I'd like to use FactoryBean as I use it for other factories in this project, so I would like to stick to FactoryBean.
Thanks in advance!
Update 1
Maybe I should clarify it more precise. What I need is a factory that could produce objects of different classes. All these classes should be extensions of the certain class (e.g., Shepherd and Corgi - all these classes extend Dog). And as the final result I actually need something like that:
public class DogService<T extend Dog> {
private DogFactory<T> dogFactory;
#Autowired
public DogService(DogFactory<T> dogFactory) {
this.dogFactory = dogFactory;
}
public T spawnDog(Color color) {
T dog = DogFactory.getObject(color);
return dog;
}
}
But it seems that I can't make a "universal" factory with the FactoryBean interface, so I can't do something like that:
public class DogFactory<T extends Dog> implements FactoryBean<T> {
// ...
}
Instead of that I have to do something like the following:
public class ShepherdFactory implements FactoryBean<Shepherd> {
// ...
}
public class CorgiFactory implements FactoryBean<Corgi> {
// ...
}
Is that true?
Thanks!
What I want is to instantiate this factory in another class
If you mean "having the factory injected in the class instead of the bean it creates", you could inject the factory by prefixing its name with an ampersand:
public class ShepherdService {
private DogFactory<Shepherd> shepherdFactory;
#Qualifier("&dogFactory")
public ShepherdService(DogFactory<Shepherd> shepherdService) {
this.shepherdService = shepherdService;
}
}
From the Spring documentation (section 3.8.3):
When you need to ask a container for an actual FactoryBean instance
itself, not the bean it produces, you preface the bean id with the
ampersand symbol & (without quotes) when calling the getBean method of
the ApplicationContext. So for a given FactoryBean with an id of
myBean, invoking getBean("myBean") on the container returns the
product of the FactoryBean, and invoking getBean("&myBean") returns
the FactoryBean instance itself.
Furthermore, my guess is that the FactoryBean is not picked up as a Spring bean as your snippets did not contain an XML config section, a Java config section, or a #Component annotation. I would explicitly declare the factory bean in a #Configuration annotated class, or annotate the factory class with #Component.
[edit]
But it seems that I can't make a "universal" factory with the
FactoryBean interface, so I can't do something like that:
You could still have a single Configuration class in which you declare all the factory beans.
#Configuration
public class DogFactoryConfig {
#Bean
public DogFactory<Shepherd> shepherdFactory() {
return new DogFactory<Shepherd>();
}
#Bean
public DogFactory<Corgi> corgiFactory() {
return new DogFactory<Corgi>();
}
}
And remove the #Component annotation from your DogFactory if it is present.
So, I wrote an extension which registers bean I am trying to create. The bean gets scanned by CDI and I can get it using:
MyInterface myInterface = CDI.current().select(MyInterface.class).get();
And I can then access myInterface.myMethod();
However, when I try to inject my bean using:
#Inject
#MyBean
MyInterface myInterface;
it is not injected and is null.
What I want to achieve is that I specify interface, which defines some methods,then my code generates instance of this interface and returns proxy of interface type:
// defined interface
#RegisterAsMyBean
interface MyInterface {
void myMethod();
}
// usage in code:
#Inject
#MyBean
MyInterface myInterface;
I declared my bean like this:
public class MyExtension implements Extension {
public void register(#Observes #WithAnnotations(RegisterAsMyBean.class) ProcessAnnotatedType<?> aType) {
Class<?> typeDef = aType.getAnnotatedType().getJavaClass();
if(typeDef.isInterface()) {
proxyTypes.add(typeDef);
aType.veto();
}
}
}
public class BeanCreator implements Bean<Object> {
#Override
public Object create(CreationalContext<Object> creationalContext) {
// my instance building logic
}
// ... other overriden methods
}
Also in META-INF/services/javax.enterprise.inject.spi.Extension I put reference to MyExtension
The problem was in bean creation lifecycle - i was trying to create bean in processAnnotatedType cycle, while I should have done that during afterBeanDiscovery cycle.
After moving my bean creation logic to appropriate cycle the bean is created and properly injected.
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.
In my spring-based project I have a core module ('core') with a class
#Component
public class Superclass {
// stuff
}
instances of which are injected by type throughout the code like this:
public class AService {
#Autowired
private Superclass superclass;
// service stuff
}
I also have two other modules that depend on the core module and one of which (let's call it 'module1') extends Superclass:
#component
public class Subclass extends Superclass {
// overridden stuff
}
The other module ('module2') uses Superclass as is.
Now I want that when I compile and run 'child1' an instance of Subclass is used everywhere an instance of Superclass is expected. So I write a configuration class:
#Configuration
public class Module2Configuration {
#Bean
public Superclass superclass(){
return new Subclass();
}
}
When I run this I see both Superclass and Subclass instantiated which is definitely not what I want. How do specify in 'module1' which type Spring should instantiate?
You can use #Qualifier("some name") annotation.
There is more information about that: http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/
Spring eagerly instantiates singleton beans as stated in the documentation:
By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process.
which might explain why both #Components are created.
To specifiy which implementation is provided as a dependency you might want to check on Qualifiers that enable to choose between different implementations. In combination with lazy loading this should do the trick.
Depending on your personal taste you could also use delegation instead of inheritance using a separated interface:
public interface MyService {
public String foobar(int baz);
}
public static class CommonBehavior {
// whatever is used by Superclass and Subclass
}
#Component #Lazy
public class FormerSuperClass implements MyService {
private final CommonBehavior ...;
...
}
#Component #Lazy
public class FormerSubClass implements MyService {
private final CommonBehavior ...;
...
}
Good luck!
There are 2 methods: Use #Qualifier("SubclassName") Or Mark your subclass as #Component and declare the subclass when #Autowired
In your case:
Use #Qualifier("SubclassName")
#Component
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
#Qualifier("Subclass")
private Superclass superclass;
// service stuff
}
2.Mark your subclass as #Component and declare the subclass when #Autowired
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
private Subclass subclass;
// service stuff
}