I have two beans, one of type scope request and the other is the factory to create Create a bean for each request from the first one. I did it with annotations and it works, however I need to create them with XML or with DSL and I haven't been able to do it. Any idea how to do it? I'm using Grails 2.5.6
These are the two Java Beans with annotations
#Configuration
public class HeadersConfiguration {
#Bean
public Function<HttpServletRequest, MelHeaders> headerHandlerFactory() {
return { request -> melHeaders(request) };
}
#Bean
#Scope(value = WebApplicationContext.SCOPE_REQUEST)
public MelHeaders melHeaders(HttpServletRequest request) {
return new MelHeaders(request);
}
}
Thank's
Related
I have two beans that implements the same interface. Both are created in Java configuration, like this:
#Bean
#Qualifier("kafkaEventSender")
public IKafkaEventSender<KafkaData> kafkaEventSender(#Qualifier("EventBus") KafkaTemplate<String, Object> kafkaTemplate){
return new KafkaEventSender<>(kafkaTemplate, false);
}
#Bean
#Qualifier("kafkaEventSenderAudited")
public IKafkaEventSender<KafkaData> kafkaEventSenderAudited(#Qualifier("EventBus") KafkaTemplate<String, Object> kafkaTemplate){
return new KafkaEventSenderAudited<>(kafkaTemplate, false);
}
The problem is that spring doesn't create first bean only the second. Any idea why?
Try using bean names instead:
#Bean(name = "kafkaEventSender")
public IKafkaEventSender<KafkaData> kafkaEventSender(#Qualifier("EventBus") KafkaTemplate<String, Object> kafkaTemplate){
return new KafkaEventSender<>(kafkaTemplate, false);
}
#Bean(name = "kafkaEventSenderAudited")
public IKafkaEventSender<KafkaData> kafkaEventSenderAudited(#Qualifier("EventBus") KafkaTemplate<String, Object> kafkaTemplate){
return new KafkaEventSenderAudited<>(kafkaTemplate, false);
}
Ok, the problem was with method name, after changing it, bean is properly created. In some other library configuration class was a method with same name. Guessing that was the problem.
#Qualifier annotation is used to select one bean over multiple available beans of same type in spring container.
when you annotate a method with #Bean annotation, default, it creates a bean whose name is the name of same method. So, for example:
#Bean
public BeanA itsBeanA() {
return new BeanA();
}
#Bean(name = "specialBeanA")
public BeanA itsAgainBeanA() {
return new BeanA("specialConstructorParam");
}
#Bean
public BeanB beanB(#Autowired #Qualifier("specialBeanA") BeanA beanA) {
return new BeanB(beanA);
}
first method will create an instance of BeanA with name 'itsBeanA'. Second, will create an instance with name 'specialBeanA' since we provided the name attribute here.
There maybe a scenario where you need to have multiple beans of same TYPE (like BeanA here). It will create ambiguity for container which bean to use of all same types, we specify the #Qualifier with the name of bean which we want.
I hope that helps.
In Spring Framework is it possible to eliminate the entire Spring.xml and use a configuration class with #Configuration and #Bean annotation for creating bean, and for all other purpose use a spring.xml?
Yes, you can have pure java configuration in Spring. You have to create a class and annotate it with #Configuration. We annotate methods with #Bean and instantiate the Spring bean and return it from that method.
#Configuration
public class SomeClass {
#Bean
public SomeBean someBean() {
return new SomeBean();
}
}
If you want to enable component scanning, then you can give #ComponentScan(basePackages="specify_your_package") under the #Configuration. Also the method name as someBean serves as bean id. Also if you have to inject a dependency, you can use constructor injection and do as following:
#Configuration
public class SomeClass {
#Bean
public SomeDependency someDependency() {
return new SomeDependency();
}
#Bean
public SomeBean someBean() {
return new SomeBean(someDependency());
}
}
Yes,most of (maybe all of)official guides uses absolutely no xml configuration file,just annotations.
I'm new to spring and spring mvc
I'm going over a course where they present the following #Configuration class:
#Configuration
public class MailConfig {
#Bean
#ConditionalOnProperty(name="spring.mail.host",
havingValue="foo",
matchIfMissing=true)
public MailSender mockMailSender() {
return new MockMailSender();
}
#Bean
#ConditionalOnProperty(name="spring.mail.host")
public MailSender smtpMailSender(**JavaMailSender javaMailSender**) {
SmtpMailSender mailSender = new SmtpMailSender();
mailSender.setJavaMailSender(javaMailSender);
return mailSender;
}
}
in the second bean (smtpMailSender) - there's a parameter :
JavaMailSender javaMailSender
but the parameter is not passed by the caller.
the instructors says : "inside bean methods if we pass parameter like this one , the parameters will be injected by spring"
My question is - how could I know that this is the expected behavior of Spring ? what is the instructor basing this on ?
is there a specific trait of JavaMailSender that is part of spring and therefor treated as a component or is something else in play here ?
That, simply said, is the way Spring works when using Java based configuration.
When a method annotated with #Bean is detected and it has parameters Spring will auto wire them by default. It does so by type.
#Bean
#ConditionalOnProperty(name="spring.mail.host")
public MailSender smtpMailSender(JavaMailSender javaMailSender) {
SmtpMailSender mailSender = new SmtpMailSender();
mailSender.setJavaMailSender(javaMailSender);
return mailSender;
}
In this case it will inject a bean of type JavaMailSender into this method. As you are using Spring Boot that is configured by default and will be injected. For a more information see the reference guide.
I am currently in a Spring 4 application that uses MyBatis and is completely annotation-driven (that cannot change per architecture requirements). I am trying to add a second data source definition with a completely separate set of mapping configurations.
The problem I am having is that I cannot get the two data sources to play nicely together.
I created a new, virtually identical class and added #Qualifier data to the new file.
The configuration for the classes looks like this:
Data Source 1
#Configuration
#MapperScan (basePackages = "com.myproject.package1", annotationClass = Mapper.class)
public class DataSource1 {
#Bean
#Qualifier ("DS1")
public DataSource getDataSource() {
/* configuration loaded */
}
#Bean
#Qualifier ("DS1")
public SqlSessionFactory getSqlSessionFactory() {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(getDataSource());
/* mapper resources added */
return bean.getObject();
}
}
Data Source 2
#Configuration
#MapperScan (basePackages = "com.myproject.package2", annotationClass = Mapper.class)
public class DataSource2 {
#Bean
#Qualifier ("DS2")
public DataSource getDataSource() {
/* configuration loaded */
}
#Bean
#Qualifier ("DS2")
public SqlSessionFactory getSqlSessionFactory() {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(getDataSource());
/* mapper resources added */
return bean.getObject();
}
}
When this runs I get exception messages like:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)
If I comment-out the data in DS2, DS1 works just fine again. I tried adding the mapper scanning configuration data in another bean and setting the name of the SqlSessionFactoryBean to pass into it but that did not work.
Suggestions?
UPDATE
I looked at this post and updated to use the following.
#Bean (name = "the_factory_1")
public SqlSessionFactory getSqlSessionFactory() { /* same code */ }
#Bean
public MapperScannerConfigurer getMapperScannerConfigurer() {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.myproject.package1");
configurer.setAnnotationClass(Mapper.class);
configurer.setSqlSessionFactoryBeanName("the_factory_1");
return configurer;
}
However, that leads me to this error:
No qualifying bean of type [com.myproject.package1.mapper.MyMapper] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
When I debug only one #Bean for the factory gets invoked.
UPDATE 2
If I move everything to a single file all is fine. However, that is not ideal as I want the DataSource definitions to be separated. That's my only hurdle right now.
You can use ace-mybatis, it simplifies configuration.
Add one bean.
#Bean
public static AceMapperScannerConfigurer mapperScannerConfigurer() {
return AceMapperScannerConfigurer.builder()
.basePackage("com.myproject.package1")
.build();
}
And then mark your mapper interfaces with #AceMapper and specify sqlSessionFactory
#AceMapper(sqlSessionFactoryBeanName = "firstSqlSessionFactory")
public interface UserMapper {
Stream<User> selectUsers();
}
#AceMapper(sqlSessionFactoryBeanName = "secondSqlSessionFactory")
public interface ClientMapper {
Stream<Client> selectClients();
}
Please use DAOFactory pattern to get connections for multiple datasources like DS1 and DS2 and use DAOUtil class to provide required configuration using annotation
I am turning old xml/java configuration into pure java config. In xml I used injection of parameters into configuration file like this:
<bean class="com.project.SpringRestConfiguration">
<property name="parameters" ref="parameters" />
</bean>
#Configuration
public class SpringRestConfiguration {
private Parameters parameters;
public void setParameters(Parameters parameters) {
this.parameters = parameters;
}
// #Bean definitions
...
}
Is it possible to inject Parameters in javaconfig? (Without the need of using autowiring!)
#Configuration
#Import(SpringRestConfiguration.class)
EDIT:
With #Import I can't see any chance to inject Parameters into SpringRestConfiguration
Basically you would need to use #Autowired but you can still use a name and not type interpretation like this:
#Configuration
public class SpringRestConfiguration {
#Autowired
#Qualifier("parameters") // Somewhere in your context you should have a bean named 'parameters'. It doesn't matter if it was defined with XML, configuration class or with auto scanning. As long as such bean with the right type and name exists, you should be good.
private Parameters parameters;
// #Bean definitions
...
}
This solves the confusion problem you mentioned when using #Autowired - there's no question here which bean is injected, the bean that is named parameters.
You can even do a little test, leave the parameters bean defined in the XML as before, use #Autowired, see that it works. Only then migrate parameters to #Configuration class.
In my answer here you can find a complete explanation of how you should migrate XML to #Configuration step by step.
You can also skip the private member altogether and do something like this:
#Configuration
public class SpringRestConfiguration {
#Bean
public BeanThatNeedsParamters beanThatNeedsParamters (#Qualifier("parameters") Parameters parameters) {
return new BeanThatNeedsParamters(parameters)
}
}
If I have understood your question properly, this is what you are trying to do :
#Component
public class SomeConfiguration {
#Bean(name="parameters")
public Parameters getParameters(){
Parameters parameters = new Parameters();
// add your stuff
return parameters;
}
#Bean(name="springRestConfiguration")
public SpringRestConfiguration springRestConfiguration(){
SpringRestConfiguration springRestConfiguration = new SpringRestConfiguration();
springRestConfiguration.setParametere(getParameters());
return springRestConfiguration;
}
}
and use it like :
ApplicationContext appContext = new AnnotationConfigApplicationContext(SomeConfiguration.class);
SpringRestConfiguration springRestConfiguration = (SpringRestConfiguration) appContext.getBean("springRestConfiguration");