How to create a websocket endpoint in an existing spring application - spring

I'm trying to make available a new websocket endpoint in an existing spring application.
I'm following the documentation at https://docs.spring.io/spring/docs/4.3.2.RELEASE/spring-framework-reference/html/websocket.html#websocket-server-handler . But based on documentation I should configure the DispatcherServlet or use WebSocketHttpRequestHandler.
How can I make available the websocket endpoint without any change in the web.xml config file ?
This is what I tried, but not working (Client error 404 not found).
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ws="http://jax-ws.dev.java.net/spring/core" xmlns:wss="http://jax-ws.dev.java.net/spring/servlet"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://jax-ws.dev.java.net/spring/core http://jax-ws.dev.java.net/spring/core.xsd
http://jax-ws.dev.java.net/spring/servlet http://jax-ws.dev.java.net/spring/servlet.xsd
http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:handlers allowed-origins="*">
<websocket:mapping path="/ws" handler="websocketService"/>
<websocket:handshake-interceptors>
<bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
</websocket:handshake-interceptors>
</websocket:handlers>
<bean id="websocketService" class="com.krios.SocketHandler"/>
</beans>
Class file:
public class SocketHandler extends TextWebSocketHandler {
List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message)
throws InterruptedException, IOException {
for(WebSocketSession webSocketSession : sessions) {
Map value = new Gson().fromJson(message.getPayload(), Map.class);
webSocketSession.sendMessage(new TextMessage("Hello " + value.get("name") + " !"));
}
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
//the messages will be broadcasted to all users.
sessions.add(session);
}
}

I can provide you the java configuration (you can then change it to xml yourself or use it as java class and scan it from xml)
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Bean
public MessagingWebSocketHandler webSocketHandler() {
//handler of your websocket. should be a class implementing WebSocketHandler.
//You could also extend AbstractWebSocketHandler or TextWebSocketHandler and override methods
return new MessagingWebSocketHandler();
}
#Bean
public WebSocketContainerFactoryBean createWebSocketContainer() {
WebSocketContainerFactoryBean container = new WebSocketContainerFactoryBean();
container.setMaxTextMessageBufferSize(StaticConfig.MAXIMUM_WS_TEXT_BUFFER_SIZE);
container.setMaxBinaryMessageBufferSize(StaticConfig.MAXIMUM_WS_BINARY_BUFFER_SIZE);
container.setMaxSessionIdleTimeout(StaticConfig.MAXIMUM_WS_SESSION_IDLE_TIMEOUT);
container.setAsyncSendTimeout(StaticConfig.MAXIMUM_WS_ASYNC_SEND_TIMEOUT);
return container;
}
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
webSocketHandlerRegistry.addHandler(webSocketHandler(), "/message").setAllowedOrigins("*"); // you could also get handler from context
}
}
I hope it hepls.
update
I myself don't use xml based configuration. But the simplest way is to add this java code then scan it from xml. For example, by adding this line to your spring servlet configuration xml you can scan your configuration package or whole project package.
<context:component-scan base-package="com.my.company.config" />
Then your WebSocketConfig class must be under com.my.company.config
Documentation Of Websocket support and configuration is here. On section Create and Configure a WebSocketHandler you can read about xml configuration. I havent test it myself tho.

Related

Spring Cache in MVC - Possible to lookup with autowiring?

