Springboot Mongo db methods doesnt rollback transactions - spring-boot

Hi i am using 2 mongo template in my codebase
and my code saves data in mongo db using both mongo template and Spring repository class.save() .In methods which has #Transactional doesnt rollback DB changes even if some error occurs in code execution.
Below is the snippet of my mongoconfig configurations
#Configuration
#EnableMongoAuditing
#EnableMongoRepositories
public class MongoConfig extends AbstractMongoClientConfiguration {
#Value("${common.db.name}")
private String dbName;
#Value("${SPRING_DATA_MONGODB_URI}")
private String dbUrl;
public String getDbName() {
return dbName;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
#Override
protected String getDatabaseName() {
return dbName;
}
/**
* Below bean is created as we want to make our code transactional.
* #param dbFactory
* #return
*/
#Bean(name="primaryTransactionManager")
MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
MongoTransactionManager transactionManager = new MongoTransactionManager(dbFactory);
transactionManager.setRollbackOnCommitFailure(true);
return transactionManager;
}
#Override
public MongoClient mongoClient() {
ConnectionString connectionString = new ConnectionString(dbUrl);
MongoClientSettings mongoClientSettings = MongoClientSettings.builder().applyConnectionString(connectionString).build();
return MongoClients.create(mongoClientSettings);
}
#Bean(name="primaryMongoTemplate")
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoClient(), getDbName());
}
}
#Configuration
#EnableMongoRepositories
public class SecondaryMongoConfig {
#Value("${common.secondary.db.name}")
private String dbName;
#Value("${COMMON_SECONDARY_SPRING_DATA_MONGODB_URI}")
private String mongoDBURI;
public String getMongoDBURI() {
return mongoDBURI;
}
public void setMongoDBURI(String mongoDBURI) {
this.mongoDBURI = mongoDBURI;
}
public String getDbName() {
return dbName;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
/**
* Below bean is created as we want to make our code transactional.
* #param dbFactory
* #return
*/
#Bean(name="secondaryTransactionManager")
MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
MongoTransactionManager transactionManager = new MongoTransactionManager(dbFactory);
transactionManager.setRollbackOnCommitFailure(true);
return new MongoTransactionManager(dbFactory);
}
#Bean(name="secondaryMongoClient")
public MongoClient secondaryMongoClient() {
ConnectionString connectionString = new ConnectionString(getMongoDBURI());
MongoClientSettings mongoClientSettings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.build();
return MongoClients.create(mongoClientSettings);
}
#Bean(name="secondaryMongoTemplate")
public MongoTemplate secondaryMongoTemplate() {
return new MongoTemplate(secondaryMongoClient(), getDbName());
}
}
Below is my sample code snippet of method annoted with #Transactional
#Override
#Transactional(transactionManager = "primaryTransactionManager",rollbackFor = {Exception.class})
public String addNewRecipe() throws Exception{
RecipesDAO recipesDao = new RecipesDAO();
recipesDao.setResourceId(UUID.randomUUID().toString());
recipeRepository.save(recipesDao);
throw new Exception();
// return "dummy";
}

I got solution after checking each and every method of classes used in my class MongoConfig.java.Below is the snippet of code which i had to use in order to rollback transactions when exceptions occured in code execution flow
#Bean(name="primaryMongoTemplate")
public MongoTemplate mongoTemplate() {
MongoTemplate primaryMongoTemplate = new MongoTemplate(mongoClient(), getDbName());
primaryMongoTemplate.setSessionSynchronization(SessionSynchronization.ALWAYS);
return primaryMongoTemplate;
}
#Bean(name="secondaryMongoTemplate")
public MongoTemplate secondaryMongoTemplate() {
MongoTemplate secondaryMongoTemplate = new MongoTemplate(secondaryMongoClient(), getDbName());
secondaryMongoTemplate.setSessionSynchronization(SessionSynchronization.ALWAYS);
return secondaryMongoTemplate;
}
Earlier wherever code of creating new or modifying mongodb docs was there like say somerepository.save(s) code used to create or modify documents immedialtely but by adding primaryMongoTemplate.setSessionSynchronization(SessionSynchronization.ALWAYS); and secondaryMongoTemplate.setSessionSynchronization(SessionSynchronization.ALWAYS);
code waits for complete execution flow and checks if any exception occured in this execution flow.It creates or modifies documents only after checking no exception occured in execution flow.

Related

