Is it possible in Spring Boot to autowire object that is marked by #ManagedResource. I'm trying to do that but object is null.
For example:
#Component
#ManagedResource(objectName = MyMBean.MBEAN_NAME)
public class MyMBeanImpl implements MyMBean {
private String attribute;
#Override
#ManagedAttribute(description="some attribute")
public void setAttribute(String attribute) {
this.attribute = attribute;
}
}
Spring creates appropriate MBean. But when I try to autowire this object to use its attribute I'm getting null:
#Component
public final class Consumer {
#Autowired
MyMBean mBean; // is null
...
}
The #Autowired objects may not get initialized if your configuration is not properly defined. Spring scans for managed components in specified packages. I assume that you have #ComponentScan annotation on your spring boot main class. If your main application class is in a root package, then #ComponentScan annotation can be used without specifying a basePackage attribute. Otherwise you need to specify the base package attribute. You need to specify the basePackage attribute similar to the below:
#ComponentScan("<your_package_to scan_for beans>")
Also the #EnableAutoConfiguration annotation is often placed on your main spring boot application class. This implicitly defines a base package to search for components.
Related
I'm trying to read some setting values from application.yml using the #ConfigurationProperties annotation.
An instantiated object of the class TestClass uses the properties class, so I added the #Configurable annotation, but the properties always be null and it causes NullpointerException.
The properties class:
#ConfigurationProperties
#Getter
#Setter
public class Properties {
private String setting;
}
And the object which uses the properties:
#Configurable
public class TestClass{
#Autowired
private Properties properties;
void print(){
System.out.println(properties.getSetting());
}
}
If I call the print method, NullPointerException will be occurred:
TestClass testClass = new TestClass();
testClass.print();
Am I missing something?
Short Answer:
Find the class that is annotated with #SpringBootApplication and add there also the annotation #EnableConfigurationProperties(Properties.class)
#SpringBootApplication
#EnableConfigurationProperties(Properties.class)
public class ServiceLauncher {
Explanation:
#ConfigurationProperties does not register the class that brings this annotation as a spring bean. It is only used so that Spring can read the properties with some meta configured information (ex prefix = "some.prop.prefix").
If you wish to use this class as a spring bean (ex via #Autowired) you need to combine the above annotation with #EnableConfigurationProperties which then says to spring that this class must become a spring bean.
Another workaround:
You could also instead just use the #Component on the Properties class and that would be enough without the need of #EnableConfigurationProperties but the later is better practice to be used.
#Component
#ConfigurationProperties
#Getter
#Setter
public class Properties {
Edit: After clarrified in the comments there is also another mistake in this code. You should replace #Configurable with #Configuration. The first one does not create a spring bean on the class that is placed!
Spring reference documentation says the following:
Spring can automatically detect stereotyped classes and register corresponding BeanDefinition instances with the ApplicationContext ...
To autodetect these classes and register the corresponding beans, you need to add #ComponentScan to your #Configuration class ...
I've created a simple example to test auto-detection functionality of Spring framework:
/**
* Java-based configuration class which defines root package to start scanning from.
*/
#ComponentScan
public class ComponentScanPackageMarker {
}
/**
* Class annotated with <b>stereotype</b> annotation is a candidate for automatic detection and registering as
* {#link BeanDefinition} instance.
*/
#Component
public class Pen {
private Ink ink;
#Autowired
public Pen(Ink ink) {
this.ink = ink;
}
}
/**
* Auto-detected class which will be used as auto-wiring candidate for another auto-detected component.
*/
#Component
public class Ink {
}
#Configuration annotation was intentionally omitted for ComponentScanPackageMarker class. I've tested component scanning and autowiring functionality. To my surprise everything went well:
#Test
public void shouldAutoDetectAndRegisterBeans() {
try (AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(ComponentScanPackageMarker.class)) {
Pen pen = context.getBean(Pen.class);
Assert.assertNotNull(pen);
Ink ink = context.getBean(Ink.class);
Assert.assertNotNull(ink);
}
}
Is this behavior of component-scanning intentional? Why does it work even without #Configuration annotation?
Yes.
I think the job of #ComponentScan is to scan given packages and register beans annotated with Stereotype annotations (#Component, #Configuration, #Service, #Repository) if found any while job of #Configuration is to register method's (annotated with #Bean) return value as a bean in the container.
Correct me if I am wrong.
I am new in Spring. I understand process of Dependency Injection and Inversion Of Control as well. But in few days ago I found one source code which compel me thinking about it.
If I am not wrong, Beans can be registered by Stereotype annotations - #Component, #Service, etc.
In code which I found will be defined class with some logic, but without annotation. Next that same class will be initialized in some #Configuration class as been like that:
#Bean
public Foo fooBean() {
return new Foo();
}
Can you tell me what is different between these options and when they use? Thanks in advice.
The greatest benefit of #Configuration and #Bean is that allows you to create spring beans that are not decorated with #Component or any of its children (#Service, #Repository and those). This is really helpful when you want/need to define spring beans that are defined in an external library that has no direct interaction with Spring (maybe written by you or somebody else).
E.g.
You have a jar created by an external provider that contains this class:
public class EmailSender {
private String config1;
private String config2;
//and on...
public void sendEmail(String from, String to, String title, String body, File[] attachments) {
/* implementation */
}
}
Since the class is in an external jar, you cannot modify it. Still, Spring allows you to create spring beans based on this class (remember, the bean is the object, not the class).
In your project, you'll have something like this:
import thepackage.from.externaljar.EmailSender;
#Configuration
public class EmailSenderConfiguration {
#Bean
public EmailSender emailSender() {
EmailSender emailSender = new EmailSender();
emailSender.setConfig1(...);
emailSender.setConfig2(...);
//and on...
return emailSender;
}
}
And then you can inject the bean as needed:
#Service
public class MyService {
#Autowired
private EmailSender emailSender;
}
#Configuration is used to define your configuration of your application. In the end #Bean, #Service, #Component will all register a bean, but using #Configuration with all beans (services, components) defined in a single place makes your app more organized and easier to troubleshoot.
I have an application (Spring 4 MVC+Hibernate 4+MySQL+Maven integration example using annotations) , integrating Spring with Hibernate using annotation based configuration. I want to get the bean name from the JoinPoint if is possible....
#Aspect
public class TDKAspectLogger {
private Logger logger = Logger.getLogger(getClass());
#Before(“execution(void set*(*))”)
public void logInfo(JoinPoint point) {
logger.info(“changing bean -> ” );
}
}
You can use this:
Stream.of(joinPoint.getTarget().getClass().getAnnotationsByType(Service.class))
.forEach(q -> logger.info(q.value()));
to get the bean as declared by #Service annotation.
However, not all beans are created this way. Some are created by #Bean annotated methods, some can even be added manually to the the context. So, if you annotate your bean classes with #Component, #Service, #Qualifier etc. and use #ComponentScan you might get what you want. You just need to remember that it's not the universal way to retrieve all beans currently available in the context (it will not work for classes without any annotations/metadata).
I have a class annotated with spring Component e.g:
#Component
public class ImportantClass{
#Autowired
private DependentClassIF otherClass;
//getters setters
#Required
public void setOtherClass(DependentClassIF c){
this.otherClass = c;
}
public interface DependentClassIF {
//methods here
}
#Component
public class DependentClass implements DependentClassIF {
//implementation here
}
I use autoscan to detect beans instead of declaring them all in the bean conf file.
I get
org.springframework.beans.factory.BeanInitializationException:
Property 'otherClass' is required for
bean 'ImportantClass'
My question is the following:
In autoscan, doesn't Spring make sure that all the required properties are injected?
If I remove the #Required it works, but I am not sure I understand Spring's behavior on this.
Any input is welcome.
Thanks
#Autowired has required set to true, so you don't need #Required
You don't need #Requried with annotation-based injection. It is meant to be used with xml configuration, to denote that a property must be set in the xml.