I see that when the application starts up my singleton cache is created
DEBUG Creating CGLIB proxy: target source is SingletonTargetSource for
target object [com.abc.xyz.util.CacheUtil#14e3dd3] DEBUG Unable to
apply any optimizations to advised method: public java.util.Map
But how do I lookup the value using autowiring as when I attempt, it does not hit the singleton created and creates a new instance of CacheUtil.
CacheUtil.java [This class is annotated with #Component]
public Map getSelectOptions(String codeType) {
System.out.println("Cache Breached!!!");
HashMap selectOpts = new HashMap();
Vector<MyTableDO> vCodeMap = null;
vCodeMap = MyTableDO.getCodesFromDatabase(codeType, "LookupCacheUtil");
if(vCodeMap == null || vCodeMap.size() == 0) return selectOpts;
vCodeMap.forEach(codeMap -> selectOpts.put(codeMap.getCodeValue(), codeMap.getCodeDesc()));
return selectOpts;
}
My spring config xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.abc.xyz" />
<context:annotation-config />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="cacheUtil" class="com.abc.xyz.util.CacheUtil" />
</beans>
Class Invoking the Cached method
#Autowired
#Qualifier("cacheUtil")
protected CacheUtil cacheUtil;
public Map getSelectOptions(String codeType) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MyApplication.class);
//ctx.refresh();
CacheUtil lkp = (CacheUtil) ctx.getBean(CacheUtil.class);
ctx.close();
System.out.println("App Context lookupCacheUtil -"+lkp); // Not the same object of Spring Cache and comes to be new instance on every call
System.out.println("Autowired lookupCacheUtil -"+cacheUtil); // Always comes to be NULL
return lkp.getSelectOptions(codeType);
}
}
MyApplication class
#SpringBootApplication
#EnableCaching
public class MyApplication extends SpringBootServletInitializer{
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
#Override
public void onStartup(ServletContext container) {
XmlWebApplicationContext context = new XmlWebApplicationContext();
context.setConfigLocation("/WEB-INF/config/spring-servlet.xml");
//using servlet 3 api to dynamically create spring dispatcher servlet
ServletRegistration.Dynamic dispatcher = container.addServlet("spring", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(2);
dispatcher.addMapping("/");
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
On detailed analysis, my understanding of Autowired become more refined. Thanks to this link.
In my case, I had autowired 'CacheUtil' on a form bean. It appears that the form beans are not being managed by spring or at least in this case. The same autowired works normally in a controller which is managed by Spring.
So I to work around by fetching the Spring Cache 'Proxy' version of CacheUtil from the Application Context. Below code snippet should help (method getInstance()):
import org.springframework.beans.BeansException;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component("MyCache")
public class CacheUtil implements ApplicationContextAware{
private static ApplicationContext appContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
appContext = applicationContext;
}
/**
* Method to fetch the shared instance of the Spring Cache Object that helps reach the
* Cache that resides in Application Context.
*
* #return Singleton shared instance of the Spring Cache Proxy of this class CacheUtil
*/
public static CacheUtil getInstance() {
CacheUtil appCache = appContext.getBean("MyCache", CacheUtil.class);
if(appCache != null) return appCache;
return new CacheUtil();
}

MessageConversionException: Failed to resolve class name in Spring AMQP

I am trying out simple sender and receiving of messages using Spring AMQP with jackson2JsonMessageConverter.
Also, what is the significance of _TypeId_ here
why it is showing sender package with class name?
I am facing issues in receiving the message.
Below is my configuration
org.springframework.amqp.support.converter.MessageConversionException:
failed to resolve class name. Class not found
[org.springframework.amqp.helloworld.User]
at org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper.getClassIdType(DefaultJackson2JavaTypeMapper.java:121)
at org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper.toJavaType(DefaultJackson2JavaTypeMapper.java:90)
at org.springframework.amqp.support.converter.Jackson2JsonMessageConverter.fromMessage(Jackson2JsonMessageConverter.java:145)
at org.springframework.amqp.rabbit.listener.adapter.AbstractAdaptableMessageListener.extractMessage(AbstractAdaptableMessageListener.java:236)
at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:288)
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:777)
... 10 common frames omitted Caused by: java.lang.ClassNotFoundException:
org.springframework.amqp.helloworld.User
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1305)
at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1139)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:250)
at org.springframework.amqp.support.converter.DefaultJackson2JavaTypeMapper.getClassIdType(DefaultJackson2JavaTypeMapper.java:118)
... 15 common frames omitted
XML Configuration
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<rabbit:connection-factory id="connectionFactory"
channel-cache-size="25" host="10.165.18.29" username="BipUser"
password="bip" />
<rabbit:queue name="Job Queue"></rabbit:queue>
<rabbit:queue name="Input Queue"></rabbit:queue>
<rabbit:queue name="More Info Queue"></rabbit:queue>
<rabbit:queue name="Adaptor O/P Queue"></rabbit:queue>
<rabbit:queue name="Command Queue"></rabbit:queue>
<rabbit:queue name="Error Queue"></rabbit:queue>
<bean id="simpleMessageConverter"
class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter">
</bean>
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
message-converter="jsonConverterWithDefaultType" />
<rabbit:listener-container
connection-factory="connectionFactory" auto-declare="true"
message-converter="simpleMessageConverter" auto-startup="true"
acknowledge="auto">
<rabbit:listener ref="rabbitMQJobListener"
queue-names="Job Queue" priority="10" />
</rabbit:listener-container>
<rabbit:admin connection-factory="connectionFactory" id="amqpAdmin" />
<bean id="rabbitMQJobListener" class="com.bosch.bip.rabbitmq.consumer.RabbitMQJobListener">
</bean>
<rabbit:annotation-driven container-factory="rabbitListenerContainerFactory" />
<bean id="rabbitListenerContainerFactory"
class="org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory">
<property name="connectionFactory" ref="connectionFactory"></property>
<property name="messageConverter" ref="jsonConverterWithDefaultType"></property>
</bean>
<bean id="jsonConverterWithDefaultType"
class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter">
<property name="classMapper">
<bean class="org.springframework.amqp.support.converter.DefaultClassMapper">
</bean>
</property>
</bean>
</beans>
Sender
package org.springframework.amqp.helloworld;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.DefaultClassMapper;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.stereotype.Component;
#Component
public class Sender {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);
User user=new User();
user.setPassword("welcome");
user.setUserName("welcome");
user.setXml("myxml");
RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
Jackson2JsonMessageConverter converter = context.getBean(Jackson2JsonMessageConverter.class);
MessageProperties properties = new MessageProperties();
properties.setHeader("user", "user");
properties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
Message message = converter.toMessage(user, properties);
System.out.println(message);
rabbitTemplate.send(message);
}
/* #RabbitListener(queues = HelloWorldConfiguration.helloWorldQueueName)
public void handleMessage(User user) {
System.out.println("User Values::::::::"+user.getPassword());
}*/
}
Consumer
package com.bip.rabbitmq.consumer;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import com.bip.entity.User;
#EnableRabbit
#Component
public class RabbitMQJobListener {
#RabbitListener(queues="Job Queue")
public void onMessage(User message) {
System.out.println(new String(message.getPassword()));
}
}
RabbitMQ
Exchange (AMQP default)
Routing Key Job Queue
Redelivered ○
Properties
priority: 0
delivery_mode: 2
headers:
user: user
__TypeId__: org.springframework.amqp.helloworld.User
content_encoding: UTF-8
content_type: application/json
Payload
57 bytes
Encoding: string
{"userName":"welcome","password":"welcome","xml":"myxml"}
The _TypeID_ header is set on outbound to tell the inbound what class to convert the JSON to. If you want to convert to a different class that is type-compatible with the JSON, you have to configure the converter.
If it'a always the same class, use a custom ClassMapper (not the default one).
Or, see this test, its listener and its configuration to see how to configure a different typeid mapping.
This might happen when the package name of the serialized instance is different than the consumer's model, represented by the headers: TypeId.
I believe following example will make things lot clearer.
Schema: Exchange x.invoice of type fanout is bound to queue q.invoice.
Producer: We are sending JSON message with type Id com.example.produceronequeuemultipletypes.model.InvoiceCreatedMessage.
Class ParseConfig is to help us avoid manual serialization of the instance to String.
public void sendInvoiceMessages() {
invoiceCreatedMessage.setId(0);
invoiceCreatedMessage.setType("Invoice Created");
rabbitTemplate.convertAndSend("x.invoice", "", invoiceCreatedMessage);
}
class InvoiceCreatedMessage {
private String type;
private int id;
}
#Configuration
class ParseConfig {
#Bean
public ObjectMapper getObjectMapper() {
return new ObjectMapper();
}
#Bean
public Jackson2JsonMessageConverter getConverter(
#Autowired ObjectMapper objectMapper) {
return new Jackson2JsonMessageConverter(objectMapper);
}
}
Consumer: Create a class mapper bean with mapping from "com.example.produceronequeuemultipletypes.model.InvoiceCreated" to InvoiceCreated.class.
#Slf4j
#Service
public class InvoiceConsumer {
#RabbitListener(queues = "q.invoice")
public void handleInvoiceCreated(
InvoiceCreatedMessage invoiceCreatedMessage) {
log.info("[Created] Invoice " + invoiceCreatedMessage);
}
}
#Configuration
class ParseConfig {
#Bean
public ObjectMapper getObjectMapper() {
return new ObjectMapper();
}
#Bean
public Jackson2JsonMessageConverter getConverter(
#Autowired ObjectMapper objectMapper) {
Jackson2JsonMessageConverter messageConverter =
new Jackson2JsonMessageConverter(objectMapper);
messageConverter.setClassMapper(getClassMapper());
return messageConverter;
}
#Bean
public DefaultClassMapper getClassMapper() {
DefaultClassMapper classMapper = new DefaultClassMapper();
Map<String, Class<?>> map = new HashMap<>();
map.put(
"com.example.produceronequeuemultipletypes.model." +
"InvoiceCreatedMessage",
InvoiceCreatedMessage.class)
classMapper.setIdClassMapping(idClassMapping);
return classMapper;
}
}
class InvoiceCreatedMessage {
private String type;
private int id;
}
Reference:
https://docs.spring.io/spring-amqp/reference/html/#json-message-converter
https://www.udemy.com/course/rabbitmq-java-spring-boot-for-system-integration/