Set Spring SolrDocument Collection name based on PropertyValue

I want to set values Spring SolrDocument Collection based on application.yml value.
#Data
#SolrDocument(collection = #Value("${solr.core}"))
public class SearchableProduct {
}
Hoi Michela,
Ok, I had the same Problem and I found a solution: SpEL
it is described in details here:Spring Data for Apache Solr
you have to add the EL-expression to the Annotation
#SolrDocument(collection = "#{#serverSolrContext.getCollectionName()}")
public class SOLREntity implements Serializable {
.....
}
you have to provide a the serverSolrContext Bean with the method getCollectionName().
#Value("${solr.core}")
private String core;
public String getCollectionName() {
return core;
}
you have to write in our application.properties the following core entry.
solr.core=myOwnCoreName
That's it actually, BUT
if you get the following Exception, so as I did:
org.springframework.expression.spel.SpelEvaluationException: EL1057E: No bean resolver registered in the context to resolve access to bean
You have to have the following in your Configuration Bean
#Configuration
#EnableSolrRepositories(basePackages = { "de.solr.db" })
#Profile("default")
#PropertySource("classpath:application.properties")
public class ServerSolrContext extends AbstractSolrConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ServerSolrContext.class);
#Resource
private Environment environment;
#Value("${solr.core}")
private String core;
public String getCollectionName() {
return core;
}
#PostConstruct
public void init() {
System.out.println(core);
}
#Bean
public SolrClient solrClient() {
String url = environment.getProperty("solr.server.url");
String user = environment.getProperty("solr.server.user");
String password = environment.getProperty("solr.server.password");
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials(user, password));
SSLContext sslContext = null;
try {
sslContext = ReportConfiguration.getTrustAllContext();
}
catch (KeyManagementException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
HttpClient httpClient = HttpClientBuilder.create().setSSLSocketFactory(sslSocketFactory)
.addInterceptorFirst(new PreemptiveAuthInterceptor()).setDefaultCredentialsProvider(credentialsProvider)
.build();
SolrClient client = new HttpSolrClient.Builder().withHttpClient(httpClient).withBaseSolrUrl(url).build();
return client;
}
#Bean
#ConditionalOnMissingBean(name = "solrTemplate")
public SolrTemplate solrTemplate(#Qualifier("mySolrTemplate") SolrTemplate solrTemplate) {
return solrTemplate;
}
#Bean("mySolrTemplate")
public SolrTemplate mySolrTemplate(SolrClient solrClient, SolrConverter solrConverter) {
return new SolrTemplate(new HttpSolrClientFactory(solrClient), solrConverter);
}
#Override
public SolrClientFactory solrClientFactory() {
return new HttpSolrClientFactory(solrClient());
}
}
The last 3 Methods are doing the Trick, that cost me a while to find the right solution:
it is here, so actually I was lucky to find this:
Allow PropertyPlaceholders in #SolrDocument solrCoreName

The FlatFileItemReader read only one line from the CSV file - Spring Batch

