CamelContext not picking up Spring annotated Routes - spring

I have just started to use Camel in one of my projects. I am trying to configure Camel with Spring, but having issues doing that.
I don't want to use xml configuration but rather go with Spring based Annotations for configuring Routes and Processors.
My App is a stand alone Spring Application, which will be run as Jar.
To keep the app running, I've a empty scheduled method which runs every x min.
Below are the dependencies in my build.gralde
// Spring //
compile('org.springframework:spring-core:5.0.0.RC2')
compile('org.springframework:spring-context:5.0.0.RC2')
compile('org.springframework:spring-beans:5.0.0.RC2')
compile('org.springframework:spring-context-support:5.0.0.RC2')
// Apache //
// Camel //
compile('org.apache.camel:camel-core:2.19.1')
compile('org.apache.camel:camel-spring:2.19.1')
snapshot of beans.xml
<context:annotation-config/>
<tx:annotation-driven/>
<context:component-scan base-package="my.package" />
<camelContext id="aggregatorCamelContext" autoStartup="true" xmlns="http://camel.apache.org/schema/spring">
<package>
my.package.camel
</package>
</camelContext>
Sample RouteBuilder
#Component
public class SampleRoute extends RouteBuilder {
#Autowired
MyClass myObject;
#Override
public void configure() throws Exception {
from("file:filelist")
.process(myObject)
.to("file:processedList");
}
}
To keep the app alive ( I know bit hacky, but suffices for now )
#Component
#EnableScheduling
public class KeepitAlive {
#Scheduled(fixedRate = 1000l)
public void run(){
System.out.println("KeepitAlive.run "+ Thread.currentThread().getName() );
}
}
Main Class. I have tried both the methods, Initializing Spring context as well as Camel Main, but to no luck
public class MyApplication {
public static void main(String[] args) throws Exception {
/*AbstractXmlApplicationContext context =
new ClassPathXmlApplicationContext("path/to/beans.xml");*/
Main main = new Main();
main.setApplicationContextUri("path/to/beans.xml");
main.start();
}
}
If I put my Route within camelContext declaration itself, it works absolutely fine,
<route>
<from uri="file:filelist"/>
<to uri="file:processedlist"/>
</route>
I've also looked into Camel Spring Integration documentation, but it also contains xml based configuration.
Could anybody please guide me in right direction.

You are using Camel's own package scanning via
<package>
my.package.camel
</package>
You should use <contextScan> if you want Camel to find the Spring #Component Camel routes.
See the Camel spring documentation for more: http://camel.apache.org/spring.html

Figured it out ultimately. Need to extend SpringRouteBuilder instead of RouteBuiler above in SampleRoute class.
Anybody struggling with issues, I suggest once go through Camel in Action book.
Somehow I missed it in the beginning which costed me lot of time figuring out trivial things that this book covers.

Related

Register spring bean as an apache camel route builder with java config