How to load Spring applicationContext into Jersey Application

I'm creating a Jersey JAX-RS web service with the following:
package com.mycompany.rest.config;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
return getRestResourceClasses();
}
private Set<Class<?>> getRestResourceClasses() {
Set<Class<?>> resources = new java.util.HashSet<Class<?>>();
resources.add(com.mycompany.rest.controllers.UserController.class);
return resources;
}
}
However, when I try and integrate a spring applicationContext such as the following :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.mycompany.rest.user"/>
<bean id="userService" class="com.mycompany.rest.user.UserServiceImpl" />
</beans>
I get null pointers from my controller class for the userService being loaded by the bean pasted above. I'm assuming this is because the application context is not being loaded into the Jersey application.
Is there a way of doing this?
If you want to inject Spring beans into your Jersey resource classes, you need to add jersey-spring3 dependency to your class path. see https://jersey.java.net/documentation/latest/spring.html
An hello-world example can be found at https://github.com/jersey/jersey/tree/2.19/examples/helloworld-spring-webapp
I had the same problem, and i fixed it by adding #autowired to my service, and extending SpringBeanAutowiringSupport like the following :
#Path("/mails")
public class MailController extends SpringBeanAutowiringSupport{
#Autowired
private MailService mailService;
#GET
#Path("/{code}")
#Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public String getMails(#PathParam("code") String code) throws Exception {
//function logic
}
Note that this is working without integrating jersey-springx.jar
And I'm using Spring 3 along with jersey-bundle-1.19.1.jar