I'm creating a Spring Batch Job to populate Data into a Database table from a given CSV file.
I created a customized FlatFileItemReader.
my problem is that the read() method is invoked only one time so only the first line of my CSV file is inserted into the database.
#Configuration
#EnableBatchProcessing
public class SpringBatchConfig {
private MultipartFile[] files;
#Bean
public Job job(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory,
ItemReader<MyModelEntity> itemReader,
ItemWriter<MyModelEntity> itemWriter) {
Step step = stepBuilderFactory.get("Load-CSV-file_STP")
.<MyModelEntity, MyModelEntity > chunk(12)
.reader(itemReader)
.writer(itemWriter).build();
return jobBuilderFactory.get("Load-CSV-Files").
incrementer(new RunIdIncrementer()) /
.start(step)
.build();
}
#Bean
ItemReader<MyModelEntity> myModelCsvReader() throws Exception {
return new MyModelCsvReader();
}
}
the myModelCsvReader
#Component
#StepScope
public class MyModelCsvReader implements ItemReader<MyModelEntity>{
#Value("#{jobParameters['SDH']}")
private String sdhPath;
private boolean batchJobState= false;
#Autowired
MyModelFieldSetMapper myModelFieldSetMapper;
public LineMapper<MyModelEntity> lineMapper() throws Exception {
DefaultLineMapper<MyModelEntity> defaultLineMapper = new
DefaultLineMapper<MyModelEntity>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setDelimiter(",");
lineTokenizer.setStrict(false);
lineTokenizer.setNames(new String[]
{
"clientId","ddId","institName","progName",
"qual","startDate","endDate","eType", "country","comments"
});
defaultLineMapper.setLineTokenizer(lineTokenizer);
defaultLineMapper.setFieldSetMapper(myModelFieldSetMapper);
return defaultLineMapper;}
#Override
public MyModelEntity read()
throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
//if(!batchJobState )
{
FlatFileItemReader<MyModelEntity> flatFileItemReader = new
FlatFileItemReader<MyModelEntity>();
flatFileItemReader.setMaxItemCount(2000);
flatFileItemReader.setResource(new UrlResource("file:\\"+sdhPath));
flatFileItemReader.setName("CSV-Reader");
flatFileItemReader.setLinesToSkip(1);
flatFileItemReader.setLineMapper(lineMapper());
flatFileItemReader.open(new ExecutionContext());
batchJobState=true;
return flatFileItemReader.read();
}
// return null;
}
}
the FieldSetMapper Implementation
#Component
public class MyModelFieldSetMapper implements FieldSetMapper<MyModelEntity> {
//private SiteService siteService =BeanUtil.getBean(SiteServiceImpl.class);
#Autowired
private SiteService siteService;
#Override
public MyModelEntity mapFieldSet(FieldSet fieldSet ) throws BindException {
if(fieldSet == null){
return null;
}
MyModelEntity educationHistory = new MyModelEntity();
// setting MyModelAttributes Values
return myModel;
}
}
any conribution is welcomed . thanks
// thereader after extending FlatFileItemReader
#Component
#StepScope
public class CustomUserItemReader extends FlatFileItemReader<User> {
#Value("#{jobParameters['UserCSVPath']}")
private String UserCSVPath;
private boolean batchJobState;
public CustomUserItemReader() throws Exception {
super();
setResource(new UrlResource("file:\\"+UserCSVPath));
setLineMapper(lineMapper());
afterPropertiesSet();
setStrict(false);
}
public LineMapper<User> lineMapper() throws Exception {
DefaultLineMapper<User> defaultLineMapper =
new DefaultLineMapper<User>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setDelimiter(",");
lineTokenizer.setStrict(false);
lineTokenizer.setNames(new String[]{"name", "dept",
"salary","endDate"});
defaultLineMapper.setLineTokenizer(lineTokenizer);
defaultLineMapper.setFieldSetMapper(new CustomUserFieldSetMapper());
//defaultLineMapper.setFieldSetMapper(fieldSetMapper);
return defaultLineMapper;}
#Override
public User read()
throws Exception, UnexpectedInputException, ParseException,
NonTransientResourceException {
//if(!batchJobState )
{
flatFileItemReader).size())
// flatFileItemReader.setMaxItemCount(2000);
this.setResource(new UrlResource("file:\\"+UserCSVPath));
this.setName("CSV-Reader");
this.setLinesToSkip(1);
//flatFileItemReader.setLineMapper(lineMapper());
this.open(new ExecutionContext());
User e = this.read();
batchJobState = true;
return e ;
}
// return null;
}
public
String getUserCSVPath() {
return UserCSVPath;
}
public
void setUserCSVPath(String userCSVPath) {
UserCSVPath = userCSVPath;
}
}
Thanks for all your suggestions, even if i have implemented ItemReader<>. I fixed the problem by moving the instantiation of the FlatFileItemReader Out from the read() method.
that was creating a new FlatFileItemReader in each loop and reading only the first line for each object created .
thanks

Spring Boot: Testing custom MongoTemplate converters