apache camel documentation describes how to register a route builder with #Component and SpringRouteBuilder and then jumps to the xml code to do
<camelContext xmlns="http://camel.apache.org/schema/spring">
<!-- and then let Camel use those #Component scanned route builders -->
<contextScan/>
</camelContext>
How can I do the same with java config? I've got
package x.y.camel;
#Component
public class MyRouteBuilder extends SpringRouteBuilder {...}
and
#EnableWebMvc
#EnableAutoConfiguration
#ComponentScan(basePackages = {"x.y"})
public class Application implements WebApplicationInitializer {
#Bean
public SpringCamelContext camelContext(ApplicationContext applicationContext) throws Exception {
SpringCamelContext camelContext = new SpringCamelContext(applicationContext);
return camelContext;
}
The component is picked up by spring and created, that part is fine. I can register the route by camelContext.addRoutes(new MyRouteBuilder());. The only bit is missing is how to tell camel context to pick up the route if it's managed as a spring bean.
Your approach does not work, because you don't create your camel context with the CamelContextFactoryBean. This is where the logic is hidden that looks for Spring Bean Camel Routes in your classpath.
The easiest solution to the problem is to add a xml-based Spring context configuration that references this factory bean!
Alternatively, you can try calling the factory bean from your Application class (see this link: FactoryBeans and the annotation-based configuration in Spring 3.0), but calling a factory bean from a #Configuration class is tricky, because they are both part of mechanisms that are not build for compatibility. Especially, since CamelContextFactoryBean is also implementing InitialisingBean.
It turns out I was pretty close to the solution. All I had to do is to add a ComponentScan annotation on my CamelConfiguration class that I already had.
#Configuration
#ComponentScan("x.y.camel")
public class CamelConfig extends CamelConfiguration {
}
And then remove public SpringCamelContext camelContext(ApplicationContext applicationContext) from my Application class.
That's it - the RouteBuilder is picked up automatically.

AOP/Aspectj, Spring (4.0.5) in spring webapplication not working, in test it does

i really hope someone can help me, i am trying to create some very simple AOP Operations in my web-application.
Unfortunately it is not triggered at all.
Here my configs:
web.xml (to load application.xml)
<!-- web.xml -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/application*.xml</param-value>
</context-param>
And the application.xml
<!--application.xml-->
<aop:aspectj-autoproxy proxy-target-class="true" /> <!-- i tried with and without proxy-->
<bean id="config" class="com.whatever.config.Configuration"/> <!-- beans are not definend in application.xml, but in a separate class-->
The config class
#Configuration
#PropertySource({ "classpath:/ui.properties" })
#Import({ somclass.class, ScanBean.class})
public class Configuration {
}
The scanbean class
#Configuration
#ComponentScan(basePackages = { "com.ui.common", "com.ui.aspects" })
public class ScanBean {
#Bean
public DefaultEntityServiceAspect defaultEntityServiceAspect() {
return new DefaultEntityServiceAspect();
}
}
Beans are there and everything starts without any error.
The aspect beans...
The annotation
#Retention(RetentionPolicy.RUNTIME)
public #interface DefaultEntity {}
// the aspect itself
#Aspect
public class DefaultEntityServiceAspect {
private final Logger logger = Logger.getLogger(DefaultEntityServiceAspect.class);
#Around("#annotation(com.ui.aspects.DefaultEntity)")
public void setDefaultEntityFields(ProceedingJoinPoint joinPoint) throws Throwable {
logger.warn("doing something 2 huhu");
joinPoint.proceed();
}
}
And finally the bean itself
#Service
#Scope("session")
public class AdminBean implements Serializable {
// some code...
#DefaultEntity
public void wtfIsWrongWithYou() {
logger.debug("am i working?");
}
}
If i write a simple JUNIT Test, it is working like expected. As soon as i deployed it to the server (tomcat). Nothing works anymore.
I found a 1000 tips, but non of them was working. I think i read everything here on stackoverflow :) but a solution was not found. I would really appreciate every tip.
Cheers!
Edit:
I created a small project on github. I still did not get it run .. if someone has a hint, please let me know! Thank you!
I finally made it work in my "big" application as well. The root cause was that i externalized all the spring / hibernate aso. libraries.
In fact i was using the shared lib settings from tomcat and had all my spring libraries on that server. This is working fine as long as you do not use aspectj / spring aop.
After i created a war file with the libs included (WEB-INF/lib) it was working immediately.
It also kind of makes sense, since the libs are loaded by different classloaders aso... hope it helps somebody as well!

Camel, Spring, OSGI: Is there a way to specify the stop method?

I'm running a Camel Spring OSGI application. The Camel context is initialized through Spring.
When the bundle stops, I need to do some clean-up activities, like de-registering the message listener. How do I do that? Is there a method I can override? I understand that an OSGI bundle must provide the activator start and stop methods but my understanding also is that the Camel/Spring/OSGI framework overrides these methods.
My beanx.xml:
<beans>
<camelContext id="camel" xmlns="http://camel.apache.org/schema/spring">
<routeBuilder ref="outboundBuilder" />
</camelContext>
</beans>
My java code:
public class MyRouteBuilder extends RouteBuilder {
public void configure() {
.....
}
}
Just to expand a little on the answer of Bilgin Ibryam which is correct.
Camel has the ability to apply a policy to a route. This Policy controls routes at runtime. This will allow you to do custom logic at certain events of the route life time.
Implementing a route policy.
It is rather simple declare a new class which extends RoutePolicySupport then override the methods you are interested in.
public class MyRoutePolicy extends RoutePolicySupport{
#Override
public void onStart(Route route) {
// TODO Auto-generated method stub
super.onStart(route);
}
#Override
public void onStop(Route route) {
// TODO Auto-generated method stub
super.onStop(route);
}
#Override
public void onExchangeBegin(Route route, Exchange exchange) {
// TODO Auto-generated method stub
super.onExchangeBegin(route, exchange);
}
}
Now use the route in your routebuilder configure() method like this:
RoutePolicy policy = new MyRoutePolicy();
from("timer://blah")
.routeId("Test1").routePolicy(policy)
.setBody().constant("A Message Like Hello World")
.to("mock:meh");
If you were just using a Spring XML with a route then add the following:
<bean id="policy" class="MyRoutePolicy"/>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route id="foo" routePolicyRef="MyRoutePolicy">
<from uri="timer://blah"/>
<setBody><constant>A Message Like Hello World</constant></setBody>
<to uri="mock:meh"/>
</route>
</camelContext>
You can use Camel Route policy and write your code to cleanup resource when the route is about to stop or be removed from the context.

