I am trying to use Apache Camel File-Watch feature.
However I notice all example are used along with Spring.
Is there anyway to make use of this feature without Spring ?
Thank you for any potential input.
Best regards.
Apache Camel is a standalone integration framework to easily integrate different systems using well know and established EIP (Enterprise Integration Patterns).
It is not tied to Spring in any way at its core and has different deployment / integration models out of which is Spring / Spring Boot for the sake of easing its adoption and configuration for Spring framework users.
Out of the runtime contexts, you can use for example Camel Main component to run your application having a File Watch component setup to watch the /tmp/ directory change events:
The main application would look like the following:
public class FileWatchApplication {
private FileWatchApplication() {
}
public static void main(String[] args) throws Exception {
// use Camels Main class
Main main = new Main(FileWatchApplication.class);
// now keep the application running until the JVM is terminated (ctrl + c or sigterm)
main.run(args);
}
}
A simple RouteBuilder setting up your File Watch component would look like the following (note that it must be within the same (or child) package of the FileWatchApplication class):
public class FileWatchRouteBuilder extends RouteBuilder {
#Override
public void configure() throws Exception {
// snippet configuration from the official documentation
from("file-watch:///tmp/")
.log("File event: ${header.CamelFileEventType} occurred on file ${header.CamelFileName} at ${header.CamelFileLastModified}");
}
}
Camel is based on Spring. In fact, the Camel Context is an extension of the Spring Application Context. So if you have Camel, you also must have Spring.
Related
I am trying to use Spring boot and akka. I have two processes and communicate with akka cluster. Only process A uses spring boot.
#Autowired
private ActorSystem springActorSystem;
#Autowired
private SpringExtension springExtension;
private ActorRef caActor;
caActor = springActorSystem.actorOf(springExtension.props("clientAgentActor"), "ca");
If I create the actor on process A, of course, using springExtension, all injections are working. However, the caActor is a cluster actor. If process B send a message to process A, the ClientAgentActor invoked somewhere, all injections are failed.
How to solve it?
#Component
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class ClientAgentActor extends AbstractActor {
private static final Logger logger = LogManager.getLogger(ClientAgentActor.class);
#Autowired
ClientAgentService caService;
#Autowired
LineService lineService;
#Override
public Receive createReceive() {
//TODO
return receiveBuilder().match(String.class, msg -> logger.debug(msg)).build();
}
Thought the same for almost whole day. And I think there is no way to integrate Spring into Akka cluster with full DI for cross-cluster calls without changing the core of Akka Cluster.
When you do call without cluster inside one JVM you use Akka wrapper instead of pure Akka.
But when you do call in cluster this call is recieved on other node by pure Akka infrastructure without Spring wrapper, so this infrastructure doesn't know about Spring actors proxies that's why you see no injections.
So if you need Spring in Akka Cluster you need to wrap the core of this library with Spring infrastructure. Except it would be not easy to implement it would be also hard to follow the Akka rules and conventions in application architecture. For example, it would be too easy to inject transitive dependency which has blocking calls or multithreading code.
If you need to use some Spring functionality I think the best way to do this is to fully separate Akka infrastructure from Spring's one. And after application initialization set global static field with created ApplicationContext and make applicationContext.getBean(...) calls where they are needed. Of course you can do comfortable method for this. Or for example class with public static fields with needed beans which are set once after Spring initialization completes.
With Spring's AbstractRefreshableApplicationContext, I am able to force Spring to fail if there is a conflict in Bean IDs or circular references by setting a couple of flags and refreshing the context like so:
AbstractRefreshableApplicationContext refreshableContext;
...
refreshableContext.setAllowBeanDefinitionOverriding(false);
refreshableContext.setAllowCircularReferences(false);
refreshableContext.refresh();
However, Spring Boot returns a ConfigurableApplicationContext which is not an instance of AbstractRefreshableApplicationContext and does not appear to have any means to prevent bean definition overriding or circular references.
Does anyone know of a way and have an example of how to prevent these types of conflicts?
For context, this is for a large project that has a mix of annotated and xml defined beans. The version of Spring Boot used is 1.3.1.RELEASE. There have been some cases where folks added duplicate bean definitions in the xml, but the application started up fine and wasn't immediately apparent the original bean was overridden until run-time issues started occurring.
The goal here is to prevent the application from event starting up if such a conflict occurs. From various forums I know Spring IDE can detect these, but the desire is to enforce this in the CI build which is a stronger safety net.
After some searching, I can't find any support for this in the context that Sprint Boot returns. If this can't be done through the context, is there a different solution available?
Thanks in advance.
You may use an initializer when building your Spring Boot app:
#SpringBootApplication
public class SpringBootApp {
public static void main(String... args) {
new SpringApplicationBuilder(SpringBootApp.class)
.initializers(new ApplicationContextInitializer<GenericApplicationContext>() {
#Override
public void initialize(GenericApplicationContext applicationContext) {
applicationContext.setAllowBeanDefinitionOverriding(false);
}
})
.run(args);
}
}
Or with java 8:
new SpringApplicationBuilder(SpringBootApp.class)
.initializers((GenericApplicationContext c) -> c.setAllowBeanDefinitionOverriding(false) )
.run(args);
add below into your application.yml
spring.main.allow-bean-definition-overriding: false
Background
I have an existing Grails application which I'm rewriting in Spring. My Grails application (simplified for example) has 2 plugins, UserProfilePlugin and UserOrderPlugin where each plugin has its own code + config + resources. Depending on a client's request, I can generate an application which is compiled/packaged to include:
Both UserProfilePlugin and UserOrderPlugin to display both User Profiles and User Orders
Only UserProfilePlugin to display only User Profiles
Only UserOrderPlugin to display only User Orders
Problem
I want to modularize my Spring application to have multiple code + config + resources units which can be included/excluded from the main application at compile/package time and can be reused across multiple applications. But I'm struggling to find Spring's equivalent of a Grails plugin. I have already gone through Spring's official documentation 1, 2, 3, 4, etc. but could not find anything useful. On the contrary, Spring application (as per the document) looks more like one monolithic unit with no reusable sub-units inside it.
Am I missing something obvious? Can someone please throw some light on this?
Spring does not have such a concept, but there are several ways to implement it.
The easiest way is probably to have a component scan in your application that would pick up all components from the optional package.
Let's say your "module" defines a top-level package "com.yourcompany.yourapp.module", then you would just have to make sure that all other parts of the same app are underneath "com.yourcompany.yourapp" and set your component scan to "com.yourcompany.yourapp".
If you are not a big fan of component scan, the cleanest way I can think of is the Java ServiceLoader SPI. You could define an interface that does the registration with Spring, e.g.
public interface SpringConfig{
void register(ApplicationContext ac);
}
(I'm sure you can improve on this design)
Anyway, in each module, you'd have a file called
/META-INF/services/com.yourcompany.yourapp.SpringConfig
that lists all implementations this module holds. In your central app, you could then have a component that initializes the modules:
#Component
public class ModuleInitializer implements ApplicationContextAware, InitializingBean {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(final ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Override
public void afterPropertiesSet() throws Exception {
for (SpringConfig springConfig : ServiceLoader.load(SpringConfig.class)) {
springConfig.register(applicationContext);
}
}
}
In both versions, you enable / disable a module by adding it to / removing it from the classpath. So the easiest way to do that is to have one build artifact (e.g. Maven module) per application module
Spring Boot automatically initializes the underlying logging system using the LoggingApplicationListener. This is a nice thing if the application I'm developing runs isolated or standalone.
However I'm developing a web application that will be deployed into the WSO2 Application Server, which offers unified logging (using log4j), with features like central log level management (at runtime via web interface), business reporting etc.
If I use Spring Boot "as is", it logs everything completely on its own. My first shot was, to remove spring-boot-starter-logging and manually add slf4j-api as provided. This works to some extent, since the LoggingApplicationListener now overrides settings of the global logmanager provided by WSO2 (and even causes global appenders to be closed).
The only "solution" I came up with is to remove the listener via reflection. Then Spring Boot starts to behave exactly as it should (logging via the global logger and not overriding the pre defined log levels, output formats, appenders, etc.)
That "solution" looks like this:
#SpringBootApplication
public class MyApp extends SpringBootServletInitializer {
public static void main(String... args) {
SpringApplication.run(MyApp.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
try {
Field appField = SpringApplicationBuilder.class.getDeclaredField("application");
appField.setAccessible(true);
SpringApplication app = (SpringApplication)appField.get(builder);
Field listenersField = SpringApplication.class.getDeclaredField("listeners");
listenersField.setAccessible(true);
List<ApplicationListener<?>> listeners = (List<ApplicationListener<?>>) listenersField.get(app);
for (int i = listeners.size() - 1; i >= 0; --i) {
if (listeners.get(i) instanceof LoggingApplicationListener) {
listeners.remove(i);
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return builder.sources(MyApp.class);
}
}
Is there any better solution to my problem that's maybe less hacky which I may have overlooked during my research and code analysis?
thank you for you post it is very helpful.
I had the same problem with Websphere Aplication Server: After spring boot context initialized I had no more logs. This solution is equivalent but less dirty by overriding the run method of SpringBootServletInitializer:
#Override
protected WebApplicationContext run(SpringApplication application) {
Collection<ApplicationListener<?>> listeners =
new ArrayList<>();
for (ApplicationListener<?> listener: application.getListeners()) {
if (!(listener instanceof LoggingApplicationListener)) {
listeners.add(listener);
}
}
application.setListeners(listeners);
return super.run(application);
}
Since Spring Boot 1.4 the LoggingSystem autoconfiguration can be disabled.
Take a look at the Custom Log Configuration section of the Spring documentation:
You can force Spring Boot to use a particular logging system by using the org.springframework.boot.logging.LoggingSystem system property. The value should be the fully qualified class name of a LoggingSystem implementation. You can also disable Spring Boot’s logging configuration entirely by using a value of none.
For Tomcat, for example, set the environment variable JAVA_OPTS:
JAVA_OPTS="-Dorg.springframework.boot.logging.LoggingSystem=none"
I am developing an non-web application and I would like to set up Spring in it. I would like to have minimal configuration that supports auto-wiring. What's the proper way to do this? Do I need to implement my own ApplicationContext loading mechanism, or is there something better I could do?
Spring provides an IoC container in the form of an ApplicationContext. However, you need to implement your own mechanism for creating the container. But that can be pretty simple
public class Start {
public static void main(String[] args) {
ApplicationContext context = ...// whichever flavor you want
// maybe start some threads, possibly managed by the IoC container
}
}
The container itself can either use XML configuration or a programatic one. Read the official documentation on how to do either, here.