I have following #Configuration class, in which I am declaring a #Bean that depends on an #Autowired list of beans. However, this list is not complete when I am accessing to it. All #Bean definitions been executed, except the one defined in the same class.
#Configuration
public class MyConfig {
#Autowired
List<RequiredBean> requiredBeans;
#Bean(name="ProblemHere")
public CustomObject customObject() {
log.info(requiredBeans.size()); // 1 (debugging, I can see is the one defined in "AnotherConfigClass")
}
#Bean(name="reqBeanInsideClass")
public RequiredBean reqBean() {
// this method does not get executed
return new RequiredBean();
}
}
Having other classes like;
#Configuration
public class AnotherConfigClass {
#Bean(name="ThisOneGetsExecuted")
public RequiredBean reqBean() {
// this gets executed, and therefore, added to the list
return new RequiredBean();
}
}
Probably, the easiest solution would be to add #DependsOn("reqBeanInsideClass").
However:
I wonder why it works for all #Beans defined in different classes, but not in this one.
I'm not really sure that's exactly like that, and I'm afraid later on, another #Bean does not get executed
I guess the correct approach should be something like
#DependsOn(List<RequiredBean>) // Obviously this does not work
How should I solve this?
Update
I have copied the exact same class twice, in order to see what would happen, so now I have also:
#Configuration
public class MyConfig2 {
#Autowired
List<RequiredBean> requiredBeans;
#Bean(name="ProblemHere2")
public CustomObject customObject() {
log.info(requiredBeans.size());
}
#Bean(name="reqBeanInsideClass2")
public RequiredBean reqBean() {
// this method does not get executed
return new RequiredBean();
}
}
Amazingly, by doing this, both #Beans methods (ProblemHere & ProblemHere2) are called before both reqBeanInsideClass and reqBeanInsideClass2 methods.
For some reason I guess, Springboot is able to recognize #Beans required for a class as long as they are defined in another class.
Does this sound logic to anyone?
Can you not utilize the array input for #DependsOn rather than passing singular value, since it accepts String[]? That would wait for all the beans that are explicitly declared in the array before initializing, though has to be defined manually.
#Configuration
public class MyConfig {
#Autowired
List<RequiredBean> requiredBeans;
#Bean(name="customObject")
#DependsOn({"reqBeanInsideClass", "thisOneGetsExecuted"})
public CustomObject customObject() {
log.info(requiredBeans.size());
}
#Bean(name="reqBeanInsideClass")
public RequiredBean reqBean() {
return new RequiredBean();
}
}
#Autowired list of beans will be same as a single bean of same type, it will contain all beans with that type or with that superclass via springs injection, the problem is the ordering of bean initialization is not controlled properly, #DependsOn with array bean input should resolve this!
Or
You can make CustomObject bean #Lazy, so it will be initialized only when it is used within the code after initialization is done. The bean must not be used within another non-lazy bean I think. Just call some logic where an #Autowired CustomObject is used, it should instantiate the bean at that moment, where the list will contain all possible RequiredBeans
#Lazy
#Bean(name="customObject")
public CustomObject customObject() {
log.info(requiredBeans.size());
}
Related
Let's suppose I have a Wrapper with generic type:
#Component
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
public class Wrapper<T> {
private final Class<T> wrappedClass;
public Wrapper(Class<T> wrappedClass) {
this.wrappedClass = wrappedClass;
}
}
And I want to use this Wrapper with many classes (for example > 100). Is it possible to make Spring create singleton of wrapper for each generic type and pass generic class as parameter to constructor? For example, Spring must always inject the same instance of Wrapper<Foo>. If it is possible, please give example with java code configuration, but not with xml.
If I understood correctly you want to add beans of wrapper dynamically based on some criteria that some beans (like Foo / Bar) adhere to and some don't.
This is a kind of advanced stuff in spring, but in a nutshell you will have to implement a Bean Factory Post Processor that will be called automatically by spring during the startup.
This is a point where you could analyze the beans by iterating over all the "accessible" beans (like Foo / Bar and others) and for beans that should be wrapped you will create a bean definition of the wrapper, despite the fact that the wrapper itself is not a bean.
I've created a simple example to illustrate this. In my sample project I've put everything under package "wrappers":
#Wrappable
public class Foo {
}
#Wrappable
public class Bar {
}
public class ShouldNotBeWrapped {
}
Note that I've put an annotation #Wrappable - a custom annotation that will serve as a "differentiator" of what should be wrapped and what not. The processing of the annotation will be done in Bean Factory Post Processor.
The annotation is nothing special really, it should be acessible in runtime (spring is a runtime framework and be put on classes):
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
public #interface Wrappable {
}
The java config will add Foo, Bar, ShouldNotBeWrapped as beans and also Bean Factory Post Processor that I'll describe below:
#Configuration
public class WrappersJavaConfig {
#Bean
public Foo foo () {
return new Foo();
}
#Bean
public Bar bar () {
return new Bar();
}
#Bean
public ShouldNotBeWrapped shouldNotBeWrapped () {
return new ShouldNotBeWrapped();
}
#Bean
public WrappersEnrichmentBFPP wrappersEnrichmentBFPP () {
return new WrappersEnrichmentBFPP();
}
}
The Wrapper class itself for the sake of example has toString but it doesn't differ much from your wrapper presented in the question:
public class Wrapper<T> {
private T wrapped;
public Wrapper(T wrapped) {
this.wrapped = wrapped;
}
#Override
public String toString() {
return "Wrapper for" + wrapped;
}
}
And the Main class will list all the loaded beans and get their classes + call toString so that we could see that the wrappers are defined correctly:
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(WrappersJavaConfig.class);
String[] names = ctx.getBeanDefinitionNames();
for(String name : names) {
Object bean = ctx.getBean(name);
if(bean.getClass().getPackage().getName().startsWith("wrappers")) {
System.out.println(ctx.getBean(name).getClass() + " ==> " + ctx.getBean(name));
}
}
}
}
Sidenote, the "if" condition in the main method is because I don't want to print the beans that spring loads by itself (infra stuff, etc) - only my beans which all reside in package "wrappers" as I've mentioned above.
Now the BeanFactoryPostProcessor - is a regular bean in a sense that it gets registered in the java config and it looks like this (your implementation might be different but the idea is the same):
public class WrappersEnrichmentBFPP implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] bddNames = beanFactory.getBeanDefinitionNames();
for(String bddName : bddNames) {
Object bean = beanFactory.getBean(bddName);
if(bean.getClass().isAnnotationPresent(Wrappable.class)) {
BeanDefinition wrappedBdd = BeanDefinitionBuilder.genericBeanDefinition(Wrapper.class)
.addConstructorArgReference(bddName)
.getBeanDefinition();
((BeanDefinitionRegistry)beanFactory).registerBeanDefinition("wrapperFor" + bddName, wrappedBdd);
}
}
}
}
So I'm getting all the beans one by one in for-each loop, then I'm asking whether the bean has an annotation "wrappable" on it in the if condition. If it has - it must be wrapped.
In this case I create an "artificial" bean definition for Wrapper and add a constuctor that will reference my bean that should be wrapped.
Then I register the bean definition by adding it to the application context.
Run the code above and you'll see the output similar to mine:
class wrappers.WrappersJavaConfig$$EnhancerBySpringCGLIB$$f88f147d ==> wrappers.WrappersJavaConfig$$EnhancerBySpringCGLIB$$f88f147d#1283bb96
class wrappers.Foo ==> wrappers.Foo#74f0ea28
class wrappers.Bar ==> wrappers.Bar#f6efaab
class wrappers.ShouldNotBeWrapped ==> wrappers.ShouldNotBeWrapped#3c19aaa5
class wrappers.WrappersEnrichmentBFPP ==> wrappers.WrappersEnrichmentBFPP#3349e9bb
class wrappers.Wrapper ==> Wrapper forwrappers.Foo#74f0ea28
class wrappers.Wrapper ==> Wrapper forwrappers.Bar#f6efaab
As you see, two last lines are lines that correspond to the wrapper beans created for the same instances of Foo and Bar but nothing was created for the ShouldNotBeWrapped bean
The APIs used are somewhat obscure and look outdated, but again its pretty advanced stuff and works at the level of spring container infra itself. Having said that, there are a lot of tutorials about BeanFactoryPostProcessor-s.
Since Using BFPPs is not a usual task, and although I've provided the solution, I don't see any real usage of it, wrappers can't be used "instead" of Foo or Bar classes, do not have their APIs, etc. Maybe you could explain why do you need wrappers over some beans. Usually people use Aspects/BeanPostProcessors (not BFPP but BPP) to wrap the class into dynamic proxy (cglib / java.lang.Proxy) and add an additional behavior, stuff like #Transactional, cache handling and so forth is implemented in spring with BeanPostProcessors, so consider checking this direction as well.
It is possible and in fact a feature in spring.
Spring can inject your dependency with the correct generic type.The following example is from spring documentation.
Suppose you have an interface
public interface Store<T>{...}
and two beans. One implements Store,one implemenets Store.
#Configuration
public class MyConfiguration {
#Bean
public StringStore stringStore() {
return new StringStore();
}
#Bean
public IntegerStore integerStore() {
return new IntegerStore();
}
}
You can declare the type with the correct type parameter and spring will inject the right bean for you.
#Autowired
private Store<String> s1; // <String> qualifier, injects the stringStore bean
#Autowired
private Store<Integer> s2; // <Integer> qualifier, injects the integerStore bean
I am using an ObjectProvider to create instances of a prototype scope bean using the getObject() method. Something like this
#Configuration
class Config {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
SomeType typeOne() {
return new SomeType();
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
SomeType typeTwo(String param) {
return new SomeType(param);
}
}
#Service
class Service {
private ObjectProvider<SomeType> objectProvider;
public Service(
ObjectProvider<SomeType> objectProvider) {
this.objectProvider = objectProvider;
}
#Override
public String performAction() {
return getSomeType().doAction();
}
private SomeType getSomeType() {
return objectProvider.getObject();
}
}
But since there are two beans of the type that the ObjectProvider is trying to get (SomeType), I get a NoUniqueBeanDefinitionException. (And I do need the other bean of the same type, because that one I need to provide parameters using objectProvider.getObject(Object... params) )
Playing around and debugging Spring I saw that if you name your ObjectProvider exactly like your bean then it works, something like:
private ObjectProvider<SomeType> typeOne;
My question is, are there other ways to use an ObjectProvider and manage to resolve ambiguity, or is this approach the way to go?
Short answer is you just need to properly qualify the ObjectProvider you want injected, like this:
public Service(#Qualifier("typeOne") ObjectProvider<SomeType> objectProvider) {
this.objectProvider = objectProvider;
}
With Spring configuration, when you specify a bean via a method, and don't specify it's name with #Bean("NAME"), Spring uses the method name as the bean name.
Similarly, when injecting a bean that is not specified by #Qualifier("NAME"), Spring takes the injected variable as the name, if that don't exists or is not unique, you might get some exceptions informing you about this (like the NoUniqueBeanDefinitionException you facing).
So, if you match the bean name and the injected variable name you don't need to be more specific, but if you don't, #Qualifier is there to your rescue :D
I am trying to autowire a member in a class using the constructor.
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(ClassA objectA) {
myMember = objectA;
}
}
If I have multiple sources that create beans of ClassA, is it possible to have a duplicate constructor definition that instantiates based on the bean that was autowired into this class?
I want to do something like this:
#Component
public class MyClass {
private ClassA myMember;
#Autowire
public MyClass(#Qualifier ("qualifierA") ClassA objectA) {
myMember = objectA;
}
#Autowire
public MyClass(#Qualifier ("qualifierB") ClassA objectB) {
myMember = objectB;
}
}
I tried using #Qualifier this way, but it didn't work.
Is it possible to do what I'm trying to do, with Spring? How can I disambiguate based on the name (qualifierA) or (qualifierB), if the bean definition is like:
#Bean (name = "qualifierA")
public ClassA getQualifierA() {
...
}
#Bean (name = "qualifierB")
public ClassA getQualifierB() {
...
}
You can't have two constructors with the exact same signature in a single class in Java. Nor any other programming language I've ever encountered. You might use method-injection instead, with two methods (named differently, of course), mark them as #Autowired(required = false) and use the proper #Qualifier(...) to specify the instance you want to inject. You might want to handle the case when both instances are present in the spring context, so no unexpected things happen.
The short answer is: no, that is not possible. In Java you cannot have two constructors with exactly the same signature. And also, you can assign only one value to your "myMember".
However, what are you trying to accomplish here? It seems that in some occasions MyClass needs to use "objectA" and in other occasions, you need "objectB".
For these scenarios, you should not use autowiring (you can't), but simply use explicit wiring:
#Bean
MyClass myObject() {
return new MyClass(qualifierA());
}
I have two beans like this:
#Component
#Scope("prototype")
class A {
A(int number, B anotherBean) {
//...
}
}
#Component
class B {
//..
}
How can I build A and have B autowired? If I use new I won't get anotherBean's value, if I use autowiring I won't get number's value.
Edit: The number is calculated at runtime, so I can't use #Value like answers suggested.
I found this question today looking for an answer myself. After some consideration, here's a solution I think I'm going with. Basically I'm baking the factory method into the bean's class. This has the advantage of keeping the 'internal' dependencies (B in this example) all inside the 'A' class, and hidden from the caller, while still allowing prototype creation using a caller's runtime value. And it doesn't require yet another class file just for a factory method.
public class A {
private A (int number, B otherBean) {
...
}
#Configuration
public static class BeanConfig {
#Autowired
private B otherBean;
#Bean
#Scope("prototype")
public A makeA(int number) {
return new A(number, otherBean);
}
}
}
Then you can request a prototype bean instance while providing only the runtime value:
applicationContext.getBean(A.class, 1);
Make use of #Valueand inject the number's value via property. Your ClassA should look something like
#Component
#Scope("prototype")
class A {
#Autowired
A(#Value("${some.property}")int number, B anotherBean) {
//...
}
}
Edit (post additional condition of runtime value for number)
You can fetch the bean from BeanFactory.getBeans method as correctly pointed out by M.Deinum in comments.
You need to annotate the desired constructor-to-be-used as #Autowired, among other ways you can find with a Google search. As for your issue with 'number', there are ways to use annotations to set parameter values as well, also not difficult to find with a Google search.
Suppose I've a class Fruit and it's two subclasses - Apple and Grape:
class Fruit {
public void grind() { }
}
class Apple extends Fruit { }
class Grape extends Fruit { }
In spring properties file, I've a property that decides which bean to register at startup. At a time, I'll only have either Apple or Grape instance registered as a bean. The property is:
# This can be either apple or grape
app.fruit = apple
In the Java configuration file, I'm binding a String attribute using #Value with this property, and based on that, I'll create appropriate instance. I'm trying to use factory pattern here. So, I've a FruitFactory like this:
class FruitFactory {
private Map<String, Fruit> map = new HashMap<String, Fruit>();
public FruitFactory() {
map.put("apple", new Apple());
map.put("grape", new Grape());
}
public Fruit getFruit(String fruit) {
return map.get(fruit);
}
}
And here's my spring configuration class:
class SpringConfig {
#Value("${app.fruit}")
private String fruitType;
#Bean
public FruitFactory fruitFactory() {
return new FruitFactory();
}
#Bean
public Fruit getFruit() {
return fruitFactory().getFruit(fruitType);
}
}
So, here're my few questions:
Will the instances stored in the map inside the factory be spring managed bean? Is there any issue with the implementation? I've tried it, and it is working fine, and I'm confused whether the instances are really spring managed.
I was trying to implement it in a better way, so that when a new fruit comes, I don't have to modify my factory. On way is to provide a register() method in factory and let all the Fruit subclasses invoke it. But the issue is when and how the subclasses will be loaded? I'll not be using the classes, not before putting their instances into the map. Can anyone suggest a better way?
Edit:
As suggested in comment and answer, I've tried using #Profile instead of factory pattern. But I'm facing some issues in that. Here's what I've:
#Configuration
#Profile("apple")
class AppleProfile {
#Bean
public Fruit getApple() {
return new Apple();
}
}
#Configuration
#Profile("grape")
class GrapeProfile {
#Bean
public Fruit getGrape() {
return new Grape();
}
}
And in a ServletListener, I've set the active profile:
class MyServletListener implements ServletContextListener {
#Value("${app.fruit}")
private String fruitType;
public void contextInitialized(ServletContextEvent contextEvent) {
// Get Spring Context
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(contextEvent
.getServletContext());
context.getAutowireCapableBeanFactory().autowireBean(this);
ConfigurableEnvironment configEnvironment = (ConfigurableEnvironment) context.getEnvironment();
logger.debug("0;Setting Active Profile: " + cacheRetrievalMode);
configEnvironment.setActiveProfiles(cacheRetrievalMode);
}
}
This is properly setting the active profile, which I can see. The only issue is, the listener is declared before the ContextLoaderListener, and by the time this is executed, the beans are already been created. Is there any alternative?
Will the instances stored in the map inside the factory be spring
managed bean?
Making the FruitFactory a managed bean
#Bean
public FruitFactory fruitFactory() {
return new FruitFactory();
}
doesn't make any of the objects it's referring to managed beans. However, this
#Bean
public Fruit getFruit() {
return fruitFactory().getFruit(fruitType);
}
does make that one returned Fruit a managed bean. #Bean marks a method as a bean definition and bean factory (it creates the bean). The object you return will be managed by Spring's bean life cycle.
Is there any issue with the implementation?
It seems weird that you're creating a FruitFactory bean but also a Fruit from that same FruitFactory. Are you even going to inject the FruitFactory elsewhere in the application?
I was trying to implement it in a better way, so that when a new fruit
comes, I don't have to modify my factory
Seriously, your factory is messing everything up. Spring already does its job, and more! Annotations make your life easier. You can give an identifier to the #Bean. You can qualify the bean with #Qualifier (and then also qualify the injection target with #Qualifier). You can set a #Profile for when and under which conditions the bean should be initialized.
But the issue is when and how the subclasses will be loaded? I'll not
be using the classes, not before putting their instances into the map.
Can anyone suggest a better way?
You can use bean initMethods, which you specify as a #Bean annotation attribute, or a #PostConstruct annotated method to do post-initialization logic. You can use these to register the beans with the factory, which you'll have injected (but that design doesn't sound right to me, you'd have to show us more.)
You should also look into InitializingBean and FactoryBean.
For setting the active profile, one possibility is to do the following. Create an ApplicationContextInitializer which sets the active profile by reading from a .properties file. You won't be able to use #PropertySources here because this isn't a bean.
Something like
public class ProfileContextInitializer implements
ApplicationContextInitializer<ConfigurableApplicationContext> {
#Override
public void initialize(ConfigurableApplicationContext applicationContext) {
PropertySource<Map<String, Object>> source = null;
try {
source = new ResourcePropertySource("spring.properties");
String profile = (String) source.getProperty("active.profile");
System.out.println(profile);
ConfigurableEnvironment env = applicationContext.getEnvironment();
env.setActiveProfiles(profile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
You can register this in your deployment descriptor
<context-param>
<param-name>contextInitializerClasses</param-name>
<param-value>com.yourapp.ProfileContextInitializer</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
When the ContextLoaderListener is created, it will pick up and instantiate your class and call its initialize method. This is done before the WebApplicationContext is refreshed.
You should probably just set a VM argument for the active profile and avoid all of this.