Spring Aspects not executing

I've been working on adding aspects to a Spring MVC webapp, and the aspects aren't executing. I've tried to boil it down to something dirt simple that clearly should work, but still no go. Here's where I'm at now:
// imports...
#Aspect
public class AuthCheckerAspect {
{
System.out.println("initting");
}
#Pointcut("execution(* * *(..))")
public void c() {}
#Before("c")
public void cc(JoinPoint pjp) throws Throwable {
System.out.println("test...");
}
}
As far as I can tell, the pointcut should apply to any method in any Spring-managed class (of which there are a lot in my application). I also added the following to my Spring config:
<aop:aspectj-autoproxy/>
I set a breakpoint at the System.out.println() statement in the cc() method, but it never caught (and yes, I'm positive that the debugger is attached; other breakpoints catch properly). I'm suspecting that the AuthCheckerAspect class is never getting loaded into the Spring context, because I also set a breakpoint within the initializer clause, and that never catches either; when I do the same with other Spring-managed classes, their breakpoints always catch during app startup.
Is there something else I need to be doing?
Thanks in advance.
Spring does not automatically mange #Aspects. Add <bean class="AuthCheckerAspect" /> to your context or annotate it with #Component and include in component scan path.
add this to your configuration file:
<context:annotation-config />
<context:component-scan base-package="root.package.to.be.scanned" />
<aop:aspectj-autoproxy>
<aop:include name="nameOfAspectBean" />
</aop:aspectj-autoproxy>

Spring AOP: advice is not triggered

Trying to design simple aspect,that will print word "logg" to console,when any of public methods executed.
aspect:
#Aspect
public class LoggingAspect {
#Pointcut("execution(public * *(..))")
public void publicServices() {
};
#Before("publicServices()")
public void logg() {
System.out.println("logg");
}
}
xml config:
<context:component-scan base-package="aspectlogging" />
<aop:aspectj-autoproxy/>
<bean id="loggingAspectHolder" class="aspectlogging.LoggingAspect"/>
simple bean:
package aspectlogging;
#Component
public class TestableBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
test:
public class TestLogging {
public static void main(String[] args) {
TestableBean tb = new TestableBean();
tb.setName("yes");
tb.getName();
}
}
I expect,that result of running of TestLogging will be "logg" word in console,and no output returned.
Do I understand AOP correctly in this case?
With #Around advice, you need to have a ProceedingJoinPoint pjp argument to the advising method and to call pjp.proceed() at the point in the advisor when you want the wrapped method to be called. It's easier to use #Before advice really, when what you've done will otherwise work just fine.
[EDIT]: Also, you must let Spring construct your beans for you instead of directly calling new. This is because the bean object is actually a proxy for your real object (which sits inside it). Because your target object doesn't implement an interface, you will need to have the cglib library on your classpath in addition to the Spring libraries. (Alternatively, you can go with using AspectJ fully, but that requires using a different compiler configuration.)
To create your beans, you first need to create a Spring context and then query that for the bean instance. This means you change from:
TestableBean tb = new TestableBean();
To (assuming you're using Spring 3, and that your XML config is in "config.xml" somewhere on your classpath):
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
TestableBean tb = context.getBean(TestableBean.class);
The rest of your code remains the same (after adjusting for import statements and possibly additional dependencies).
Not quite sure on this one, but maybe you need to use a spring managed TestableBean to have spring AOP pick up the method call.
edit: of course, you can't use #Around the way that you provided - but this subject has been addressed by another answer, so it's omitted here.
edit2: If you need help on how to get a spring managed bean, please feel free to ask. but since you already got your aspect bean set up, I believe you can handle this :)
edit3: Hehe. Ok.. maybe not :)
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
will load your application context.
Load beans from there by calling:
TestableBean testableBean = (TestableBean )ctx.getBean("testableBean ");
Define the TestableBean just like you did with your Aspect bean.
edit4: Now I'm pretty sure that the fault is the non-spring managed bean.
Use the simplest thing that can work. Spring AOP is simpler than using full AspectJ as there is no requirement to introduce the AspectJ compiler / weaver into your development and build processes. If you only need to advise the execution of operations on Spring beans, then Spring AOP is the right choice. If you need to advise domain objects, or any other object not managed by the Spring container, then you will need to use AspectJ.
Taken from: http://static.springsource.org/spring/docs/2.0.x/reference/aop.html

Resources