I'm trying to learn the basics of Spring and have defined this class?
public class Processor {
public Processor() {
this.setup();
}
private void setup(){
//run some setup code
}
public String processString(String str) {
// process the string
return str;
}
}
I want to Spring enable this class so I use a factory bean:
Reading https://www.baeldung.com/spring-factorybean I use:
public class Processor implements FactoryBean<Processor> {
#Override
public Processor getObject() throws Exception {
return new Processor();
}
#Override
public Class<?> getObjectType() {
return Processor.class;
}
}
To Test:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = ProcessorFactory.class)
public class ProcessorTest {
#Autowired
private Processor processor;
#Test
public void testProcessor() {
//Some tests
}
}
This works as expected.
When I try to use
#Autowired
private Processor processor;
elsewhere in my project I receive compile-time error :
Could not autowire. No beans of 'Processor' type found.
Have I not setup the factory correctly? I should annotate the Processor object to indicate it is to be autowired ? Perhaps this is not a valid use case for Factory ?
In general, factory beans are pretty outdated, first spring versions indeed used this approach, but spring has evolved since that time.
The Factory bean itself should be registered in the spring configuration (the very first versions of spring used xml based configuration because Java Annotation did not exist at that time) so the tutorial contains the XML configuration example. Anyway, that's probably the reason of failure. In the test you should also specify the path to the xml configuration otherwise the factory bean won't be loaded.
You can use these factory beans (they're still supported) but they have the following downsides:
They couple your code to the spring framework
A lot of boilerplate (usually in typical application there can be hundreds of beans, so creating a Factory Bean for each one is an overkill).
So you can:
Instead of using Factory Beans, annotate the Processor with #Component annotation (or more specialized #Service).
Alternatively Use Java configuration:
#Configration
public class MyConfig {
#Bean
public Processor processor() {
// optionally slightly customize the creation of the class if required;
return new Processor();
}
}
Related
I have a spring-boot app that now needs to support multiple Object stores and selectively use the desired store based on the environment. Essentially what i have done is create an interface that each store repository then implements.
I have simplified the code for the examples.
I have created 2 beans for each store type based on the spring profile determining the env:
#Profile("env1")
#Bean
public store1Sdk buildClientStore1() {
return new store1sdk();
}
#Profile("env2")
#Bean
public store2Sdk buildClientStore2() {
return new store2sdk();
}
in the service layer I have autowired the interface and then in the repositories i have used #Profile to specify which instance of the interface to use.
public interface ObjectStore {
String download(String fileObjectKey);
...
}
#Service
public class ObjectHandlerService {
#Autowired
private ObjectStore objectStore;
public String getObject(String fileObjectKey) {
return objectStore.download(fileObjectKey);
}
...
}
#Repository
#Profile("env1")
public class Store1Repository implements ObjectStore {
#Autowired
private Store1Sdk store1client;
public String download(String fileObjectKey) {
return store1client.getObject(storeName, fileObjectKey);
}
}
When I start the application with the configured "env" this actually runs as expected. however when running the test I get the "no qualifying bean of type ObjectStore. expected at least 1 bean which qualifies as autowire candidate."
#ExtendWith({ SpringExtension.class })
#SpringBootTest(classes = Application.class)
#ActiveProfiles("env1,test")
public class ComposerServiceTest {
#Autowired
private ObjectHandlerService service;
#Test
void download_success() {
String response = service.getObject("testKey");
...
}
}
As noted in the #ActiveProfile on the test class there are some other environments e.g. dev,test,prod. I have tried playing around with Component scan, having impl and interface in the same package, etc, to no success. I feel like I am missing something obvious with the test setup. But could be something with my overall application config? my main aim with the solution is to avoid having something a long the lines of
if (store1Sdk != null) {
store1Sdk.download(fileObjectKey);
}
if (store2Sdk != null) {
store2Sdk.download(fileObjectKey);
}
Try #ActiveProfiles({"env1", "test"}).
Activate multiple profiles using #ActiveProfiles and specify profiles as an array.
this probrom because Store1Repository use #Profile("env1"), when you use #test,this class not invoke. try delete #Profile("env1") of Store1Repository.
if you use #test, both of store1Sdk/store2Sdk don't instanse, try add default instanse.eg:
#Bean
public store2Sdk buildClientStoreDefault() {
return new store2sdk();
}
I am in the process of developing a common java library with reusable logic to interact with some AWS services, that will in turn be used by several consumer applications. For reasons outlined here, and the fact that Spring Boot seems to provide a lot of boilerplate free code for things like SQS integration, I have decided to implement this common library as a custom spring boot starter with auto configuration.
I am also completely new to the Spring framework and as a result, have run into a problem where my auto-configured class's instance variables are not getting initialized via the AutoWired annotation.
To better explain this, here is a very simplified version of my common dependency.
CommonCore.java
#Component
public class CommonCore {
#AutoWired
ReadProperties readProperties;
#AutoWired
SqsListener sqsListener; // this will be based on spring-cloud-starter-aws-messaging
public CommonCore() {
Properties props = readProperties.loadCoreProperties();
//initialize stuff
}
processEvents(){
// starts processing events from a kinesis stream.
}
}
ReadProperties.java
#Component
public class ReadProperties {
#Value("${some.property.from.application.properties}")
private String someProperty;
public Properties loadCoreProperties() {
Properties properties = new Properties();
properties.setProperty("some.property", someProperty);
return properties;
}
}
CoreAutoConfiguration.java
#Configuration
public class CommonCoreAutoConfiguration {
#Bean
public CommonCore getCommonCore() {
return new CommonCore();
}
}
The common dependency will be used by other applications like so:
#SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
public class SampleConsumerApp implements ApplicationRunner {
#Autowired
CommonCore commonCore;
public SampleConsumerApp() {
}
public static void main(String[] args) {
SpringApplication.run(SampleConsumerApp.class, args);
}
#Override
public void run(ApplicationArguments args) {
try {
commonCore.processEvents();
} catch (Exception e) {
e.printStackTrace();
}
}
}
The main problem I have like I mentioned, is the AutoWired objects in the CommonCore instance are not getting initialized as expected. However, I think the actual problems are more deeply rooted; but due to my lack of understanding of the Spring framework, I am finding it difficult to debug this on my own.
I am hoping for a few pointers along these points
Does this approach of developing a custom starter make sense for my use case?
What is the reason for the AutoWired dependencies to not get initialized with this approach?
Wild guess, but I think it's because of the order of how things are constructed. I am talking about this class:
#Component
public class CommonCore {
#AutoWired
ReadProperties readProperties;
#AutoWired
SqsListener sqsListener; // this will be based on spring-cloud-starter-aws-messaging
public CommonCore() {
Properties props = readProperties.loadCoreProperties();
//initialize stuff
}
processEvents(){
// starts processing events from a kinesis stream.
}
}
You are trying to use a Spring injected component in a constructor, but constructor is called before Spring can do its #Autowire magic.
So one option is to autowire as a constructor argument
Something like this (untested):
#Component
public class CommonCore {
private final ReadProperties readProperties;
private final SqsListener sqsListener; // this will be based on spring-cloud-starter-aws-messaging
#AutoWired
public CommonCore(SqsListener sqsListener, ReadProperties readProperties) {
this.readProperties = readPropertis;
this.sqsListener = sqsListener;
Properties props = readProperties.loadCoreProperties();
//initialize stuff
}
processEvents(){
// starts processing events from a kinesis stream.
}
}
Sidenote: I prefer to use dependency injection via constructor arguments always, wherever possible. This also makes unit testing a lot easier without any Spring specific testing libraries.
I'm having two spring(4.2) java configurations, one in a base module and one in a client specific module:
#Configuration
public class BaseConfig {
#Bean
public A getA() {
return new A("aaa");
}
}
#Configuration
public class ClientConfig {
#Bean
public A getA() {
return new A("bbbb");
}
}
During the app load there is always BaseConfig.getA() called, how can I ovverride the base bean factory configuration to have some client specific stuff?
Personally I would NEVER override a bean in spring! I have seen people spend too much time debugging issues related to this. For the same reason I would never use #Primary.
In this case I would have 3 contexts
Context that contains beans unique to the parent context
Context that contains beans unique to the child context
Abstract context that contains all shared beans.
This way you will specify the 2 contexts to load. This could be done programatically, or using profiles. Potentially you will need more contexts, because you probably want some of your beans to be different in tests.
I think that you should take a look at the #Profile annotation. You could simply split configuration into different base and client specific one like:
#Configuration
#Profile("base")
public class BaseConfig {
#Bean
public A getA() {
return new A("aaa");
}
}
#Configuration
#Profile("client")
public class ClientConfig {
#Bean
public A getA() {
return new A("bbbb");
}
}
now run the specific profile by adding
#ActiveProfiles("base") on application main method
spring.profiles.active=base entry in application.properties
or even pass profile name into jvm params
I'm not sure on how to extend bean config classes. One solution is to mark the bean in ClientConfig with #Primary annotation. This will cause the ClientConfig definition of bean A to be used.
If you include both configurations you can check Primary annotation: Primary
Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one 'primary' bean exists among the candidates, it will be the autowired value.
#Profile Annotation can be used for this...
#Configuration
#Profile("base")
public class BaseConfig {
#Bean
public A getA() {
return new A("aaa");
}
}
#Configuration
#Profile("client")
public class ClientConfig {
#Bean
public A getA() {
return new A("bbbb");
}
}
Use the following link
https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/
This is an answer to a comment above, but since comments have limited formating and size, I will reply with an answer instead.
how does spring define the ordering and overriding of beans when loading configuration files
It depends what you mean by loading multiple configuration. If you have one spring context and have two classes with #Configuration and do a component scan, then Spring will build the dependency tree, and which ever context (bean) is loaded last will define the bean (as it overrides the fist definition).
If you have have multiple Spring contexts in a parent child relation, then the child and see parent beans, and will also 'override' parent beans if you use child.getBean(type.class). The parent can't see bean from children.
Using #Primary. If you have a Spring context (can come from multiple configurations) that defines two beans of the same type, you will not be able to use context.getBean(type.class) or #AutoWired (without #Qualifier) because you have multiple beans of the same type. This behaviour can be altered if one of the beans is #Primary. I try to avoid the use of #Primary in my own code, but I can see it is used heavily used in Spring boots auto configure system, so I think it has some subtle usage when it comes to framework design.
Here is a small example, note that if you load configuration classes directly, they don't need to have the #Configuration annotation.
public class ParentChildContext {
public static void main(String[] args) {
parentChildContext();
twoConfigurationsSameContext();
}
private static void twoConfigurationsSameContext() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(Parent.class, Child.class);
// if you have two beans of the same type in a context they can be loaded by name
Object childA = ctx.getBean("childA");
System.out.println("childA = " + childA);
Object parentA = ctx.getBean("parentA");
System.out.println("parentA = " + parentA);
// since both configurations define A, you can't do this
ctx.getBean(A.class);
}
private static void parentChildContext() {
ApplicationContext parentCtx = new AnnotationConfigApplicationContext(Parent.class);
A parentA = parentCtx.getBean(A.class);
System.out.println("parent = " + parentA);
AnnotationConfigApplicationContext childCtx = new AnnotationConfigApplicationContext();
childCtx.register(Child.class);
childCtx.setParent(parentCtx);
childCtx.refresh();
A childA = childCtx.getBean(A.class);
System.out.println("child = " + childA);
}
public static class Parent {
#Bean
//#Primary // if you enable #Primary parent bean will override child unless the context is hierarchical
public A parentA() {
return new A("parent");
}
}
public static class Child {
#Bean
public A childA() {
return new A("child");
}
}
public static class A {
private final String s;
public A(String s) {
this.s = s;
}
#Override
public String toString() {
return "A{s='" + s + "'}";
}
}
}
I want configure a component test using spring-test configuration inner class (#Configuration). Tested components has some services which I'd like to mock for the test. These services are classes (no interface used) and have spring annotations (#Autowired) in them. Mockito can easily mock them, however, I found no way of disabling spring autowiring.
Example how I can easily reproduce:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SomeTest.Beans.class)
public class SomeTest {
// configured in component-config.xml, using ThirdPartyService
#Autowired
private TestedBean entryPoint;
#Test
public void test() {
}
#Configuration
#ImportResource("/spring/component-config.xml")
static class Beans {
#Bean
ThirdPartyService createThirdPartyService() {
return mock(ThirdPartyService.class);
}
}
}
public class ThirdPartyService {
#Autowired
Foo bar;
}
public class TestedBean {
#Autowired
private ThirdPartyService service;
}
In this example "TestBean" represents the service to be mocked. I would NOT like "bar" to be injected by spring! #Bean(autowire = NO) does not help (in fact, that's the default value).
(Please save me from "use interfaces!" comments - the mocked service can be 3rd party which I can't do anything with.)
UPDATE
Springockito partially solves the problem, as long as you don't have to have anything else to configure (so you can't use configuration class with Springockito - it does not support it), but use mocks only.
Still looking for pure spring solution, if there's any...
Here is my solution to your problem:
import static org.mockito.Mockito.mockingDetails;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
#Configuration
public class MockitoSkipAutowireConfiguration {
#Bean MockBeanFactory mockBeanFactory() {
return new MockBeanFactory();
}
private static class MockBeanFactory extends InstantiationAwareBeanPostProcessorAdapter {
#Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return !mockingDetails(bean).isMock();
}
}
}
and then just
#Import(MockitoSkipAutowireConfiguration.class)
in your test #Configuration and you are all set
I solved it by creating FactoryBean for my bean instead of just mocking bean. At this way Spring don't try to autowire fields.
Factory bean helping class:
public class MockitoFactoryBean<T> implements FactoryBean<T> {
private final Class<T> clazz;
public MockitoFactoryBean(Class<T> clazz) {
this.clazz = clazz;
}
#Override public T getObject() throws Exception {
return mock(clazz);
}
#Override public Class<T> getObjectType() {
return clazz;
}
#Override public boolean isSingleton() {
return true;
}
}
Actual test context part:
#Configuration
public class TestContext {
#Bean
public FactoryBean<MockingService> mockingService() {
return new MockitoFactoryBean<>(MockingService.class);
}
}
Check Spring profiles. You don't need to disable auto wiring, you need to inject different beans for different configuration.
You could add the mocked service manually to the spring application context via org.springframework.beans.factory.config.SingletonBeanRegistry#registerSingleton. This way the mock is not post-processed by spring and spring does not attempt to autowire the mock. The mock itself will be injected into your tested bean.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SomeTest.Beans.class)
public class SomeTest {
// configured in component-config.xml, using ThirdPartyService
#Autowired
private TestedBean entryPoint;
#Autowired
private ThirdPartyService thirdPartyServiceMock;
#Test
public void test() {
}
#Configuration
static class Beans {
#Autowired
private GenericApplicationContext ctx;
#Bean
TestedBean testedBean() {
ctx.getBeanFactory().registerSingleton("thirdPartyService", mock(ThirdPartyService.class));
return new TestedBean();
}
}
public static class ThirdPartyService {
#Autowired
Object bar;
}
public static class TestedBean {
#Autowired
private ThirdPartyService service;
}
}
I am in quite the same situation.
What I found that if you do not set the context loader by #ContextConfiguration annotation on your test class, the default context loader will be used, which derived from AbstractGenericContextLoader. I had a look at its source and turned out it registers all the bean post processors which are responsible for reading annotations such #Autowired. In other words, annotation config is enabled by default.
So the main problem is that there are two configurations which are in conflict: in the java config we said that autowiring is not needed, while the autowired annotation tells the opposite. The real question is how to disable the annotation processing in order to eliminate the undesired configuration.
As far as I know there is no such spring implementation of ContextLoader which would not be derived from AbstractGenericContextLoader so I guess the only we can do is to write our own. It would be something like this:
public static class SimpleContextLoader implements ContextLoader {
#Override
public String[] processLocations(Class<?> type, String... locations) {
return strings;
}
#Override
public ApplicationContext loadContext(String... locations) throws Exception {
// in case of xml configuration
return new ClassPathXmlApplicationContext(strings);
// in case of java configuration (but its name is quite misleading)
// return new AnnotationConfigApplicationContext(TestConfig.class);
}
}
Of course it would be worth to spend more time to find out how to implement ContextLoader properly.
Cheers,
Robert
There are so many ways of doing this, I'm pretty sure that this answer will be incomplete, but here are a few options...
As currently seems to be recommended practice, use constructor injection for your services rather than autowiring the fields directly. This makes testing like this so much easier.
public class SomeTest {
#Mock
private ThirdPartyService mockedBean;
#Before
public void init() {
initMocks(this);
}
#Test
public void test() {
BeanUnderTest bean = new BeanUnderTest(mockedBean);
// ...
}
}
public class BeanUnderTest{
private ThirdPartyService service;
#Autowired
public BeanUnderTest(ThirdPartyService ThirdPartyService) {
this.thirdPartyService = thirdPartyService;
}
}
By doing that, you can also mix up autowired and mocked services by autowiring into the test itself and then constructing the beans under test with the most useful mix of autowired and mocked beans.
A reasonable alternative is to use Spring profiles to define stub services. This is particularly useful when wish to use the same stubbed features in multiple tests:
#Service
#Primary
#Profile("test")
public class MyServiceStub implements MyService {
// ...
}
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = SomeTest.Beans.class)
#ActiveProfiles({"test"})
public class SomeTest {
// ...
}
By using the #Primary annotation, it ensures that this stub bean will be used instead of any other bean implementing the MyService interface. I tend to use this approach for things like email services, where by changing profile, I'm able to switch between a real mail server and Wiser.
I stumbled upon a case where the AOP proxy created by using #Cacheable breaks the dependency injection in Spring 3.1.1. Here is my scenario:
I have an interface and a class implementing this interface using #Cacheable at the implemented method.
Example interface:
public interface ImgService {
public byte[] getImage(String name);
}
Example implementation:
public class ImgServiceImpl implements ImgService {
#Cacheable(cacheName = "someCache")
public byte[] getImage(String name){//TODO};
protected String someOtherMethod(){//};
}
I also have to JUnit test classes - one which injects the interface and one the implementation:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" })
public class ImgServiceTest {
#Inject
private ImgService;
}
and
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" })
public class ImgServiceImplTest {
#Inject
private ImgServiceImpl;
}
Dependency injection for the interface works fine. However, when I get to injecting the implementation in the second test class I get an "Injection of autowired dependencies failed". I was able to debug it and it appears that ClassUtils.isAssignableValue() wrongly compares the desired type to the proxy class. It is called by DefaultListableBeanFactory. What is even stranger is that if I remove the #Cacheable annotation from the implemented method and add it to some other protected/private method, dependency injection works fine again. Is this a bug and what would be the correct approach to handle this situation?
It's not a bug, it's an expected side-effect of using JDK dynamic proxies for AOP implementation.
Since all calls to the cacheable method of ImgServiceImpl should go through the dynamic proxy of type ImgService, there is no way to inject this dependency into a field of type ImgServiceImpl.
When you move #Cacheable to private or protected method, injection works because #Cacheable doesn't take effect in this case - only public methods can be adviced using proxy-based AOP.
So, you should either declare fields to be injected as ImgService, or configure Spring to use target class-based proxies instead using proxy-target-class = "true".
Yet another option is to configure Spring to use AspectJ-based AOP implementation (requires compile-time or load-time weaving).
It's applicable to all AOP-based features provided by Spring (transactions, security, async execution, cache, custom aspects, etc).
See also:
7.6 Proxying mechanisms
OK, so here is the solution I came up finally. I implemented a simple method that attempts to extract the target object from the proxy based on its implementation of the org.springframework.aop.framework.Advised class:
#SuppressWarnings({"unchecked"})
public static <T> T getTargetObject(Object proxy, Class<T> targetClass) {
if (AopUtils.isJdkDynamicProxy(proxy)) {
try {
return (T) ((Advised)proxy).getTargetSource().getTarget();
} catch (Exception e) {
return null;
}
} else {
return (T) proxy;
}
}
My implementation test class now looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" })
public class ImgServiceImplTest {
#Inject
private ImgService imgService;
private ImgServiceImpl imgServiceImpl;
#PostConstruct
public void setUp() {
imgServiceImpl = getTargetObject(imgService, ImgServiceImpl.class);
}
}