Um Arquitetura EDA parte 1: Esper e Spring

No ultimo post fiz uma breve introdução de uma séria de coisas como CEP, EDA e BAM. A idéia é que em mais 4 posts eu venha a publicar aqui uma arquitetura EDA completa. Essa arquitetura seria uma possibilidade de uso de várias tecnologias e soluções para alcançarmos uma arquitetura EDA.

Meu foco será mostrar como as tecnologias funcionam e como elas podem ser integradas com o mínimo de esforço e desenvolvimento. Gostaria que todos se sentissem a vontade para perguntar e/ou melhorar a solução de arquitetura.

Então vamos começar com o Esper, neste post vou falar um pouco mais sobre o Esper que é uma implementação de Engine de CEP tanto para Java como para .NET. Meu foco aqui é Java é claro :)

O Framework Esper

O Esper é uma engine de CEP escrita em Java que é muito poderoso e escalável! Como um pouquinho de esforço vou mostrar como podemos integrar o Esper com o Spring Framework e assim ganharmos mais flexibilidade e produtividade.



Nota: O Spring é carro chefe da arquitetura pois vamos utiliza-lo tanto para o com o Esper como para o ESB(ServiceMix) que é baseado em Spring, assim vamos aproveitar o modelo mental de você e uma vez se conhecendo Spring a curva de aprendizado é menor. Sem falar nas facilidades como por exemplo: Backing Beans, Transações declarativas, Arvore de Exceptions, Integração com outros frameworks, ciclo de vida e muito mais muito mais que o Spring nos oferece!

Caso você tenha interesse em se aprofundar no Spring pode conferir mais sobre o framework em alguns desses meus posts a baixo:
Voltando ao Esper...

A grande vantagem do Esper é a capacidade de processar grandes volumes de eventos(isso ajuda a deixar a solução escalável) . O Esper funciona como se fosse um banco de dados de cabeça para baixo. Em uma solução de banco de dados você armazena os dados e faz as queries na horas, com o Esper é o contrário, ou seja, você armazena as queries e os dados você *pega* na hora!

O Esper prove uma linguagem de consulta sobre os eventos. Essa linguagem, é o EQL que é uma DSL do tipo *SQL-Like*. A linguagem de consulta do esper conta com diversos recursos como funções de agregação, projeções, joins e funções. Outros coisa que o esper prove que é fundamental nesse tipo de solução é a query temporal. Você pode dizer que algo acontece 5mim depois de um eventos ou depois de um query realizada.

Por exemplo esse EQL a baixo:
StockTickEvent.win:ext_timed(10, 'timestamp')

Essa queries a cima do Esper faria que selecionaremos os eventos do tipo *StockTickEvent* dos últimos 10 segundos em relação a propriedade *timestamp*. Para uma referencia completa a EQL do Esper confiram a documentação aqui!

Esper Básico

Antes de entrarmos na arquitetura e a junção do Esper com o Spring vamos ver um exemplo fácil de como o Esper funciona, confira isso no código a baixo:
package com.blogspot.diegopacheco.cep.esper.samples;

import com.blogspot.diegopacheco.cep.esper.event.model.VendaRequest;
import com.espertech.esper.client.Configuration;
import com.espertech.esper.client.EPServiceProvider;
import com.espertech.esper.client.EPServiceProviderManager;
import com.espertech.esper.client.EPStatement;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.UpdateListener;

/**
* Classe que mostra o funcionamento do Esper de maneira mais simples possível.
*
* @author Diego Pacheco
* @since 26/02/2009
* @version 1.0
*
*/
public class EsperSimpleEasyWay {

public static void main(String[] args) throws Throwable {

// Configura e levanta a engine do esper.
// perceba que aqui todos os eventos seram automaticamente
// importados do pacote com.blogspot.diegopacheco.cep.esper.event.model
// O Service eh criado a partir da configuracao. 
Configuration config = new Configuration();
config.addEventTypeAutoName("com.blogspot.diegopacheco.cep.esper.event.model");
EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider(config);

// Aqui estamos criando um query.
EPStatement vendaStatement = epService.getEPAdministrator().createEPL("select * from VendaRequest");

// Adiciono o código de tratamento a essa query.
vendaStatement.addListener(new UpdateListener(){           
@Override
public void update(EventBean[] arg0, EventBean[] arg1) {

// Verifico se o resulta é da query que eu espero.
if (arg0[0]!=null &&  VendaRequest.class.getSimpleName().equals(arg0[0].getEventType().getName()) ){
System.out.println("Aconreceu o evento: " + arg0[0].get("clienteId") + ", " + arg0[0].get("produtoId") );
}               
}
});       

// Uma paradinha soh para dar tempo do esper subir a engine.
Thread.sleep(3L);

// Aqui estamos criando um objeto de enveto
// Estamos adicionado esse evetno ao esper
// Estamos simulando a geracvao de um evento
VendaRequest vreEvent = new VendaRequest( new Integer((int)(Math.random() * 10)).toString()  , new Integer((int)(Math.random() * 10)).toString(), System.currentTimeMillis());
epService.getEPRuntime().sendEvent(vreEvent);

}

}

