Configure Spring AMQP to Connect to RabbitMQ using Credential

@Configuration
public class RabbitConfiguration {

    @Bean
    public CachingConnectionFactory connectionFactory() {
        // configure to connect with credential
        ConfigFile configFile = new ConfigFile();
        CachingConnectionFactory connectionFactory =
                new CachingConnectionFactory(configFile.getRabbitmqHost());
        connectionFactory.setUsername(configFile.getRabbitmqUserName());
        connectionFactory.setPassword(configFile.getRabbitmqPassword());
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin amqpAdmin() {
        return new RabbitAdmin(connectionFactory());
    }

    @Bean
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(connectionFactory());
        return template;
    }

    @Bean
    public Queue MonitoringV5_Queue1() {
        // declare queue1
        return new Queue("MonitoringV5_Queue1");
    }

    @Bean
    public Queue MonitoringV5_Queue2() {
        // declare queue2
        return new Queue("MonitoringV5_Queue2");
    }
}

References
https://docs.spring.io/spring-amqp/docs/current/reference/html/#cachingconnectionfactory

Read a configuration file in Java

app.config

app.name=Properties Sample Code
app.version=1.09
Properties prop = new Properties();
String fileName = "app.config";
try (FileInputStream fis = new FileInputStream(fileName)) {
    prop.load(fis);
} catch (FileNotFoundException ex) {
    ... // FileNotFoundException catch is optional and can be collapsed
} catch (IOException ex) {
    ...
}
System.out.println(prop.getProperty("app.name"));
System.out.println(prop.getProperty("app.version"));

References
https://stackoverflow.com/questions/16273174/how-to-read-a-configuration-file-in-java

Logging in Spring Boot

When using starters, Logback is used for logging by default.

@RestController
public class LoggingController {

    Logger logger = LoggerFactory.getLogger(LoggingController.class);

    @RequestMapping("/")
    public String index() {
        logger.trace("A TRACE Message");
        logger.debug("A DEBUG Message");
        logger.info("An INFO Message");
        logger.warn("A WARN Message");
        logger.error("An ERROR Message");

        return "Howdy! Check out the Logs to see the output...";
    }
}

the default logging level of the Logger is preset to INFO, meaning that TRACE and DEBUG messages are not visible.

References
https://www.baeldung.com/spring-boot-logging

Controlling Bean Creation Order with @DependsOn Annotation in Spring Boot

Spring, by default, manages beans’ lifecycle and arranges their initialization order.

But, we can still customize it based on our needs. We can choose either the SmartLifeCycle interface or the @DependsOn annotation for managing initialization order.

@Configuration
@ComponentScan("com.baeldung.dependson")
public class Config {
 
    @Bean
    @DependsOn({"fileReader","fileWriter"})
    public FileProcessor fileProcessor(){
        return new FileProcessor();
    }
    
    @Bean("fileReader")
    public FileReader fileReader() {
        return new FileReader();
    }
    
    @Bean("fileWriter")
    public FileWriter fileWriter() {
        return new FileWriter();
    }   
}

Finally, there are few points which we should take care of while using @DependsOn annotation:

  • While using @DependsOn, we must use component-scanning
  • If a DependsOn-annotated class is declared via XML, DependsOn annotation metadata is ignored

DependsOnDatabaseInitialization Annotation

Indicate that a bean’s creation and initialization depends upon database initialization having completed. May be used on a bean’s class or its @Bean definition.

References
https://www.baeldung.com/spring-depends-on

Spring Bean Scopes in Dependency Injection

The scope of a bean defines the life cycle and visibility of that bean in the contexts we use it.

The latest version of the Spring framework defines 6 types of scopes:

  • singleton
  • prototype
  • request
  • session
  • application
  • websocket

The last four scopes mentioned, request, session, application and websocket, are only available in a web-aware application.

Let’s create a Person entity to exemplify the concept of scopes:

public class Person {
    private String name;

    // standard constructor, getters and setters
}

Singleton Scope