I'm using this custom converters into my Spring Boot service:
#Configuration
public class MongoConfig {
#Bean
public MongoCustomConversions customConversions(){
List<Converter<?,?>> converters = new ArrayList<>();
converters.add(ReferenceWriterConverter.INSTANCE);
return new MongoCustomConversions(converters);
}
#WritingConverter
enum ReferenceWriterConverter implements Converter<Reference, DBObject> {
INSTANCE;
#Override
public String convert(Reference reference) {
//do stuff
}
}
}
Into my controllers, I'm using MontoTemplate in order to talk with MongoDB. So, all converters are already loaded into template.
However, I'd like to test MongoDbTemplate using Spring injection features. I mean, I want to test MongoDbTemplate using custom converters which should already be loaded.
Any ideas on how it can be achieved?
EDIT
public class ModelTest {
private List<Reference> references;
public ModelTest() {
this.references = new ArrayList<Reference>();
}
#Before
public void setUp() {
Reference reference = new Reference();
reference.setId("Ref1");
reference.setTimestamp(new Date());
Metadata met = new Metadata();
met.setId("Mdt1");
met.setUser("user");
met.setCreationTimestamp(new Date());
met.setMetadata("[{'departament': 'JUST'}]");
reference.setMetadata(met);
this.references.add(reference);
ServerAddress serverAddress = new ServerAddress("127.0.0.1", 27017);
MongoClient mongoClient = new MongoClient(serverAddress);
MongoTemplate mongoTemplate = new MongoTemplate(mongoClient, "db");
mongoTemplate.insert(reference);
}
/**
* Assert Office mime type documents.
*/
#Test
public void office() {
fail("Not yet implemented");
}
}
EDIT 2
I also would like to use custom testing properties. I mean, currently, we are setting properties into src/test/resources/application.properties.
spring.data.mongodb.host: localhost
spring.data.mongodb.port: 27017
How could I load these file properties?
Solution 1
If you want to test it with the Spring context, you can annotate your Test class as SpringBootTest and autowire the MongoTemplate. This should then contain your custom conversions for you to test them:
#RunWith(SpringRunner.class)
#SpringBootTest
public class ModelTest {
private List<Reference> references;
#Autowired
private final MongoTemplate mongoTemplate;
public ModelTest() {
this.references = new ArrayList<Reference>();
}
#Before
public void setUp() {
Reference reference = new Reference();
reference.setId("Ref1");
reference.setTimestamp(new Date());
Metadata met = new Metadata();
met.setId("Mdt1");
met.setUser("user");
met.setCreationTimestamp(new Date());
met.setMetadata("[{'departament': 'JUST'}]");
reference.setMetadata(met);
this.references.add(reference);
mongoTemplate.insert(reference);
}
/**
* Assert Office mime type documents.
*/
#Test
public void office() {
fail("Not yet implemented");
}
}
Solution 2
If you just want to test the converter alone, you could make a ReferenceWriterConverterTest like so:
public class ReferenceWriterConverterTest {
private ReferenceWriterConverter converter;
#Before
public void setUp() {
converter = ReferenceWriterConverter.INSTANCE;
}
//test stuff
}

Spring Boot multiple MongoDB configuration

I have looked everywhere for this and it seems like I cannot find a solution that works. I am using spring boot 1.5.10-RELEASE. I am trying to configure two different mongodb instances in the same application. Here is my code:
Main Application:
#SpringBootApplication(exclude = {MongoAutoConfiguration.class})
#ComponentScan("com.reef.reports")
public class MainApplication
{
public static void main(String[] args)
{
SpringApplication.run(MainApplication.class, args);
}
}
1st Instance
#Configuration
#EnableMongoRepositories(basePackages = {"com.reef.repository.mongousa"} , mongoTemplateRef = "USAMongo")
public class MongoUsaConfig
{
#Value("${usa.mongodb.host}")
private String host;
#Value("${usa.mongodb.database:reef}")
private String database;
#Value("${usa.mongodb.port:27017}")
private int port;
#Value("${usa.mongodb.username:}")
private String username;
#Value("${usa.mongodb.password:}")
private String password;
#Value("${usa.mongodb.authdb:}")
private String authdb;
private final List<MongoCredential> credentials = new ArrayList<>();
private final List<ServerAddress> hosts = new ArrayList<>();
/**
* Method that creates MongoDbFactory
* Common to both of the MongoDb connections
*/
public MongoDbFactory mongoDbFactory()
{
return new SimpleMongoDbFactory(getMongoClient(), database);
}
/**
* Method that creates MongoClient
*/
#Bean(name = "USAClient")
public MongoClient getMongoClient()
{
if ((null != username)&&(!username.isEmpty()))
{
hosts.add(new ServerAddress(host, port));
credentials.add(MongoCredential.createMongoCRCredential(username, authdb, password.toCharArray()));
return new MongoClient(hosts, credentials);
}
else
{
return new MongoClient(host, port);
}
}
#Primary
#Bean(name = "USAMongo")
public MongoTemplate getMongoTemplate()
{
return new MongoTemplate(mongoDbFactory());
}
}
2nd Instance
#Configuration
#EnableMongoRepositories(basePackages = {"com.reef.repository.mongocan"} , mongoTemplateRef = "CANMongo")
public class MongoCanConfig
{
#Value("${can.mongodb.host}")
private String host;
#Value("${can.mongodb.database:reef}")
private String database;
#Value("${can.mongodb.port:27017}")
private int port;
#Value("${can.mongodb.username:}")
private String username;
#Value("${can.mongodb.password:}")
private String password;
#Value("${can.mongodb.authdb:}")
private String authdb;
private final List<MongoCredential> credentials = new ArrayList<>();
private final List<ServerAddress> hosts = new ArrayList<>();
/**
* Method that creates MongoDbFactory
* Common to both of the MongoDb connections
*/
public MongoDbFactory mongoDbFactory()
{
return new SimpleMongoDbFactory(getMongoClient(), database);
}
/**
* Method that creates MongoClient
*/
#Bean(name = "CANClient")
public MongoClient getMongoClient()
{
if ((null != username)&&(!username.isEmpty()))
{
hosts.add(new ServerAddress(host, port));
credentials.add(MongoCredential.createMongoCRCredential(username, authdb, password.toCharArray()));
return new MongoClient(hosts, credentials);
}
else
{
return new MongoClient(host, port);
}
}
#Bean(name = "CANMongo")
public MongoTemplate getMongoTemplate()
{
return new MongoTemplate(mongoDbFactory());
}
}
When I run the application, it will run the configuration for the first instance. However, it will not pick up the second instance. I have put in breakpoints to debug and it never hits the breakpoint in the configuration. The repositories in this package get loaded correctly:
com.reef.repository.mongousa
The errors happen with the repositories in this package:
com.reef.repository.mongocan
Please let me know what I am missing. Why does one config work and the other does not?
Refer to this blog post https://medium.com/#joeclever/using-multiple-datasources-with-spring-boot-and-spring-data-6430b00c02e7
I tried it out for two MySQL DataBases and it is working fine.