Como esse código podemos ver as funcionalidades básicas do Esper. Como vocês devem ter percebido o Esper é baseado em POJOS, os eventos são todos POJOS, isso facilita muito o desenvolvimento.

O Código primeiro configura o esper, criando um objeto de configurações e dizendo onde estão os pojos que representam eventos para o esper, você pode informar um a um ou pode fazer como eu fiz e indicar um pacote, ai ele pega todos os pojos desse pacote e adiciona como eventos.

Depois o service do esper é iniciado, isso seria equivalente a subir a engine ou contexto do esper. Essa engine sobe com as configurações que informei, isso possibilita subir diversas engines com configurações variadas.

Isso pode ser muito util para separar eventos externos de outras aplicações eventos internos da própria solução que venhamos a construir, quando chegarmos ao ESB vamos ver melhor esse questão das configurações.

Depois é criado um query e armazenada em um EPStatement, você pode criar quantas queries quizer, o esper processa todas e associa o resultado de cada uma a seu respectivo EPStatement, alem disso estou adicionando um UpdateListener ao meu EPStatement, esse é o call back do esper para tratamento do retorno da query. O seu código de ação ou negocio seria chamado de dentro desse call back :)

OK, uma parada básica para o café... Por que o engine pode não ter subido até o momento que o evento foi originado....

Então criei um pojo chamado VendaRequest que simboliza um pedido de venda, que é um evento esse evento é adicionado ao Esper com o código: epService.getEPRuntime().sendEvent(vreEvent)