Can I use both configuring SI with annotation in java file and xml?

Last year, spring integration released 4.0 version for us to configure using annotation without configuring in XML files. But I want to use this feature using the existing XML configurations.
So I wrote the code using spring boot and integration annotation
#Configuration
#ComponentScan(basePackages ={"com.strongjoe.blue"},excludeFilters=#ComponentScan.Filter(type=FilterType.REGEX, pattern={"com.strongjoe.blue.agent.Bootstrap*"}))
#IntegrationComponentScan
#ImportResource( {"${context.agent.path}context-bean-*.xml", // Context Configuration
"${project.agent.path}context-properties.xml" } ) // Project Based Chain configuration
public class AgentStarter implements CommandLineRunner{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Lazy
#Bean
#ServiceActivator(inputChannel="blue-hub-start-channel", outputChannel="blue-hub-route-channel")
public <T> BlueMessage<T> startJob(BlueMessage<T> msg) {
logger.debug("BluE Hub Agent started :{} [phrase:{}]", System.currentTimeMillis() , "prototype-version");
return msg;
}
#Lazy
#Bean
#ServiceActivator(inputChannel="blue-hub-end-channel")
public <T> BlueMessage<T> endJob(BlueMessage<T> msg) {
logger.debug("BluE Hub Agent ended :{} [phrase:{}]", System.currentTimeMillis() , "prototype-version");
return msg;
}
#Bean
#Transformer(inputChannel="blue-normalized-channeel", outputChannel="blue-output-channel")
public org.springframework.integration.transformer.Transformer JsonToMap( ) {
return new JsonToObjectTransformer( List.class );
}
#MessageEndpoint
public static class Echo {
#ServiceActivator(inputChannel="blue-output-channel")
public void stringEcho(Message message) {
}
}
#Autowired
Gateway gateway;
public static void main(String[] args) {
SpringApplication app = new SpringApplication(AgentStarter.class);
app.setWebEnvironment(false);
app.run(args).close();
}
#Override
public void run(String... args) throws Exception {
System.err.println("blue-hub-agent started..");
System.out.println(gateway.sendReceive("gitlab"));
}
And I wrote the definition about every channel I use in the xml.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-ws="http://www.springframework.org/schema/integration/ws"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-4.0.xsd
http://www.springframework.org/schema/integration/ws http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd
http://www.springframework.org/schema/integration/xml http://www.springframework.org/schema/integration/xml/spring-integration-xml.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http-4.0.xsd">
<int:channel id="blue-normalized-channel" />
<int:channel id="blue-header-channeel" />
<int:channel id="blue-request-channel" />
<int:channel id="blue-output-channel" />
<int:channel id="blue-gitlab-request-prepare-channel" />
<int:channel id="blue-hub-start-command-channel" />
<int:channel id="blue-hub-start-channel"/>
<int:channel id="blue-hub-end-channel" />
But I got error.
Caused by: org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application:8090.blue-hub-start-channel'.
at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:81)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:255)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:223)
The reason will be, I think,
that spring bean in XML file and spring bean with the annotation has different context. So I think that even if blue-hub-start-channel is subscribed by the service activator named "startJob", it got error.
How can I solve this problem?
Annotating #ServiceActivator on #Bean is not for POJO Messaging. See the documentation.
When you annotate #Beans this way, you have to provide an appropriate object (MessageHandler in this case).
For POJO style annotated methods, the annotation must be on a method in a #Bean method (like you have on this one...
#MessageEndpoint
public static class Echo {
#ServiceActivator(inputChannel="blue-output-channel")
public void stringEcho(Message message) {
}
}
... and then declare a #Bean for Echo.
You can put all your #ServiceActivator methods (and #Transformers) in the same #MessageEndpoint.

