How to use the #Autowired filed when construct in Spring - java

I have a bean use the "MongoTemplate" in construction,like this:
public class BasicRepository<T> implements DAO<T>{
...
#Autowired
private MongoTemplate mongoTemplate;
public BasicRepository(Class<?> typeParameterClass,DBConvertor<T> convertor){
getLogger().info("create a Object of BasicRepository,type of "+typeParameterClass);
this.typeParameterClass = typeParameterClass;
mongoTemplate.getCollectionName(typeParameterClass);
this.convertor = convertor;
}
...
}
configuration:
public class BeansConfiguration {
#Bean
DBConvertor<Topic> topicConvertor(){
return new DBConvertor<>(Topic.class);
}
#Bean
BasicRepository<Topic> topicDao(){
return new BasicRepository<Topic>(Topic.class,topicConvertor());
}
}
As you see,when construct the BasicRepository,it will throw the exception,because “mongoTemplate” is null during constructing time.How can I do for this.

#Autowired can not guarantee the constructor order. If you want to initialize the mongoTemplate first, you could use the mongoTemplate as a param of your constructor of BasicRepository.Then the Spring will do the dependent order for you.

Seems missing configuration of MongoTemplate. And you also need to check where you calling this repository. Spring beans are initialized after configuration load, if you use beans before spring loaded, it will be null.

Related

Spring Boot read values from application properties

I'm not sure if I understand it correctly, but from what I got, is that I can use #Value annotations to read values from my application.properties.
As I figured out this works only for Beans.
I defined such a bean like this
#Service
public class DBConfigBean {
#Value("${spring.datasource.username}")
private String userName;
#Bean
public String getName() {
return this.userName;
}
}
When the application starts I'm able to retrieve the username, however - how can I access this value at runtime?
Whenever I do
DBConfigBean conf = new DBConfigBean()
conf.getName();
* EDIT *
Due to the comments I'm able to use this config DBConfigBean - but my initial problem still remains, when I want to use it in another class
#Configurable
public SomeOtherClass {
#Autowired
private DBConfigBean dbConfig; // IS NULL
public void DoStuff() {
// read the config value from dbConfig
}
}
How can I read the DBConfig in a some helper class which I can define as a bean
Thanks
As Eirini already mentioned you must inject your beans.
The #Value annotation only works on Spring beans.
There is another way of accessing configuration with #ConfigurationProperties.
There you define a class that holds the configuration.
The main advantage is, that this is typesafe and the configuration is in one place.
Read more about this:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-vs-value
You shouldn't instantiate your service with the new operator. You should inject it, for example
#Autowired
private DBConfigBean dbConfig;
and then dbConfig.getName();
Also you don't need any #Bean decorator in your getName() method
You just need to tell spring where to search for your annotated beans. So in your configuration you could add the following:
#ComponentScan(basePackages = {"a.package.containing.the.service",
"another.package.containing.the.service"})
EDIT
The #Value, #Autowired etc annotations can only work with beans, that spring is aware of.
Declare your SomeOtherClass as a bean and add the package config in your #Configuration class
#Bean
private SomeOtherClass someOtherClass;
and then
#Configuration
#ComponentScan(basePackages = {"a.package.containing.the.service"
"some.other.class.package"})
public class AppConfiguration {
//By the way you can also define beans like:
#Bean
public AwesomeService service() {
return new AwesomeService();
}
}
Wrap your DBConfig with #Component annotation and inject it using #Autowired :
#Autowired
private DBConfig dbConfig;
Just add below annotation to your DBConfigBean class:
#PropertySource(value = {"classpath:application.properties"})

Registering #Component annotated class programmatically

I'm new to spring framework, my problem is to register spring component through the spring application context I tried it with many different ways but no luck yet.
#Configuration
#ComponentScan("com.example.app")
#EnableAutoConfiguration
public class ContextDataConfiguration
{
...
}
registered it with
#PostConstruct
public void initilize()
{
AutowireCapableBeanFactory beanFactory = context.getAutowireCapableBeanFactory();
beanFactory.initializeBean( new ContextDataConfiguration(), "contextDataConfiguration" );
}
but the other beans specified in the ContextDataConfiguration class are not getting initialized with this approach.
And if I specify the ContextDataConfiguration class in the component scan it is working but it is giving me an error like
not a managed type class
Is there any alternative way to do this?
You can use the #Bean annotation in a factory method to initialize your bean. So, lets say you have a MyBean component and wants to initialize it... You can do this inside your #Configuration class:
#Bean
public MyBean myBean() {
MyBean myBean = ... // initialize your bean here
return myBean;
}
How a about
#Bean
public ContextDataConfiguration contextDataConfiguration(){
return new ContextDataConfiguration();
}
This registers an instance of ContextDataConfiguration as a bean.

#Autowired create null object inspite #configuration