E pronto eras isso. Ao rodar o código você vê algo do tipo:
00:08:34,554 DEBUG [MetricReportingPath] Metrics reporting has been disabled, this setting takes affect for all engine instances at engine initialization time.
00:08:34,725 DEBUG [TimerServiceImpl] .startInternalClock Starting internal clock daemon thread, resolution=100
00:08:34,831 DEBUG [EPAdministratorImpl] .createEPLStmt statementName=null eplStatement=select * from VendaRequest
00:08:34,845 DEBUG [ParseHelper] .parse Parsing expr=select * from VendaRequest
00:08:35,187 DEBUG [ParseHelper] .parse Dumping AST...
00:08:35,241 DEBUG [ParseHelper] .walk Walking AST using walker com.espertech.esper.epl.parse.EPLTreeWalker
00:08:35,241 DEBUG [EPLTreeWalker] .leaveNode *
00:08:35,241 DEBUG [EPLTreeWalker] .leaveWildcardSelect
00:08:35,242 DEBUG [EPLTreeWalker] .leaveNode SELECTION_EXPR
00:08:35,242 DEBUG [EPLTreeWalker] .leaveSelectClause
00:08:35,242 DEBUG [EPLTreeWalker] .leaveNode EVENT_FILTER_EXPR
00:08:35,242 DEBUG [EPLTreeWalker] .leaveStreamFilter
00:08:35,243 DEBUG [EPLTreeWalker] .leaveNode STREAM_EXPR
00:08:35,243 DEBUG [EPLTreeWalker] .leaveStreamExpr
00:08:35,244 DEBUG [EPLTreeWalker] .end
00:08:35,244 DEBUG [ParseHelper] .walk AST tree after walking
00:08:35,342 DEBUG [StatementResultServiceImpl] .ctor
00:08:35,343 DEBUG [EventAdapterServiceImpl] .addBeanType Adding VendaRequest for type VendaRequest
00:08:35,481 DEBUG [FilterStreamSpecRaw] .resolveType Event type name 'VendaRequest' not resolved by plug-in event representations
00:08:35,494 DEBUG [FilterSpecCompiler] .makeFilterSpec spec=FilterSpecCompiled type=BeanEventType clazz=com.blogspot.diegopacheco.cep.esper.event.model.VendaRequest parameters=[]
00:08:35,525 DEBUG [StatementLifecycleSvcImpl] .start Starting statement 54b94a21-794f-4ceb-ada2-b6f452871830 from desc=com.espertech.esper.core.StatementLifecycleSvcImpl$EPStatementDesc@18c56d
00:08:35,525 DEBUG [StatementLifecycleSvcImpl] .startInternal Starting statement 54b94a21-794f-4ceb-ada2-b6f452871830 from desc=com.espertech.esper.core.StatementLifecycleSvcImpl$EPStatementDesc@18c56d
00:08:35,527 DEBUG [StreamFactorySvcImpl] .createStream hashCode=29420695 filter=FilterSpecCompiled type=BeanEventType clazz=com.blogspot.diegopacheco.cep.esper.event.model.VendaRequest parameters=[]
00:08:35,539 DEBUG [ViewServiceHelper] .addMergeViews Incoming specifications=[]
00:08:35,539 DEBUG [ViewServiceHelper] .addMergeViews Outgoing specifications=[]
00:08:35,549 DEBUG [ResultSetProcessorFactory] .getProcessor Getting processor for  selectionList=[com.espertech.esper.epl.spec.SelectClauseElementWildcard@110003] groupByNodes=[] optionalHavingNode=null
00:08:35,558 DEBUG [OrderByProcessorFactory] .getProcessor Using no OrderByProcessor
00:08:35,561 DEBUG [SelectExprProcessorFactory] .getProcessor Using wildcard processor
00:08:35,564 DEBUG [ResultSetProcessorFactory] .getProcessor Using no result processor
00:08:35,566 DEBUG [ViewServiceImpl] .createView No new views created, dumping stream ... com.espertech.esper.view.ZeroDepthStream@79a2e7
00:08:35,570 DEBUG [OutputProcessViewDirect] .ctor
00:08:35,570 DEBUG [EPStatementStartMethod] .start Statement start completed
00:08:35,570 DEBUG [EPAdministratorImpl] .createEPLStmt Statement created and started
00:08:35,571 DEBUG [StatementLifecycleSvcImpl] .updatedListeners No action for base implementation
Aconreceu o evento: 6, 1

Muito bem agora que você viu como o esper funciona, vamos colocar isso em uma infra-estrutura de arquitetura com o Spring.

Integrando o Esper ao Spring Framework

Integrar o Esper com o Spring é tranquilo, case que natural, porem tive que desenvolver uma pequena infra-estrutura para que poçamos configurar o esper de forma totalemte declarativa utilizando injeção de dependencias, para isso tive que criar uma classe Holder uma que outra classe Helper, mas não é nada absurdo :)

Estrutura dos pacotes
  • com.blogspot.diegopacheco.cep.esper.core: Infra-Estrutura do Esper com Spring
  • com.blogspot.diegopacheco.cep.esper.event.bootstrap: Subir o Esper/Spring e iniciar a aplicação.
  • com.blogspot.diegopacheco.cep.esper.event.model: Os POJOS que representam os eventos.
  • com.blogspot.diegopacheco.cep.esper.event.model.service.es: Gerador de Eventos para o esper.
  • com.blogspot.diegopacheco.cep.esper.event.model.service.stmts: São Statements das queries e ações sobre os eventos do Esper.
  • com.blogspot.diegopacheco.cep.esper.samples: Contém exemplos simples e do Esper de modo puro.
Depêndencias de Jars
  • esper-3.0.0.jar
  • esperio-3.0.0.jar
  • commons-logging-1.1.1.jar
  • cglib-nodep-2.2.jar
  • antlr-runtime-3.1.1.jar
  • log4j-1.2.15.jar
  • spring-beans.jar
  • spring-context.jar
  • spring-core.jar
Estou utilizando o Spring 2.5.6! Mas se vocês mudarems os xmls dos beans deve funcionar com as versões antigas do Spring também, pois não uso nenheum recurso novo. OK, chega de papo, vamos aos códigos, primeiro os POJOS que representam eventos.

VendaRequest.Java
package com.blogspot.diegopacheco.cep.esper.event.model;