When we define a bean with the singleton scope, the container creates a single instance of that bean; all requests for that bean name will return the same object, which is cached. Any modifications to the object will be reflected in all references to the bean. This scope is the default value if no other scope is specified.

@Bean
@Scope("singleton")
public Person personSingleton() {
    return new Person();
}

We can also use a constant instead of the String value in the following manner:

@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)

Now we can proceed to write a test that shows that two objects referring to the same bean will have the same values, even if only one of them changes their state, as they are both referencing the same bean instance:

private static final String NAME = "John Smith";

@Test
public void givenSingletonScope_whenSetName_thenEqualNames() {
    ApplicationContext applicationContext = 
      new ClassPathXmlApplicationContext("scopes.xml");

    Person personSingletonA = (Person) applicationContext.getBean("personSingleton");
    Person personSingletonB = (Person) applicationContext.getBean("personSingleton");

    personSingletonA.setName(NAME);
    Assert.assertEquals(NAME, personSingletonB.getName());

    ((AbstractApplicationContext) applicationContext).close();
}

Prototype Scope

A bean with the prototype scope will return a different instance every time it is requested from the container. It is defined by setting the value prototype to the @Scope annotation in the bean definition:

@Bean
@Scope("prototype")
public Person personPrototype() {
    return new Person();
}
private static final String NAME = "John Smith";
private static final String NAME_OTHER = "Anna Jones";

@Test
public void givenPrototypeScope_whenSetNames_thenDifferentNames() {
    ApplicationContext applicationContext = 
      new ClassPathXmlApplicationContext("scopes.xml");

    Person personPrototypeA = (Person) applicationContext.getBean("personPrototype");
    Person personPrototypeB = (Person) applicationContext.getBean("personPrototype");

    personPrototypeA.setName(NAME);
    personPrototypeB.setName(NAME_OTHER);

    Assert.assertEquals(NAME, personPrototypeA.getName());
    Assert.assertEquals(NAME_OTHER, personPrototypeB.getName());

    ((AbstractApplicationContext) applicationContext).close();
}

Web Aware Scopes

There are four additional scopes that are only available in a web-aware application context. We use these less often in practice.

The request scope creates a bean instance for a single HTTP request, while the session scope creates a bean instance for an HTTP Session.

The application scope creates the bean instance for the lifecycle of a ServletContext, and the websocket scope creates it for a particular WebSocket session.

Let’s create a class to use for instantiating the beans:

public class HelloMessageGenerator {
    private String message;
    
    // standard getter and setter
}

Request Scope

@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator requestScopedBean() {
    return new HelloMessageGenerator();
}
@Bean
@RequestScope
public HelloMessageGenerator requestScopedBean() {
    return new HelloMessageGenerator();
}
@Controller
public class ScopesController {
    @Resource(name = "requestScopedBean")
    HelloMessageGenerator requestScopedBean;

    @RequestMapping("/scopes/request")
    public String getRequestScopeMessage(final Model model) {
        model.addAttribute("previousMessage", requestScopedBean.getMessage());
        requestScopedBean.setMessage("Good morning!");
        model.addAttribute("currentMessage", requestScopedBean.getMessage());
        return "scopesExample";
    }
}

Session Scope

@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator sessionScopedBean() {
    return new HelloMessageGenerator();
}
@Bean
@SessionScope
public HelloMessageGenerator sessionScopedBean() {
    return new HelloMessageGenerator();
}
@Controller
public class ScopesController {
    @Resource(name = "sessionScopedBean")
    HelloMessageGenerator sessionScopedBean;

    @RequestMapping("/scopes/session")
    public String getSessionScopeMessage(final Model model) {
        model.addAttribute("previousMessage", sessionScopedBean.getMessage());
        sessionScopedBean.setMessage("Good afternoon!");
        model.addAttribute("currentMessage", sessionScopedBean.getMessage());
        return "scopesExample";
    }
}

Application Scope

