I am new to Spring, I am working in moving some bean definitions from XML to #Configuration Class.
Here is one of the beans I am struggling with:
<bean id="jmsProducerTemplate" class="org.springframework.jms.core.JmsTemplate"
p:connectionFactory-ref="connectionFactory"/>
<jms:listener-container container-type="default"
connection-factory="connectionFactory"
acknowledge="auto">
<jms:listener destination="YOURQUEUENAME" ref="theListenerClassYouAreUsing" />
</jms:listener-container>
How would that look in a #Configuration class, thanks.
So far I have this
#Bean("myContainerFactory")
public JmsListenerContainerFactory myContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
ConnectionFactory connectionFactory = pooledConnectionFactory();
factory.setConnectionFactory(connectionFactory);
factory.setPubSubDomain(false);
return factory;
}
I am missing the destination set, no idea how to do it.
You have to add a listener as well, see for example Annotation-driven Listener Endpoints:
#Component
public class MyService {
#JmsListener(destination = "YOURQUEUENAME", containerFactory = "myContainerFactory")
public void myListener(String data) { ... }
}
Related
I have 2 beans of the same type:
#Component("beanA")
public class BeanA implements BaseBean {}
#Component("beanB")
public class BeanB implements BaseBean {}
This type is used in my service:
#Service
public class MyService {
#Autowired
private BaseBean baseBean;
}
Now I want to use both possible MyService beans in another service
#Service
public class AnotherService {
#Autowired
private MyService myServiceWithBeanA;
#Autowired
private MyService myServiceWithBeanB;
}
How can I achieve that? Maybe I should take another approach?
I know how to do it in XML-based beans configuration. How can I do it using annotations?
<bean id="AnotherService" class="AnotherService">
<property name="myServiceWithBeanA" ref="myServiceWithBeanA" />
<property name="myServiceWithBeanB" ref="myServiceWithBeanB" />
</bean>
<bean id="myServiceWithBeanA" class="MyService">
<property name="baseBean" ref="beanA" />
</bean>
<bean id="myServiceWithBeanB" class="MyService">
<property name="baseBean" ref="beanB" />
</bean>
<bean id="beanA" class="BeanA" />
<bean id="beanB" class="BeanB" />
The problem is that MyService is annotated with #Service. This means that it is a singleton - only one instance will be created.
In order to create multiple instances, you need to expose two #Beans via configuration.
#Configuration
public class MyServiceConfig {
#Bean
public MyService serviceA(#Qualifier("beanA") beanA) {
return new MyService(beanA);
}
#Bean
public MyService serviceB(#Qualifier("beanB") beanB) {
return new MyService(beanB);
}
}
MyService would become
public class MyService {
private BaseBean baseBean;
public MyService(BaseBean baseBean) {
this.baseBean = baseBean;
}
}
You can then pass all of these to the other service with qualifiers
#Service
public class AnotherService {
#Autowired
#Qualifier("serviceA")
private MyService myServiceWithBeanA;
#Autowired
#Qualifier("serviceB")
private MyService myServiceWithBeanB;
}
Using the #Qualifier annotation you can specify which bean you want to autowire.
#Service
public class AnotherService {
#Autowired
#Qualifier("beanA")
private MyService myServiceWithBeanA;
#Autowired
#Qualifier("beanB")
private MyService myServiceWithBeanB;
}
Hope this helps.
In your xml bean definition add the these tags <qualifier value="name"/>.
<bean id="myServiceWithBeanA" class="MyService">
<qualifier value="A"/>
<property name="baseBean" ref="beanA" />
</bean>
<bean id="myServiceWithBeanB" class="MyService">
<qualifier value="B"/>
<property name="baseBean" ref="beanB" />
</bean>
And then you can get them by using Qualifier annotation like this:
#Autowired
#Qualifier("A")
private MyService myServiceWithBeanA;
#Autowired
#Qualifier("B")
private MyService myServiceWithBeanB;
You also can do more stuff than that.
Have a look at the documentation on the following link:
Qualifier documentaiton
Not everything can be done with annotations. In cases where you need to create multiple instance of a bean but with different arguments you have to fallback to #Configuration and define those beans as you would in the XML config.
#Configuration
public class AppConfig {
#Bean
public MyService myServiceWithBeanA(BeanA beanA) {
return new MyService(beanA);
}
#Bean
public MyService myserviceWithBeanB(BeanB beanB) {
return new MyService(beanB);
}
}
Now just tell AnotherService to expect MyService twice with matching bean names as name of the bean defining method is its default qualifier.
#Service
public class AnotherService {
#Autowired
private MyService myServiceWithBeanA;
#Autowired
private MyService myServiceWithBeanB;
}
Java - Spring
I have spring factory bean creation in .xml
<bean id="concurrentHashMapFactory" class="com.abc.HashMapFactory.ConcurrentHashMapFactory"/>
<bean id="idCorpMap" factory-bean="concurrentHashMapFactory" factory-method="createIdCorpMapInstance"/>
but i want to convert above .xml statement into equivalent using annotation any help ?
Roughly like this (I didn't test it)..
#Configuration
public class Config {
#Bean(name = "concurrentHashMapFactory")
public ConcurrentHashMapFactory createConcurrentHashMapFactory() {
return new ConcurrentHashMapFactory();
}
#Bean(name = "idCorpMap")
public IdCorpMapType createIdCorpMap(ConcurrentHashMapFactory factory) {
return factory.createIdCorpMapInstance();
}
}
how can i change this xml configuration :
<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">
...
<property name="additionalDialects">
<set>
<bean class="org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect"/>
</set>
</property>
...
</bean>
to a java code configuration so far i have this i only have problems in this part :
<property name="additionalDialects">
<set>
<bean class="org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect"/>
</set>
</property>
this is what i have so far in java code :
#Bean
public SpringSecurityDialect springSecurityDialect() {
return new SpringSecurityDialect();
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver( templateResolver() );
engine.setMessageSource( messageSource() );
//DIALECTS
Set<SpringSecurityDialect> ssdSet = new HashSet<SpringSecurityDialect>();
ssdSet.add( springSecurityDialect() );
engine.setAdditionalDialects( ssdSet ); <-- this line give me this error
return engine;
}
this line give me this error: The method setAdditionalDialects(Set<IDialect>) in the type TemplateEngine is not applicable for the arguments (Set<SpringSecurityDialect>)
I banged my head against this for a while today. The answer lay in looking at the Spring Boot source:
https://github.com/spring-projects/spring-boot/blob/v1.2.5.RELEASE/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java
#Configuration
#ConditionalOnClass({ SpringSecurityDialect.class })
protected static class ThymeleafSecurityDialectConfiguration {
#Bean
#ConditionalOnMissingBean
public SpringSecurityDialect securityDialect() {
return new SpringSecurityDialect();
}
}
So Spring Boot (well, "org.springframework.boot:spring-boot-starter-thymeleaf") will try to inject the org.thymeleaf.extras.springsecurity3.dialect.SpringSecurityDialect. Perhaps it's not working because I have the springsecurity4 jar.
In any case, there's a simple fix: just do what Spring Boot tries to do. In an #Configuration class, just add the bean:
#Bean
public SpringSecurityDialect securityDialect() {
return new SpringSecurityDialect();
}
According to your config, property additionalDialects should assigned with a Set containing one bean. So in javaconfig just create an instance of HashSet, add to it SpringSecurityDialect bean and assign the resulting set to additionalDialects property.
SpringSecurityDialect bean should be created by method annotated with #Bean to let Spring application context know about this bean to execute bean initializers and postprocessors.
Following code illustrates it:
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver( templateResolver() );
engine.setMessageSource( messageSource() );
Set<SpringSecurityDialect> ssdSet = new HashSet<SpringSecurityDialect>();
ssdSet.add( springSecurityDialect() );
engine.setAdditionalDialects( ssdSet );
return engine;
}
#Bean
public SpringSecurityDialect springSecurityDialect() {
return new SpringSecurityDialect();
}
You could instantiate the entire engine using code similar to this.
FileSystemXmlApplicationContext appCtx = new FileSystemXmlApplicationContext("myconfigfile.xml");
if (appCtx.containsBean("templateEngine") {
SpringTemplateEngine engine = (SpringTemplateEngine) appCtx.getBean("templateEngine");
}
The additional dialects and any other properties you've set on the engine in your xml configuration file will be applied.
You might want to look at using ClassPathXmlApplicationContext instead of the FileSystem one in my example.
Everything works fine when I try to get messages in a #Controller class, but when I try
to achieve the same in a #Service or #Component class I receive the following error:
org.springframework.context.NoSuchMessageException:
No message found under code 'email.ativacao.title' for locale 'pt_BR'.
My Controller:
#Controller
public class TestController {
#Autowired
TestService service;
#Autowired
TestComponent component;
#Autowired
private MessageSource message;
#RequestMapping(value = "/send", method = RequestMethod.GET)
public String go() {
String message = message.getMessage
("email.ativacao.title", null, new Locale("pt", "BR"));
service.getMessage();
component.getMessage();
return "signsucess";
}
}
My Service:
#Service
public class TestService {
#Autowired
private MessageSource message;
public void getMessage() {
//Error
String message = message.
getMessage("email.ativacao.title", null, new Locale("pt", "BR"));
}
}
My Component:
#Component
public class TestComponent {
#Autowired
private MessageSource message;
public void getMessage() {
//Error
String message = message.
getMessage("email.ativacao.title", null, new Locale("pt", "BR"));
}
}
My config:
<!-- i18n -->
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.
LocaleChangeInterceptor" p:paramName="lang"/>
</mvc:interceptors>
<!-- Mesage Source Config -->
<bean id="messageSource"
class="org.springframework.context.support.
ReloadableResourceBundleMessageSource" p:fallbackToSystemLocale="true" >
<property name="basename" value="WEB-INF/i18n/messages" />
</bean>
<!-- Mapeia o cookie que irá salvar as opções de idioma -->
<bean class="org.springframework.web.servlet.i18n.CookieLocaleResolver"
id="localeResolver" p:cookieName="locale"/>
MessageSource is not null on both #Service and #Component, but they're not able to
get the message (Exception above). My properties:
WebContent/WEB-INF/i18n
messages_pt_BR
messages_en_US
I really can't find the problem. Any suggestion to solve this? Thanks.
From what you were describing, I guess controller bean and messageSource were declared in same context. so then can find each other.
if your service bean and controller bean are not declared in same context, your service cannot find the messageSource.
same context doesn't mean same file. your one.xml could include two.xml.
anyway, if it worked for you, it's good.
I have:
#Component
class MyDecorator{
private Cache cache;
/*
some wrapped methods like get put remove
*/
}
Is it possible to autowire MyDecorator in different places with different cache?
I can configure XML like this:
<bean id="id1" class="MyDecorator ">
<property name="cache" value="Cache1" />
</bean>
<bean id="id2" class="MyDecorator ">
<property name="cache" value="Cache2" />
</bean>
But is there more elegance way without addition of xml configs, only with annotation?
Correct code should be
#Configuration
public class AppConfig {
#Bean
public MyAdapter adaptedCache2() {
return new MyAdapter (cache1);
}
#Bean
public MyAdapter adaptedCache2() {
return new MyAdapter (cache2);
}}
according to specs will be generated two beans adaptedCache1 and adaptedCache2
and now i can
autowire those beans with qualifiers adaptedCache1 and adaptedCache2
With Java configuration (Spring 3.1) you can write:
#Bean
public MyDecorator decoratedCache1() {
return new MyDecorator(cache1);
}
#Bean
public MyDecorator decoratedCache2() {
return new MyDecorator(cache2);
}
Of course in this case MyDecorator does not need #Component:
#Component
class MyDecorator{
private final Cache cache;
public MyDecorator(Cache cache) {
this.cache = cache;
}
}