Sunday 22 January 2023

Micronaut: Conditional beans using @Required annotation

There are situations, where you may want to define a bean when certain conditions are met (like the configuration, based on operating system etc.,). This ability is provided by @Requires annotation.

 

Example

@Singleton
@Requires(beans = DataSource.class)
@Requires(property = "datasource.url")
@Requires(property = "datasource.port")
@Requires(property = "datasource.username")
public class MySQLDataSource {

	private DataSource dataSource;

	public MySQLDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	.........
	.........
}

The above bean defines four requirements.

a.   The first indicates that a DataSource bean must be present for the bean to load.

b.   The second requirement ensures that the datasource.url property is set before loading the MySQLDataSource bean.

c.    The third requirement ensures that the datasource.port property is set before loading the MySQLDataSource bean.

d.   The second requirement ensures that the datasource.username property is set before loading the MySQLDataSource bean.

 

Find the below working application.

 

Step 1: Create new maven project ‘micronaut-conditional-beans-demo’.

 

Step 2: Update pom.xml with maven dependencies.

 

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.sample.app</groupId>
	<artifactId>micronaut-conditional-beans-demo</artifactId>
	<version>1</version>

	<properties>
		<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
		<micronaut.version>3.7.1</micronaut.version>

		<maven.compiler.target>15</maven.compiler.target>
		<maven.compiler.source>15</maven.compiler.source>
	</properties>

	<dependencies>

		<dependency>
			<groupId>io.micronaut</groupId>
			<artifactId>micronaut-inject-java</artifactId>
			<version>${micronaut.version}</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>

			<plugin>
				<artifactId>maven-assembly-plugin</artifactId>
				<configuration>
					<archive>
						<manifest>
							<mainClass>com.sample.app.App</mainClass>
						</manifest>
					</archive>
					<descriptorRefs>
						<descriptorRef>jar-with-dependencies</descriptorRef>
					</descriptorRefs>
				</configuration>

				<executions>
					<execution>
						<id>make-assembly</id>
						<phase>package</phase>
						<goals>
							<goal>single</goal>
						</goals>
					</execution>
				</executions>
			</plugin>

		</plugins>
	</build>
</project>

Step 3: Create application.yml file under src/main/resources folder.

 

application.yml

logger:
  levels:
    io.netty: ERROR
    io.micronaut: ERROR
    
datasource:
  url: my-datasource.com
  port: 12345
  username: krishna

Step 4: Define DataSource and MySQLDataSource classes.

 

DataSource.java

package com.sample.app.datasources;

import io.micronaut.context.annotation.Requires;
import io.micronaut.context.annotation.Value;
import jakarta.inject.Singleton;

@Requires(property = "datasource.url")
@Requires(property = "datasource.port")
@Requires(property = "datasource.username")
@Singleton
public class DataSource {

	@Value("${datasource.url}")
    private String dataSourceUrl;
	
	@Value("${datasource.port}")
    private String dataSourcePort;
	
	@Value("${datasource.username}")
    private String dataSourceUsername;

	public String getDataSourceUrl() {
		return dataSourceUrl;
	}

	public void setDataSourceUrl(String dataSourceUrl) {
		this.dataSourceUrl = dataSourceUrl;
	}

	public String getDataSourcePort() {
		return dataSourcePort;
	}

	public void setDataSourcePort(String dataSourcePort) {
		this.dataSourcePort = dataSourcePort;
	}

	public String getDataSourceUsername() {
		return dataSourceUsername;
	}

	public void setDataSourceUsername(String dataSourceUsername) {
		this.dataSourceUsername = dataSourceUsername;
	}
	
	
}

MySQLDataSource.java

package com.sample.app.datasources;

import io.micronaut.context.annotation.Requires;
import jakarta.inject.Singleton;

@Singleton
@Requires(beans = DataSource.class)
@Requires(property = "datasource.url")
@Requires(property = "datasource.port")
@Requires(property = "datasource.username")
public class MySQLDataSource {

	private DataSource dataSource;

	public MySQLDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

}

Step 5: Define main application class.

 

App.java

package com.sample.app;

import com.sample.app.datasources.MySQLDataSource;

import io.micronaut.context.ApplicationContext;;

public class App {

	public static void main(String[] args) {
		try (ApplicationContext applicationContext = ApplicationContext.run()) {
			MySQLDataSource mySQLDataSource = applicationContext.getBean(MySQLDataSource.class);

			System.out.println("url : " + mySQLDataSource.getDataSource().getDataSourceUrl());
			System.out.println("port : " + mySQLDataSource.getDataSource().getDataSourcePort());
			System.out.println("username : " + mySQLDataSource.getDataSource().getDataSourceUsername());
		}
	}
}

Total project structure looks like below.




Build the project using mvn package command.

Navigate to the folder where pom.xml is located and execute the command ‘mvn package’.

 

Upon command successful execution, you can see the jar file ‘micronaut-conditional-beans-demo-1-jar-with-dependencies.jar’ in project target folder.

$ ls ./target/
archive-tmp
classes
generated-sources
maven-archiver
maven-status
micronaut-conditional-beans-demo-1-jar-with-dependencies.jar
micronaut-conditional-beans-demo-1.jar
test-classes

Execute below command to run the application.


$ java -jar ./target/micronaut-conditional-beans-demo-1-jar-with-dependencies.jar
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
url : my-datasource.com
port : 12345
username : krishna

You can download this application from this link.


How to reuse the requirements on multiple beans?

If multiple beans require the same combination of requirements, then you can define a meta-annotation with the requirements and use it on the bean definitions.


@Requires(property = "datasource.url")
@Requires(property = "datasource.port")
@Requires(property = "datasource.username")
public @interface RequiresDataSource {

}

In the above example the RequiresDataSource annotation can be used on the JdbcBookService and MySQLDataSource classes like below.

@Singleton
@RequiresDataSource
public class DataSource {

}

@Singleton
@Requires(beans = DataSource.class)
@RequiresDataSource
public class MySQLDataSource {

}

You can download this application from this link.


Refer below documentation, to get more details on @Requires annotation usage.

https://docs.micronaut.io/latest/guide/#conditionalBeans

 

Previous                                                    Next                                                    Home

No comments:

Post a Comment