/**
* POJO que será transimitido através de um evento. Pode-se considerar
* que esse POJO representa um tipo de evento chamado VendaRequest.
*
* @author Diego Pacheco
* @since 25/02/2009
* @version 1.0
*
*/
public class VendaRequest {

private String produtoId;
private String clienteId;
private long timestamp;

public VendaRequest() {}   

public VendaRequest(String produtoId, String clienteId, long timestamp) {
super();
this.produtoId = produtoId;
this.clienteId = clienteId;
this.timestamp = timestamp;
}

public String getProdutoId() {
return produtoId;
}
public void setProdutoId(String produtoId) {
this.produtoId = produtoId;
}

public String getClienteId() {
return clienteId;
}
public void setClienteId(String clienteId) {
this.clienteId = clienteId;
}

public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}    

@Override
public String toString() {
return "VendaRequest|" + super.toString() + "|[produtoId: " + produtoId + ",clienteId: " + clienteId +
",timestamp: " + timestamp + "]";
}

}

VendaResponse.Java
package com.blogspot.diegopacheco.cep.esper.event.model;


/**
* POJO que será transimitido através de um evento. Pode-se considerar
* que esse POJO representa um tipo de evento chamado VendaResponse.
*
* @author Diego Pacheco
* @since 25/02/2009
* @version 1.0
*
*/
public class VendaResponse {

private VendaRequest venda;
private boolean isAchado;

public VendaResponse() {}   

public VendaResponse(VendaRequest venda,boolean isAchado) {
super();
this.venda       = venda;
this.isAchado = isAchado;
}


public VendaRequest getVenda() {
return venda;
}
public void setVenda(VendaRequest venda) {
this.venda = venda;
}

public boolean isAchado() {
return isAchado;
}
public void setAchado(boolean isAchado) {
this.isAchado = isAchado;
}

@Override
public String toString() {
return "VendaRequest|" + venda.toString() +  ",isAchado: " + isAchado + "]";
}

}

Como podem ver são dois POJOS simples, sendo que o VendaResponde é a respota de um VendaRequest e tem referencia a esse outro objeto(Evento Original). Vamos a classe que gera esses eventos.

EventSourceBean.java
package com.blogspot.diegopacheco.cep.esper.event.model.service.es;

import com.blogspot.diegopacheco.cep.esper.core.EsperServiceHolder;
import com.blogspot.diegopacheco.cep.esper.event.model.VendaRequest;
import com.blogspot.diegopacheco.cep.esper.event.model.VendaResponse;

/**
* Classe que representa uma fonte de eventos. Essa classe está gerando diversos eventos para o esper.
*
* @author Diego Pacheco
* @since 26/02/2009
* @version 1.0
*
*/
public class EventSourceBean {

private EsperServiceHolder serviceHolder;

public void startSeeding(){
// Adiciona um evento.
VendaRequest vreEvent = new VendaRequest( new Integer((int)(Math.random() * 10)).toString()  , new Integer((int)(Math.random() * 10)).toString(), System.currentTimeMillis());
serviceHolder.getService().getEPRuntime().sendEvent(vreEvent);

// Adiciona um evento.
VendaResponse vrEvent = new VendaResponse(vreEvent, true);
vrEvent.setAchado(true);       
serviceHolder.getService().getEPRuntime().sendEvent(vrEvent);   
}

public void setService(EsperServiceHolder serviceHolder) {
this.serviceHolder = serviceHolder;
}

}

Essa classe gera os eventos instanciando os POJOS de enventos e enviando eles ao esper através do código: serviceHolder.getService().getEPRuntime().sendEvent(vrEvent); Aqui o unico detalhe é que para acessar o service do Esper estou usando o EsperServiceHolder que foi uma classe que criei para manter o contexto do Esper acessivel a outros objetos.

Nota: Esse cara vai ser mudado depois quando entar o ESB(ServiceMix), ai o ESB leria de diversas fontes, protocolos, sistemas e a partir do ESB que os eventos seriam gerados.

EsperServiceHolder.java
package com.blogspot.diegopacheco.cep.esper.core;

import com.espertech.esper.client.Configuration;
import com.espertech.esper.client.EPServiceProvider;
import com.espertech.esper.client.EPServiceProviderManager;