I have the following configuration class
#org.springframework.context.annotation.Configuration
public class TemplateConfiguration {
#Bean
public Configuration configuration() {
Configuration configuration = new Configuration(new Version(2, 3, 23));
configuration.setClassForTemplateLoading(TemplateConfiguration.class, "/templates/");
configuration.setDefaultEncoding("UTF-8");
configuration.setLocale(Locale.US);
configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
return configuration;
}
}
and I use it at the following #service
#Service
public class FreeMarkerService {
#Autowired
private Configuration configuration;
private static final Logger logger = LoggerFactory.getLogger(FreeMarkerService.class);
public String process() {
try {
Template template = configuration.getTemplate("someName");
....
} catch (IOException | TemplateException e) {
logger.error("Error while processing FreeMarker template: " + e);
throw new RuntimeException(e);
}
}
}
but when I try to call process() like
FreeMarkerService f = new FreeMarkerService()
f.process()
I get a null exception cause the configuration Object is null
I want to create an instance using #Autowired and #Configuration annotations
what am I doing wrong?
You should use the Spring instantiated FreeMarkerService object avoiding use of new keyword for objects like Controllers or Services as possible.
For example,
#Service
public class SampleService {
#Autowired
private FreeMarkerService freeMarkerService;
public String callProcess() {
return freeMarkerService.process();
}
}
More details you can find in many posts like this.
This is a member injection:
#Autowired
private static Configuration configuration;
Which spring does after instantiating the bean from its constructor. So at the time you are making that static method call spring has not injected the value.
This is because you are trying to autowire a static field. This is not possible in Spring. Remove static from your Configuration property and it should work.
#Autowired
private Configuration configuration;
#Autowired
private static Configuration configuration;
Why autowired a static field? this is the reason. static member load as class definition load so it is not getting injected value and getting default value which is null.

Spring - ConversionService no #Autowired because of ConfigurationPropertiesBindingPostProcessor

i've found a problem when using the Spring ConversionService (first I thought this was related to my test, but this was my error, it happens always). I try to create it via...
#Configuration
#ComponentScan(basePackages={"com.mybasepacke"})
public class MyConfiguration {
#Bean
#SuppressWarnings("rawtypes")
public ConversionServiceFactoryBean conversionService(ApplicationContext context) {
ConversionServiceFactoryBean factory = new ConversionServiceFactoryBean();
Map<String, MyConverter> converters = context.getBeansOfType(MyConverter.class);
factory.setConverters(new HashSet<>(converters.values()));
factory.afterPropertiesSet();
return factory;
}
}
This way, I expect to be able to simply create Converters (MyConverter is just a marker interface that extends Spring's Converter) like this...
#Component
public class ExampleConverter implements MyConverter<Something, SomethingElse> {
#Autowired
private SomeService someService;
... }
Spring should find all the MyConverters, add them all to the ConversionService (Factory) and I'll be able to use them... Theoretically. In reality, this happens:
ConfigurationPropertiesBindingPostProcessor gets initialized.
It optionally depends on a ConversionService.
Spring finds my ConversionServiceFactoryBean definition and starts it.
Unfortunately, ConfigurationPropertiesBindingPostProcessor is created BEFORE the AutowiredAnnotationBeanPostProcessor is registered. So all of its dependencies are NOT autowired. Which leads to all my converters not being autowired.
Has anyone an idea how to prevent this behavior? Or do I have to get rid of ConversionService since it doesn't seem to be able to use Converters with autowired fields?
Don't name your ConversionService conversionService, check the doc that basically explains what you found out yourself.
#Bean
public ConversionService myConversionService() {
// your setup
}
This is going to register a myConversionService (notice the method name) that will not be eagerly loaded by the configuration stuff. If you need some converters to coerce value from configuration (as defined in the doc), consider marking those converters with ConfigurationPropertiesBinding:
#Component
#ConfigurationPropertiesBinding
// This can't autowire things either ...
public class ExampleConverter implements MyConverter<Something, SomethingElse> { ... }

DefaultAdvisorAutoProxyCreator causing #Autowired dependencies to remain null

My project is currently protected using Apache Shiro, and would like to add Shiro annotations for a cleaner source code.
Apache Shiro asks you to include DefaultAdvisorAutoProxyCreator in order for Spring AOP to detect it.
My configuration is as follows:
#Configuration
#ComponentScan("com.mcac0006.flip")
#EnableWebMvc
public class AppContextConfiguration {
#Autowired
private JdbcRealm shiroRealm;
#Bean(name="shiroFilter")
public ShiroFilterFactoryBean getShiroFilter() {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(getSecurityManager());
return bean;
}
#Bean(name="securityManager")
public DefaultSecurityManager getSecurityManager() {
return new DefaultWebSecurityManager(shiroRealm);
}
#Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor a = new AuthorizationAttributeSourceAdvisor();
a.setSecurityManager(getSecurityManager());
return a;
}
#Bean
#DependsOn("authorizationAttributeSourceAdvisor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
final DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
return defaultAdvisorAutoProxyCreator;
}
}
In this example shiroRealm remains null and is causing all its dependants to fail. If I comment-out the last method defaultAdvisorAutoProxyCreator(), shiroRealm is instantiated just fine.
What am I overlooking??
Thanks guys.
DefaultAdvisorAutoProxyCreator is a BeanPostProcessor. Beans of that type are instantiated and initialized before other beans. However, in this case, your #Bean method is also annotated with #DependsOn in which case the bean depends on another bean to be initialized before its own initialization can take place.
So before defaultAdvisorAutoProxyCreator can run, authorizationAttributeSourceAdvisor must be run. That method now depends on getSecurityManager(), so that must also be ran first. When it is ran, your #Autowired field isn't processed yet because the BeanPostProcessor beans haven't all been initialized yet. (A BeanPostProcessor processes injections for #Autowired.)
If you had a completely separate bean and checked the state of the shiroRealm, you would see it as non-null at that point.

Categories

Resources