First time using Profiles and need help.
I have an abstract base class (DecisionManagementRuleExecutor) that gets its dependency (RuleHandler) wired through annotation.
#Component
public class RuleHandler {......
public abstract class DecisionManagementRuleExecutor<M extends PersistentEntity,T extends Response> implements RuleExecutor<M,T>{
#Autowired
RuleHandler ruleHandler;
When I run with 'itest' profile, I want 'ITestRuleHandler' a child of 'RuleHandler' to be wired.
Where 'ItestRuleHandler' is
#Component
#ActiveProfiles(value = "itest")
public class ITestRuleHandler extends RuleHandler {
I see that in the logs that active profile is 'itest'
System.getProperty("spring.profiles.active")
I am pasting the log for the wiring
Processing injected element of bean 'vendorServiceRuleExecutor': AutowiredFieldElement for c.a.p.d.RuleHandler c.a.p.d.s.DecisionManagementRuleExecutor.ruleHandler
Returning cached instance of singleton bean 'ITestRuleHandler'
Creating shared instance of singleton bean 'ruleHandler'
Creating instance of bean 'ruleHandler'
Eagerly caching bean 'ruleHandler' to allow for resolving potential circular references
Finished creating instance of bean 'ruleHandler'
Autowiring by type from bean name 'vendorServiceRuleExecutor' to bean named 'ruleHandler'
Finished creating instance of bean 'vendorServiceRuleExecutor'
Edit:
Changed the 'RuleHandler' as an interface and now I am getting this error:
No qualifying bean of type [c.a.p.d.RuleHandler] is defined: expected single matching bean but found 2: ITestRuleHandler,iTestRuleHandler
To make the implementation ITestRuleHandler available for the itest profile, you need to declare your class as:
#Component
#Profile("itest")
public class ITestRuleHandler extends RuleHandler
#ActiveProfiles activates one or more profiles, not expose a component for a profile. This should be applied to one of the test (or consuming) classes to activate a profile for testing (or consumption).
Related
From the official documentation:
When registered by type, any existing single bean of a matching type (including subclasses) in the context will be replaced by the mock
What if the service under test is autowired in the constructor, though? E.g. in Kotlin (I suppose #MockkBean and #MockBean work the same regarding DI):
#RunWith(SpringRunner.class)
class ExampleTests #Autowired constructor(val userOfService: UserOfService) {
#MockkBean
private lateinit var service: ExampleService
...
}
I would expect this example to fail because in order to instantiate ExampleTests Spring has to first obtain a proper instance of UserOfService. That shouldn't be possible at that time, though, because there's no bean of type ExampleService in the application context yet.
Contrary to my expectation, this works. How is it possible?
Because you miss the other part from the documentation :
In either case, if no existing bean is defined a new one will be
added.
So #MockBean will also instantiate a bean automatically if that bean is not found in the spring context.
The sequence of actions are mainly as follows :
Start up the spring context which create all the spring BeanDefinition only that are registered in the spring context.
Process #MockBean which will replace the BeanDefinition in (1) or create a new BeanDefinition
Actually instantiate all the beans based on these BeanDefinition. It will handle which bean to be actually instantiated first and later.
Create a test instance (i.e ExampleTests) to execute its test methods. If any beans required to be auto-wired into the test instance are not created , it will fail.
So as long as you define UserOfService bean , ExampleTests can be instantiated as you are now using #MockBean on the ExampleService which means it must exist no matter you define it or not in the spring context for the test.
We register some beans with custom bean definition, in a BeanPostProcessor we need to access the bean definition
public Object postProcessBeforeInitialization(Object bean, String beanName)
I can make it ApplicationContextAware and then do:
((ConfigurableApplicationContext)applicationContext).getBeanFactory().getBeanDefinition(beanName)
but is it assured that the applicationContext is always ConfigurableApplicationContext?
Is there another way to access the bean definition from a BeanPostProcessor?
If you need to access BeanDefinition instances, you should use BeanFactoryPostProcessor instead of BeanPostProcessor.
BeanFactoryPostProcessor
Allows for custom modification of an application context's bean
definitions, adapting the bean property values of the context's
underlying bean factory. A BeanFactoryPostProcessor may interact with and modify bean definitions, but never bean instances.
BeanPostProcessor
Factory hook that allows for custom modification of new bean
instances, e.g. checking for marker interfaces or wrapping them with
proxies.
Using Spring 3.1. If I want to retrieve a bean with prototype scope (i.e. I want a different instance of the class each time), is it possible to retrieve the bean without having to use an ApplicationContextaware class?
This is how I do it at present
#Component
#Qualifier("MyService")
public class MyServiceImpl implements MyService {
#Override
public void doSomething() {
Blah blah = (Blah)ApplicationContextProvider.getContext().getBean("blah");
blah.setThing("thing");
blah.doSomething();
}
}
#Component("blah")
#Scope("prototype")
public class Blah {
....
}
where ApplicationContextProvider implements ApplicationContextAware.
Is it possible to do this with annotations or simple Spring configuration without having to use an ApplicationContextAware class?
Spring has some fairly sophosticated methods for achieving what you're after...
See the spring documentation: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html#beans-factory-scopes-other-injection
Searching for spring proxy scope on google also threw up some results...
You don't really need a ApplicationContextAware. You just need a BeanFactory (ApplicationContextAware is just a convinient way to get it).
A bean with scope prototype just means that everytime ApplicationContext.getBean is called a new instance of the bean is created. If you try to inject a prototype bean in a singleton, your prototype bean will be injected once (and so is no more a prototype).
There is something called method injection that may help you if you really need it, but it is more complex than simply calling applicationContext.getBean().
i have a little trouble in Spring with two component of a service.
I have this component:
#Component
public class SmartCardWrapper
and this one:
#Component
public class DummySmartCardWrapper extends SmartCardWrapper
The service autowire both but spring fails due this expection:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.cinebot.smartcard.SmartCardWrapper] is defined: expected single matching bean but found 2: [dummySmartCardWrapper, smartCardWrapper]
Why it doesn't use class names?
That's one of the most basic concepts of Spring - Inversion of Control.
You don't need to declare your dependencies using their implementation types (to avoid coupling with implementation). You can declare them using interfaces or superclasses instead, and make Spring find the proper implementation class in the context.
In other words, bean are not distinguished by their implementation classes, because you may want to change implementation class of a bean without changing the beans that depend on it. If you want to distinguish between different beans of the same type, use logical bean names instead:
#Autowired #Qualifier("smartCardWrapper")
private SmartCardWrapper smardCardWrapper;
#Autowired #Qualifier("dummySmartCardWrapper")
private SmartCardWrapper dummySmardCardWrapper;
I have a number of Spring beans, some of which are in a shared library jar. I can't seem to get #Qualifier to work.
I have default-autowire set to "byType", this is using Spring 3.1.0.M2 and running as a standalone executable. If I remove "TestTwoBean" from the shared library the project executes as expected.
myproj-shared-lib.jar:
#Service
public class TestOneBean implements ITestBean {
}
#Service
public class TestTwoBean implements ITestBean {
}
myproj.jar:
#Service
public class TestConsumerBean {
#Autowired #Qualifier("testOneBean")
private ITestBean bean;
}
I get the "no unique bean with name" exception at runtime:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'testConsumerBean' defined in file [-]:
Unsatisfied dependency expressed through bean property 'bean': : No
unique bean of type [com.myco.ITestBean] is defined: expected single
matching bean but found 2: [testOneBean, testTwoBean]; nested
exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type [com.myco.TestBean] is defined: expected single
matching bean but found 2: [testOneBean, testTwoBean] at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1167)
...
Does #Qualifier not work in this situation? Is there a known workaround?
Are you sure you want to use autowire by type AND annotation injection? Autowire by type means spring will attempt to inject detected setters and constructor parameters using by type lookup even if they aren't annotated for injection.
At the same time you are trying to inject fields by name. Your #Service annotated classes produce beans with names defaulting to the class name, "testOneBean" and "testTwoBean" respectively. #Qualifier uses bean names as correct matches. The recommended way of doing "by name" injection though is by using #Resource(name="testOneBean"). I can only guess spring tries injection by type due to autowire mode set to by type (which I doubt you really need).
I would recommend reverting to default autowire mode and using #Resource for wiring by name.