/**
* Classe que é responsável por guardar a instancia do EPServiceProvider.
*  
* @author Diego Pacheco
* @since 26/02/2009
* @version 1.0
*
*/
public class EsperServiceHolder {

private EPServiceProvider service;
private Configuration config;

public EsperServiceHolder(Configuration config) {
this.config = config;
init();
}

private void init(){
service = EPServiceProviderManager.getDefaultProvider(config);
}

public EPServiceProvider getService() {
return service;
}   
}

Esse objeto mantem referencia ao EPServiceProvider e a Configuration, no momento que esse objeto é instanciado pelo contexto do spring ele já chama o init e sobe a engine do esper com esse objeto de configurações. Vamo a classe que sobe o Spring e Esper e roda a aplicação.

EsperEngineContextBootstrap.java
package com.blogspot.diegopacheco.cep.esper.event.bootstrap;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.blogspot.diegopacheco.cep.esper.core.EsperServiceHolder;
import com.espertech.esper.client.EPServiceProvider;

/**
* Classe que é responsável por subir o contexto do Esper e configurar a engine
* com os tipos de eventos a serem utilizados. Essa classe sobre o Contexto do Spring que por sua vez
* configura e sobe o Esper.
*
* @author Diego Pacheco
* @since 25/02/2009
* @version 1.0
*
*/
public class EsperEngineContextBootstrap {

private static ApplicationContext ac;

public static EPServiceProvider getEPServiceProvider(){
return ((EsperServiceHolder)ac.getBean("esperServiceHolder")).getService();
}

public static ApplicationContext getSpringApplicationContext(){
return ac;
}

public static void startUp(){
ac = new ClassPathXmlApplicationContext("classpath:application-context.xml");          
}

public static void shutdown(){       
((AbstractApplicationContext)ac).registerShutdownHook();
}

}

Essa classe sobe o contexto do spring pelo método startup() e deruba o contexto em um tipo de clean shutdown com o método shutdown. Ela ainda prove facilidades para recuperar o contexto do Spring e o EPServiceProvider do Esper.

ApplicationLauncher.java
package com.blogspot.diegopacheco.cep.esper.event.bootstrap;

import com.blogspot.diegopacheco.cep.esper.event.model.service.es.EventSourceBean;

/**
* Classe que roda a aplicação.
*
* @author Diego Pacheco
* @since 25/02/2009
* @version 1.0
*
*/
public class ApplicationLauncher {

public static void main(String[] args) throws Throwable {

// Inicia a engine do Esper.
EsperEngineContextBootstrap.startUp();       

// Espera um pouco para dar tempo do contexto subir.
Thread.sleep(3000L);

// Gera eventos para o Esper.
EventSourceBean esBean = (EventSourceBean)EsperEngineContextBootstrap.getSpringApplicationContext().getBean("eventSourceBean");
esBean.startSeeding();
esBean.startSeeding();
esBean.startSeeding();

}
}

Essa é a classe que serve para rodar a aplicação, isso vai morer em breve por que dentro do ESB não iria ser assim o proprio ESB que serviria como uma especie de container, mas quando o ESB entrar na jogada falamos melhor sobre isso.

Agora só falta dois pontos, os Statements e as configurações de Beans no Spring. Vamos ao mecanismo de Statements primeiro!

Toda vez que você cria um EPStatement precisa registra-lo no EPAdministrator do Esper, então fiz uma pequeno design para que isso acontecesse de forma injetável e configurável por següência.

StatementRegisterable.java
package com.blogspot.diegopacheco.cep.esper.core;

import com.espertech.esper.client.EPAdministrator;

/**
* Interface que indica que o Statement do Esoer é registrável.
* Assim você pode registar vários Statement com o StatementRegister.
* 
* @author Diego Pacheco
* @since 25/02/2009
* @version 1.0
*
*/
public interface StatementRegisterable {
public void setEPAdministrator(EPAdministrator admin);
}

Esse interface é um tipo de observer nesse solução. Um observer de registro, esntranho não ? :)
Vamos a classe genérica que registra os Statements de forma automatizada e injetável.

StatementRegister.java
package com.blogspot.diegopacheco.cep.esper.core;

import java.util.List;


