Skip to content
This repository has been archived by the owner on Dec 3, 2017. It is now read-only.

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
tkrullmann committed Mar 16, 2015
1 parent ff9a602 commit e9d9cfa
Show file tree
Hide file tree
Showing 46 changed files with 2,447 additions and 15 deletions.
17 changes: 5 additions & 12 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
.*
*.iml
*.iws
bin/
build/
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015 unbroken-dome
Copyright (c) 2015 Till Krullmann

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
208 changes: 206 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,206 @@
# spring-integration-eventbus
An event bus connecting event publishers and event subscribers in a decoupled fashion, based on the Spring Integration framework.
# Spring Integration Event Bus
An event bus library for Java/Spring projects, based on the Spring Integration framework.

Event-driven architectures promote loosely coupled interactions between event publishers and event subscribers.
Events are essentially messages with added semantics, which is why many event infrastructures are built on some kind of
messaging framework (like Spring Integration).

This library aims to combine the ease of use of the [Guava EventBus](https://code.google.com/p/guava-libraries/wiki/EventBusExplained)
with the power of the Spring and Spring Integration frameworks.

Notable features include:

- Declarative subscriber registration using method annotations
- Async events use a configurable [message store](http://docs.spring.io/spring-integration/reference/htmlsingle/#message-store)
- Transactional subscriber support
- Sync or async behavior on a per-subscriber basis
- Optional auto-configuration when using [Spring Boot](http://projects.spring.io/spring-boot/)


## Prerequisites

To use this library, your project needs to use:
- Java 8
- Spring Integration 4.1.x or higher
- Spring Framework 4.x or higher


## Setup

If your project uses Spring Boot and auto-configuration, then all you have to do is include the spring-integration-eventbus
library JAR on your classpath.

To enable the event bus manually, add the `@EnableEventBus` annotation to one of your `@Configuration` classes:

```java
@Configuration
@EnableEventBus
public class MyConfig {
}
```


## Publishing events

The event bus configuration provides a bean of type `EventPublisher` that can be injected to any bean that wishes
to publish events.

An event may be any object, but since it is going to forwarded to potentially many subscribers, it is preferred to
use only immutable objects as events.

```java
@Service
public class MyService {

@Autowired
private EventPublisher eventPublisher;

public void doSomething() {
// ...
eventPublisher.publish(new SomethingHappenedEvent());
}
}
```

## Subscribing to events

Simply place the `@Subscribe` annotation on any method that should be subscribed to a particular event type.

The method must have a return type of `void` and take exactly one parameter, which will be the event.
The parameter type may be an interface or abstract class.

The method will then be called by the event bus whenever an event of the given type (or a derived type) is published.

```java
@Service
public class MySubscriber {

@Subscribe
public void somethingHappened(SomethingHappenedEvent event) {
System.out.println("Something happened...");
}
}
```

## Subscription types

The Spring Integration Event Bus supports both synchronous and asynchronous subscribers in the same event bus.

### Synchronous subscribers

Subscribers will be default be called in a synchronous fashion; that means that they run in the same thread
(and hence in the same transaction) as the call to `EventPublisher.publish`.


### Asynchronous subscribers

To mark a subscriber as asynchronous, specify the argument `async = true` on the `@Subscribe` annotation. Events sent
to asynchronous subscribers will be queued using a `ChannelMessageStore`, and run on a different thread than the
publisher.

```java
@Service
public class MySubscriber {

@Subscribe(async = true)
public void somethingHappened(SomethingHappenedEvent event) {
System.out.println("Something happened...");
}
}
```

## Customizing event bus configuration

To further customize the event bus, implement the `EventBusConfigurer` interface on one of your configuration classes.
It defines a single method, `configureEventBus`, which takes an `EventBusBuilder` that can be used to fine-tune
event bus configuration.

```java
@Configuration
public class MyEventBusConfig implements EventBusConfigurer {

@Override
public void configureEventBus(EventBusBuilder eventBusBuilder) {
eventBusBuilder.setMessageStore(eventBusMessageStore());
}
}
```

If there are multiple `EventBusConfigurer`s in the application context, the ordering according to Spring's `Ordered`
interface or `@Order` annotation is taken into account. The configurer with the highest precedence is executed _last_
(so it may overwrite the changes made by other configurers). Two configurers with the same order value will be called
in unspecified order.


### Configuring the event message store

By default, an implementation of `SimpleMessageStore` will be used for the event message queue. When asynchronous
subscribers are used, it is advisable to provide a persistent `ChannelMessageStore` instead, so that events will not
get lost between publication and consumption.

You can do so by calling `setMessageStore` on the builder passed to the `configureEventBus` method:

```java
@Configuration
public class EventMessageStoreConfig implements EventBusConfigurer {

@Autowired
private DataSource dataSource;


@Bean
public ChannelMessageStore eventBusMessageStore() {
return new JdbcChannelMessageStore(dataSource);
}

@Override
public void configureEventBus(EventBusBuilder eventBusBuilder) {
eventBusBuilder.setMessageStore(eventBusMessageStore());
}
}
```

### Configuring the event queue poller

The message queue for asynchronous subscribers requires a polling on the subscribers' end. If no custom poller is
specified, the event bus uses a poller with a short _fixed rate_ (100 milliseconds), a very long _receive timeout_
(30 seconds) and the default `TaskExecutor` (see
[Polling Consumer](http://docs.spring.io/spring-integration/reference/html/messaging-endpoints-chapter.html#endpoint-pollingconsumer)
in the Spring Integration docs).

In addition, if a `PlatformTransactionManager` bean is present in the application context, it will automatically be used
to make the poller transactional.

To customize the polling behavior, call `setEventPoller` on the builder passed to the `configureEventBus` method:

```java
@Configuration
public class EventMessageStoreConfig implements EventBusConfigurer {

@Bean
public TaskExecutor eventPollingTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// ... configure the task executor ...
return executor;
}

@Override
public void configureEventBus(EventBusBuilder eventBusBuilder) {
eventBusBuilder.setEventPoller(
Pollers.fixedRate(100)
.receiveTimeout(30000)
.taskExecutor(eventPollingTaskExecutor()));
}
}
```

### Configuring the event queue poller using Spring Boot application properties

When using Spring Boot auto-configuration, the following properties may be added to your `application.properties`
to configure the event queue poller:

- `eventbus.poller.fixed-delay`: use a _fixed delay_ poller with the specified value as the delay in milliseconds;
- `eventbus.poller.fixed-rate`: use a _fixed rate_ poller with the specified value as the rate in milliseconds;
- `eventbus.poller.cron`: use a _cron_ poller with the specified value as the cron expression.

These properties are all mutually exclusive, and only one of them should be used.
158 changes: 158 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
buildscript {
repositories { jcenter() }
dependencies {
classpath 'com.netflix.nebula:gradle-extra-configurations-plugin:1.12.+'
}
}

plugins {
id 'java'
id 'groovy'
id 'maven'
id 'maven-publish'
id 'signing'
id 'com.jfrog.bintray' version '1.0'
}

apply plugin: 'optional-base'


sourceCompatibility = 1.8
targetCompatibility = 1.8


repositories {
jcenter()
}


dependencies {

compile 'org.springframework:spring-context:4.+'
compile 'org.springframework:spring-messaging:4.+'
compile 'org.springframework.integration:spring-integration-core:4.1.+'
compile 'org.springframework.integration:spring-integration-java-dsl:1.+'

compile 'org.slf4j:slf4j-api:1.7.+'
compile 'com.google.guava:guava:18.0'

compile 'org.springframework.boot:spring-boot:1.2.2.RELEASE', optional
compile 'org.springframework.boot:spring-boot-autoconfigure:1.2.2.RELEASE', optional

testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
testCompile 'org.spockframework:spock-spring:1.0-groovy-2.4'
testCompile 'org.mockito:mockito-all:1.10.8'
testCompile ('com.cyrusinnovation:mockito-groovy-support:1.3') {
exclude group: 'org.mockito'
}

testCompile 'org.springframework:spring-test:4.+'

testCompile 'org.slf4j:jcl-over-slf4j:1.7.+'
testRuntime 'org.apache.logging.log4j:log4j-core:2.2'
testRuntime 'org.apache.logging.log4j:log4j-slf4j-impl:2.2'
testRuntime 'cglib:cglib-nodep:3.1'
}


def pomDefinition = pom {
project {
name project.friendly_name
packaging 'jar'
description project.description
url project.home_url

scm {
connection "scm:git:${project.scm_url}"
developerConnection "scm:git:${project.scm_url}"
url project.scm_url
}

licenses {
license {
name = project.license_name
url project.license_url
}
}

developers {
developer {
name 'Till Krullmann'
email '[email protected]'
}
}
}
}


task generatePom {
outputs.file "$buildDir/poms/pom.xml"
doLast {
pomDefinition.writeTo "$buildDir/poms/pom.xml"
}
}


jar {
into("META-INF/maven/$project.group/$project.name") {
from generatePom
}
}


task javadocJar(type: Jar) {
description = 'Assembles a jar archive containing the javadocs.'
classifier = 'javadoc'
from javadoc
}


task sourcesJar(type: Jar) {
description = 'Assembles a jar archive containing the sources.'
classifier = 'sources'
from sourceSets.main.allSource
}



artifacts {
archives javadocJar, sourcesJar
}


signing {
sign configurations.archives
}


install {
repositories.mavenInstaller {
beforeDeployment { deployment -> signing.signPom(deployment) }

pom = pomDefinition
}
}


bintray {
user = bintray_user
key = bintray_key
configurations = ['archives']

pkg {
repo = project.bintray_repo
name = project.name
desc = project.description
websiteUrl = project.home_url
licenses = ['MIT']
labels = ['events', 'eventbus', 'spring-integration']

vcsUrl = project.scm_url
issueTrackerUrl = project.issues_url
publicDownloadNumbers = true

version {
vcsTag = project.version
}
}
}
Loading

0 comments on commit e9d9cfa

Please sign in to comment.