Abe Abe - 4 months ago 24
Java Question

Can I use @Async annotation with Grails

As per the following spring doc link I can use @Async annotation to make a method call asynchronous. Can I use this facility in Grails from a java src file that I have?

[Update]
This is my java(netty) socket handler class which receives the socket packet.

public class DefaultHandler extends SimpleChannelUpstreamHandler {

private static final Logger LOG = LoggerFactory.getLogger(DefaultHandler.class);

private AggregateSocketData aggregateSocketData;

@Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
throws Exception {
LOG.trace("In messageRecieved method with event: {}",e);
IEvent event = Events.dataInEvent(e.getMessage());
System.out.println(Thread.currentThread().getName());
aggregateSocketData.receiveSocketData(event);
}


@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
throws Exception {
LOG.error("Exception occurred in Default Handler: " ,e.getCause());
}

public AggregateSocketData getAggregateSocketData() {
return aggregateSocketData;
}

public void setAggregateSocketData(AggregateSocketData aggregateSocketData) {
this.aggregateSocketData = aggregateSocketData;
}


}

I have made it a bean in grails- conf - resources.xml

<bean id="defaultECM1240Handler" class="com.appcapture.buildingmgr.netty.DefaultHandler"
scope="prototype">
<property name="aggregateSocketData" ref="binaryDataAggregatorService"></property>
</bean>


And this is my grails service class whose method I have annotated with @Async

class BinaryDataAggregatorService implements AggregateSocketData {

def rawDataService
static transactional = true

@Async
void receiveSocketData(IEvent event) {
println Thread.currentThread().name
log.debug("Going to decode netty packet in receiveSocketData");
Map decodedPacket = decodePacket((INettyPacket)event.getSource())
def rawData = saveRawData (decodedPacket);
log.debug ("Saved raw data, id: ${rawData?.id}")
rawDataService.saveHTTPData(decodedPacket);
}


}

[Update 2] Here is the stack trace for the method call.
Here is the stack. BinaryDataAggregatorService.receiveSocketData(INettyPacket) line: 20
BinaryDataAggregatorService$$FastClassByCGLIB$$82489f62.invoke(int, Object, Object[]) line: not available

MethodProxy.invoke(Object, Object[]) line: 149

Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint() line: 688

Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 150

TransactionInterceptor.invoke(MethodInvocation) line: 110

Cglib2AopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 172

Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 621
BinaryDataAggregatorService$$EnhancerByCGLIB$$1c96985c.receiveSocketData(INettyPacket) line: not available

DefaultHandler.handlePacket(INettyPacket) line: 50

[Update 3]
The grails stack trace on setting the task:annotation-driven element.

011-05-26 17:38:03,109 [main] ERROR context.GrailsContextLoader - Error executing bootstraps: Error creating bean with name 'defaultECM1240Handler' defined in URL [file:./grails-app/conf/spring/resources.xml]: Cannot resolve reference to bean 'binaryDataAggregatorService' while setting bean property 'aggregateSocketData'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'binaryDataAggregatorService': Invocation of init method failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy12]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy12
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultECM1240Handler' defined in URL [file:./grails-app/conf/spring/resources.xml]: Cannot resolve reference to bean 'binaryDataAggregatorService' while setting bean property 'aggregateSocketData'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'binaryDataAggregatorService': Invocation of init method failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class $Proxy12]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy12


Thanks,

Abraham

Answer

If it is a spring bean - yes, you can. For that you have to annotate it with @Service and have a <context:component-scan base-package="com.foo.bar" />

But to make it easier, you can use a groovy class placed in the grails-app/services - it will be a spring bean automatically

In order to make @Async work, you need <task:annotation-driven/> in the xml config.

Comments