/**
* Classe que registra um conjunto de StatementRegisterable no mesmo EPAdministrator de um service.
* 
* @author Diego Pacheco
* @since 25/02/2009
* @version 1.0
*
*/
public class StatementRegister {   

private EsperServiceHolder serviceHolder;

public StatementRegister(EsperServiceHolder serviceHolder){
this.serviceHolder = serviceHolder;
}

/**
* Metodo que registra o EPAdministrator para um conjunto de StatementRegisterable;
*
* @param admin instancia de EPAdministrator
* @param stmts instancia de StatementRegisterable
*/
public void registerStatements(List stmts){
for(StatementRegisterable stmt: stmts){
stmt.setEPAdministrator(serviceHolder.getService().getEPAdministrator());
}
}   
}

Esse cara tem o método *registerStatements* que é onde acontece toda a mágina, ele passa a intancia do EPAdministrator para todos os Statements para que eles possam se registrar, seria como se fosse um EPAdministratorAware. Uffa uma classe só, o Statement agora.

package com.blogspot.diegopacheco.cep.esper.event.model.service.stmts;

import com.blogspot.diegopacheco.cep.esper.core.StatementRegisterable;
import com.blogspot.diegopacheco.cep.esper.event.model.VendaResponse;
import com.espertech.esper.client.EPAdministrator;
import com.espertech.esper.client.EPStatement;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.UpdateListener;


/**
* Classe que processa o evento de vendas. Aqui adicionamos as querys sobre
* os eventos de vendas e bem como o processamento das ações em cima desses
* eventos.
*
* @author Diego Pacheco
* @since 25/02/2009
* @version 1.0
*
*/
public class VendaStatement implements StatementRegisterable{

private EPAdministrator admin;
private EPStatement vendaStatement;

public VendaStatement() {}

private void setUp(){       

// Adiciono a query.
vendaStatement = admin.createEPL("select * from VendaResponse");

// Adiciono o código de tratamento a essa query.
vendaStatement.addListener(new UpdateListener(){           
@Override
public void update(EventBean[] arg0, EventBean[] arg1) {

// Verifico se o resulta é da query que eu espero.
if (arg0[0]!=null &&  VendaResponse.class.getSimpleName().equals(arg0[0].getEventType().getName()) ){
System.out.println("Aconreceu o evento: " + arg0[0].get("clienteId") + ", " + arg0[0].get("produtoId") );
}               
}
});
}

@Override
public void setEPAdministrator(EPAdministrator admin) {
this.admin = admin;
setUp();
}

}

Essa classe implementa StatementRegisterable, também cria seu proprio Statement e associa uma query e uma call back a essa query, a query aqui é simples, pois meu propósito é mostrar a coisa toda funcionando.

Configurações agora! Primeiro vamos ao básico log4j.xml




























Nada de mais, dois loggers, spring e esper, você pode configurar o level se quizer ver mais o que está acontecnedo, mas esse nivél já é muito bom.

Existem 4 arquivos do Spring, são eles:
  • application-context.xml: Junta todos os outros 3 arquivos via import.
  • spring-esper-context-beans.xml: Beans responsáveis pelo contexto do Esper e Confs.
  • spring-esper-es-beans.xml: Beans que são fontes geradoras de eventos.
  • spring-esper-stmts-beans.xml: Beans Statements do Esper.
Vamos ao código dos 4 então. application-context.xml




   
   



spring-esper-context-beans.xml



   

           





   










       




       



Nesse arquivo está o bean de configurações do Esper e de forma declarativa injetei a execução do método que confgira os pacotes que auto transforman beans em eventos, existe também o bem que segura o service do Esper que é o esperServiceHolder.

spring-esper-es-beans.xml



   









Esse é fácil, é a declaração do bean gerador de eventos.

spring-esper-stmts-beans.xml






   



























Aqui temos 2 coisas, a declaração de todos os statements do sistema no bean stmts, e o registro automativo do EPAdministrador nesses Statemetns, isso é feito via injeção de método com o MethodInvokingTimerTaskFactoryBean do Spring.

Pronto já temos um arquitetura básica integrada entre o Esper o Spring, o próximo passo é colocar o ESB(ServiceMix) ai vamos modificar o código dos beans geradores de eventos e vamos adicionar coisas bem interessantes, mas isso é no próximo post.

Caso alguém queira pode baixar os códigos aqui. Se você gostou desse post pode ler esses outros posts relacionados ao assunto:
Até a próxima, Abraços.

Popular posts from this blog

Kafka Streams with Java 15

Rust and Java Interoperability

HMAC in Java