@Bean
@Scope(
  value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator applicationScopedBean() {
    return new HelloMessageGenerator();
}
@Bean
@ApplicationScope
public HelloMessageGenerator applicationScopedBean() {
    return new HelloMessageGenerator();
}
@Controller
public class ScopesController {
    @Resource(name = "applicationScopedBean")
    HelloMessageGenerator applicationScopedBean;

    @RequestMapping("/scopes/application")
    public String getApplicationScopeMessage(final Model model) {
        model.addAttribute("previousMessage", applicationScopedBean.getMessage());
        applicationScopedBean.setMessage("Good afternoon!");
        model.addAttribute("currentMessage", applicationScopedBean.getMessage());
        return "scopesExample";
    }
}

WebSocket Scope

@Bean
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator websocketScopedBean() {
    return new HelloMessageGenerator();
}

References
https://www.baeldung.com/spring-bean-scopes

Spring Boot ApplicationContext

The primary job of the ApplicationContext is to manage beans.
let’s create a configuration class to define our AccountService class as a Spring bean:

@Configuration
public class AccountConfig {

  @Bean
  public AccountService accountService() {
    return new AccountService(accountRepository());
  }

  @Bean
  public AccountRepository accountRepository() {
    return new AccountRepository();
  }
}

Java configuration typically uses @Bean-annotated methods within a @Configuration class. The @Bean annotation on a method indicates that the method creates a Spring bean. Moreover, a class annotated with @Configuration indicates that it contains Spring bean configurations.

AnnotationConfigApplicationContext

ApplicationContext context = new AnnotationConfigApplicationContext(AccountConfig.class);
AccountService accountService = context.getBean(AccountService.class);

AnnotationConfigWebApplicationContext

is a web-based variant of AnnotationConfigApplicationContext.

We may use this class when we configure Spring’s ContextLoaderListener servlet listener or a Spring MVC DispatcherServlet in a web.xml file.

Moreover, from Spring 3.0 onward, we can also configure this application context container programmatically. All we need to do is implement the WebApplicationInitializer interface:

public class MyWebApplicationInitializer implements WebApplicationInitializer {

  public void onStartup(ServletContext container) throws ServletException {
    AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
    context.register(AccountConfig.class);
    context.setServletContext(container);

    // servlet configuration
  }
}

@Autowire  ApplicationContext

You can Autowire the ApplicationContext, either as a field

@Autowired
private ApplicationContext context;

or a method

@Autowired
public void context(ApplicationContext context) { this.context = context; }

Finally use

context.getBean(SomeClass.class)

References
https://www.baeldung.com/spring-application-context
https://stackoverflow.com/questions/34088780/how-to-get-bean-using-application-context-in-spring-boot

Dependency Injection in Spring Boot

Dependency Injection in Spring can be done through constructors, setters or fields.

Constructor-Based Dependency Injection

@Configuration
public class AppConfig {

    @Bean
    public Item item1() {
        return new ItemImpl1();
    }

    @Bean
    public Store store() {
        return new Store(item1());
    }
}

The @Configuration annotation indicates that the class is a source of bean definitions. We can also add it to multiple configuration classes.

We use the @Bean annotation on a method to define a bean. If we don’t specify a custom name, then the bean name will default to the method name.

For a bean with the default singleton scope, Spring first checks if a cached instance of the bean already exists, and only creates a new one if it doesn’t. If we’re using the prototype scope, the container returns a new bean instance for each method call.

Setter-Based Dependency Injection

@Bean
public Store store() {
    Store store = new Store();
    store.setItem(item1());
    return store;
}

Field-Based Dependency Injection

public class Store {
    @Autowired
    private Item item; 
}

While constructing the Store object, if there’s no constructor or setter method to inject the Item bean, the container will use reflection to inject Item into Store.

Autowiring Dependencies

Wiring allows the Spring container to automatically resolve dependencies between collaborating beans by inspecting the beans that have been defined.

There are four modes of autowiring a bean using an XML configuration:

no: the default value – this means no autowiring is used for the bean and we have to explicitly name the dependencies.
byName: autowiring is done based on the name of the property, therefore Spring will look for a bean with the same name as the property that needs to be set.
byType: similar to the byName autowiring, only based on the type of the property. This means Spring will look for a bean with the same type of the property to set. If there’s more than one bean of that type, the framework throws an exception.
constructor: autowiring is done based on constructor arguments, meaning Spring will look for beans with the same type as the constructor arguments.

For example, let’s autowire the item1 bean defined above by type into the store bean:

@Bean(autowire = Autowire.BY_TYPE)
public class Store {
    
    private Item item;

    public setItem(Item item){
        this.item = item;    
    }
}

We can also inject beans using the @Autowired annotation for autowiring by type:

public class Store {
    
    @Autowired
    private Item item;
}

If there’s more than one bean of the same type, we can use the @Qualifier annotation to reference a bean by name:

public class Store {
    
    @Autowired
    @Qualifier("item1")
    private Item item;
}

References
https://www.baeldung.com/inversion-control-and-dependency-injection-in-spring

Create Indexes in Spring Data MongoDB

Using @Indexed
This annotation marks the field as indexed in MongoDB:

@QueryEntity
@Document
public class User {
    @Indexed
    private String name;
    
    ... 
}

but as of Spring Data MongoDB 3.0, automatic index creation is turned off by default.

We can, however, change that behavior by explicitly overriding autoIndexCreation() method in our MongoConfig:

public class MongoConfig extends AbstractMongoClientConfiguration {

    // rest of the config goes here

    @Override
    protected boolean autoIndexCreation() {
        return true;
    }
}

We can create other types of index using these attributes :

@Indexed
@TextIndexed
@HashIndexed
@GeoSpatialIndexed
@WildcardIndexed
@GeoIndexed

Create an Index Programmatically

mongoOps.indexOps(User.class).
  ensureIndex(new Index().on("name", Direction.ASC));

Compound Indexes

MongoDB supports compound indexes, where a single index structure holds references to multiple fields.

@QueryEntity
@Document
@CompoundIndexes({
    @CompoundIndex(name = "email_age", def = "{'email.id' : 1, 'age': 1}")
})
public class User {
    //
}

References
https://www.baeldung.com/spring-data-mongodb-index-annotations-converter
https://careydevelopment.us/blog/spring-boot-and-mongotemplate-how-to-handle-a-full-text-search
https://spring.io/blog/2014/07/17/text-search-your-documents-with-spring-data-mongodb
https://mongodb.github.io/mongo-java-driver/3.4/driver/tutorials/indexes/
https://www.mongodb.com/docs/manual/indexes/

Initialize MongoDB Repositories using ApplicationContextAware in Spring Boot

@Component
public class ApplicationContextProvider implements ApplicationContextAware {
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        DB.mongoTemplate=applicationContext.getBean(MongoTemplate.class);
        DB.monitoringItemRepository = applicationContext.getBean(MonitoringItemRepository.class);
    }
}
public class DB {
    public static MongoTemplate mongoTemplate=null;
    public static MonitoringItemRepository monitoringItemRepository = null;
}

References
https://zetcode.com/springboot/applicationcontext/

Configure Spring Boot to Connect to MongoDB with Credential

@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
    /*
     * Use the standard Mongo driver API to create a com.mongodb.client.MongoClient instance.
     */
    public MongoClient mongoClient() {
        //String connectionString = "mongodb://username:password@localhost:27017/?authSource=admin&authMechanism=SCRAM-SHA-1";
        MongoCredential credential = MongoCredential.createScramSha256Credential("username", "admin", "password".toCharArray());
        MongoClient mongoClient = MongoClients.create(
                MongoClientSettings.builder()
                        .applyToClusterSettings(builder ->
                                builder.hosts(Arrays.asList(new ServerAddress("localhost", 27017))))
                        .credential(credential)
                        .build());
        return mongoClient;
    }

    @Override
    protected String getDatabaseName() {
        return "databaseName";
    }

    @Override
    public Collection getMappingBasePackages() {
        return Collections.singleton("net.pupli");
    }
}

References
https://www.baeldung.com/spring-data-mongodb-tutorial
https://www.mongodb.com/docs/drivers/java/sync/current/fundamentals/auth/
https://www.mongodb.com/docs/manual/reference/connection-string/