In the previous post under Spring Core, I showed how to use “@Profile” annotation with “@Configuration” and “@Bean” annotation.
In this post under Spring Core, I will show with example how to use “@Profile” annotation with “@Component” annotation.
In previous post I also mentioned that “@Profile” annotation can be used with “@Configuration”, “@Bean”, and “@Component” annotation.
The difference between them being
1) if they are multiple objects that change based on the environment we are using, and they are declared using “@Bean” annotation we can group them in one separate configuration class and in that class, we apply the “@Profile” annotation at the class level. In this case, the entire configuration class is ignored if the profile name applied doesn’t match with the profile name given at the start of the application
2) if they are one or two objects that change based on the environment we are using, and they are declared using “@Bean” annotation in configuration classes along with other “@Bean” annotated methods, then we apply “@Profile” at the bean level. In this case, the entire bean declaration is ignored if the profile name applied doesn’t match with the profile name given at the start of the application
3) if they are objects that change based on the environment we are using, and they are declared using “@Component” annotation then we apply “@Profile” at each objects class level. In this case, the entire bean declaration is ignored if the profile name applied doesn’t match with the profile name given at the start of the application
In this post I will discuss the 3nd option. The 1st and 2nd option was discussed in previous post.
To explain with example I will create marker interface as shown below
ICalculator
package package16;
public interface ICalculator {
}
Now I will create two different implementations of “ICalculator” interface one for production and another for testing as shown below
ProdCalculator
package package16;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component("calculator")
@Profile({"prod", "default"})
public class ProdCalculator implements ICalculator {
@Override
public String toString() {
return "Production Calculator";
}
}
TestCalculator
package package16;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
@Component("calculator")
@Profile("test")
public class TestCalculator implements ICalculator {
@Override
public String toString() {
return "Test Calculator";
}
}
In the above two classes “ProdCalculator” and “TestCalculator”, I have added “@Profile” annotation at class level.
For “ProdCalculator” class I am passing “prod” and “default” as profile names as an argument to “@Profile” annotation. This informs the Spring framework to consider this class only when the application environment is production.
For “TestCalculator” class I am passing “test” as profile name as an argument to “@Profile” annotation. This informs the Spring framework to conside this class only when the application environment is testing.
In this way we can use “@Profile” annotation with “@Component” annotation.
We can specify the profile or environment information at the start of the application by using the VM argument “-Dspring.profiles.active” as shown below.
-Dspring.profiles.active=test
Note the profile name passed as VM argument must match with one of the profile names passed as argument to “@Profile” annotation.
Below code shows the main class for your reference
Main class
package package16;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = "package16")
public class Example16 {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Example16.class);
ICalculator calculator = applicationContext.getBean(ICalculator.class);
System.out.println(calculator);
}
}