unable to use Spring Advice(#Before) using annotations

I am new to springs and trying to run a simple java application with java advices....
xml file...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<aop:aspectj-autoproxy>
<aop:include name="com.cts.two.Advices"/>
</aop:aspectj-autoproxy>
<context:annotation-config/>
<context:component-scan base-package="com.cts.two"></context:component-scan>
</beans>
Advice Class
package com.cts.two;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
#Aspect
public class Advices implements Adv{
#Pointcut("execution(* com.cts.two.*.*(..))")
public void advice(){
}
#Before("advice()")
public void before(JoinPoint name) throws Throwable{
System.out.println("inside advices");
/*System.out.println(name.getClass() + " this is get class");
System.out.println(name.getSignature().getName() + " this is the get signatue and get name");*/
}
}
class on which advice needs to be applied...I want the before method of Advice class to be executed before below mentioned test() method
package com.cts.two;
import org.springframework.stereotype.Component;
#Component
public class ClassA {
private ClassB b= new ClassB();
public void setB(ClassB b) {
this.b = b;
}
public void test(){
System.out.println("inside classA test");
//b.test();
}
}
caller of methods/test class/main class
package com.cts.two;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class CallerAB {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext context = new ClassPathXmlApplicationContext(
"AllAnnotations.xml");
ClassA calledA = (ClassA) context.getBean("classA");
calledA.test();
}
}
the problem is that when I run the code directly the test method of class A is executed but the advice is not...
Kindly advice..
Am i missing something ???
AspectJ 1.6.12 jar is also added...
Aspects should be decalred as beans.
#Aspect doesn't do it automatically, <aop:include> doesn't do it as well (it sets additional restriction on beans that can be used as aspects).
So, you need
#Aspect
#Component
public class Advices implements Adv { ... }
and don't need <aop:include>.
As mentioned in the answer from #axtavt you need to add the #Component annotation. But you also need to remove the <aop:include>. Your spring wiring xml should just be:
<aop:aspectj-autoproxy/>
<context:annotation-config/>
<context:component-scan base-package="com.cts.two"/>
As stated in the spring AOP documentation, the name attribute in the <aop:include> element is supposed to be a bean name, not a class name. Specifying a bean explicitly overrides Spring's auto-detection and specifying it incorrectly means that there is no aspect used at all.

Resources