Implementing Snapshot in AXON 3.0 : Aggregate Type is unknown in this snapShotter

I'm still new to the axon frame work.
I'm trying to implement snapshotting using mongodb in my application and I keep on getting an error saying
"AbstractSnapshotter : An attempt to create and store a snapshot resulted in an exception. Exception summary: Aggregate Type is unknown in this snapshotter: com.myworklife.contacts.domain.contact.Contact"
This is a part of my java config file.
#Bean
public AggregateSnapshotter snapShotter(EventStore eventStore, AggregateFactory<Contact> contactAggregateFactory) {
return new AggregateSnapshotter(eventStore);
}
#Bean
public SnapshotTriggerDefinition snapshotTriggerDefinition(Snapshotter snapShotter) throws Exception {
return new EventCountSnapshotTriggerDefinition(snapShotter, 1);
}
#Bean
public EventStore eventStore(EventStorageEngine eventStorageEngine) {
return new EmbeddedEventStore(eventStorageEngine);
}
#Bean
public Repository<Contact> contactAggregateRepository(EventStore eventStore, SnapshotTriggerDefinition snapshotTriggerDefinition) {
return new ContactRepository(eventStore, snapshotTriggerDefinition);
}
And my repository.
#Repository("ContactRepository")
public class ContactRepository extends EventSourcingRepository<Contact> {
#Autowired
public ContactRepository(EventStore eventStore, SnapshotTriggerDefinition snapshotTriggerDefinition) {
super(Contact.class, eventStore, snapshotTriggerDefinition);
}
public Contact findContact(ContactId contactId) {
return load(contactId.toString()).getWrappedAggregate().getAggregateRoot();
}
}
My aggregate.
#Aggregate(repository="contactAggregateRepository")
public class Contact {
#AggregateIdentifier
private ContactId id;
private String name;
private String mobileNumber;
public Contact() {
// do nothing, Axon requires default constructor
}
#CommandHandler
public Contact(CreateContactCommand createContactCommand) {
apply(new ContactHasBeenCreatedEvent(createContactCommand.getContactId(), createContactCommand.getName(),
createContactCommand.getMobileNumber()));
}
}
Is there something I'm doing wrong?
since I'm getting an error saying "An attempt to create and store a snapshot resulted in an exception. Exception summary: Aggregate Type is unknown in this snapshotter: com.myworklife.contacts.domain.contact.Contact"
Any help will be highly appreciated.
Thanks,
Pat
You need to add the contactAggregateFactory to the constructor of the AggregateSnapshotter in the snapShotter bean:
#Bean
public AggregateSnapshotter snapShotter(EventStore eventStore, AggregateFactory<Contact> contactAggregateFactory) {
return new AggregateSnapshotter(eventStore, contactAggregateFactory);
}
1.depencity jar
<dependency>
<groupId>org.axonframework</groupId>
<artifactId>axon-spring-boot-autoconfigure</artifactId>
<version>${axon.version}</version>
</dependency>
2.At first,you should config your application.ymp or bootstrap.yml,like this:spring:
data:
mongodb:
host: localhost
port: 27017
database: axonframework
events: domainevents
snapshots: snapshotevents
3.config your mongoDB:
#Bean(name = "axonMongoTemplate")
public MongoTemplate axonMongoTemplate() {
MongoTemplate template = new DefaultMongoTemplate(mongoClient(), mongoDbName, eventsCollectionName, snapshotCollectionName);
return template;
}
#Bean
public MongoClient mongoClient(){
MongoFactory mongoFactory = new MongoFactory();
mongoFactory.setMongoAddresses(Arrays.asList(new ServerAddress(mongoHost)));
return mongoFactory.createMongo();
}
#Bean
public EventStorageEngine eventStorageEngine(Serializer serializer){
return new MongoEventStorageEngine(
serializer,null, axonMongoTemplate(), new DocumentPerEventStorageStrategy());
4.config repository for your aggregate,for example,i config a Element Aggreaget's repository
#Configuration
public class ElementConfiguration {
#Autowired
private EventStore eventStore;
#Bean
#Scope("prototype")
public Element elementAggregate() {
return new Element();
}
#Bean
public AggregateFactory<Element> elementAggregateAggregateFactory() {
SpringPrototypeAggregateFactory<Element> aggregateFactory = new SpringPrototypeAggregateFactory<>();
aggregateFactory.setPrototypeBeanName("elementAggregate");
return aggregateFactory;
}
#Bean
public SpringAggregateSnapshotterFactoryBean springAggregateSnapshotterFactoryBean(){
SpringAggregateSnapshotterFactoryBean factory = new SpringAggregateSnapshotterFactoryBean();
return factory;
}
#Bean
public Repository<Element> elementAggregateRepository(Snapshotter snapshotter) {
EventCountSnapshotTriggerDefinition eventCountSnapshotTriggerDefinition = new EventCountSnapshotTriggerDefinition(snapshotter, 3);
EventSourcingRepository<Element> repository = new EventSourcingRepository<Element>(
elementAggregateAggregateFactory(),
eventStore,
eventCountSnapshotTriggerDefinition
);
return repository;
}
5.enjoy
If you're using Axon 3.3 and SpringBoot 2, this is how we did it in this project:
#Configuration
public class SnapshotConfiguration {
#Bean
public SpringAggregateSnapshotter snapshotter(ParameterResolverFactory parameterResolverFactory,
EventStore eventStore,
TransactionManager transactionManager) {
// https://docs.axoniq.io/reference-guide/v/3.3/part-iii-infrastructure-components/repository-and-event-store#snapshotting
// (...) By default, snapshots are created in the thread that calls the scheduleSnapshot() method, which is generally not recommended for production (...)
Executor executor = Executors.newSingleThreadExecutor();
return new SpringAggregateSnapshotter(eventStore, parameterResolverFactory, executor, transactionManager);
}
#Bean
public EventCountSnapshotTriggerDefinition snapshotTrigger(SpringAggregateSnapshotter snapshotter) {
int snapshotThreshold = 42;
return new EventCountSnapshotTriggerDefinition(snapshotter, snapshotThreshold);
}
}
And if you need the EventStore configuration:
#Configuration
public class AxonMongoEventStoreConfiguration {
#Bean
public MongoClient axonMongoClient(MongoClientURI axonMongoClientUri) {
return new MongoClient(axonMongoClientUri);
}
#Bean
public MongoClientURI axonMongoClientUri() {
return new MongoClientURI("mongodb://host:port/database");
}
#Bean
#Primary
public EventStorageEngine eventStore(MongoClient axonMongoClient, MongoClientURI axonMongoClientUri) {
DefaultMongoTemplate mongoTemplate = new DefaultMongoTemplate(axonMongoClient, axonMongoClientUri.getDatabase());
return new MongoEventStorageEngine(mongoTemplate);
}
}

Resources