Suppose the following code:
#Service
public class SearchService {
#Autowired
DependencyService dependencyService;
}
#Service
public class DependencyService {
private final Util util;
DependencyService(Util util){
this.util = util;
execute();
}
public void execute(){
util.execte();
}
}
#Component
public class ConcreteUtil implements Util{
#Override
public void execte() {
System.out.println("I'm the first concrete Util");
}
}
#Component
public class SecondConcreteUtil implements Util{
#Override
public void execte() {
System.out.println("I'm the second concrete Util");
}
}
In Plain Java I can do something like this:
public class SearchService {
DependencyService first = new DependencyService(new ConcreteUtil());
DependencyService second = new DependencyService(new SecondConcreteUtil());
}
But in Spring, it's not resolved by the client. We instruct Spring which bean to take from inside DependencyService:
DependencyService(#Qualifier("concreteUtil")Util util){
this.util = util;
execute();
}
And not like that:
#Autowired
#Qualifier("concreteUtil")
DependencyService dependencyService;
Why? To me this approach sounds like the opposite of decoupling. What do I miss? And how can Plain Java's result be achieved?
Edit:
I want this behaviour
public class SomeSerice {
DependencyService firstConcrete = new DependencyService(new ConcreteUtil());
}
public class OtherService {
DependencyService SecondConcrete = new DependencyService(new SecondConcreteUtil());
}
So I can reuse the code
You can declare multiple beans of type Dependency service inside some configuration class, like
#Qualifier("ConcreteUtilDepService")
#Bean
public DependencyService concreteUtilDS(#Qualifier("ConcreteUtil")Util util){
return new DependencyService (util);
}
Hi I am trying to use Strategy Design pattern. I am getting ReEncryptionOperation bean as null in my TestServiceImpl class.
this is my interface
public interface ReEncryptionOperation {
void performOperation (String name);
}
These are my implementation classes
public class Test1 implements ReEncryptionOperation {
#Override
public void performOperation(String name){
return ....;
}
}
public class Test2 implements ReEncryptionOperation {
#Override
public void performOperation(String name) {
return ....;
}
}
This is my configuration class where I am defining as a bean
#Configuration
#Slf4j
public class TestConfiguration
{
#Bean("reEncryptionOperation")
public ReEncryptionOperation getReEncryptionOperation () throws ReEncryptionException {
if (annotationSupport) {
return new Test1();
}
return new Test2();
}
}
this is my service class where i am trying to use ReEncryptionOperation using #Autowired. But I am getting null.
#Component
#Slf4j
public class TestServiceImpl
{
#Autowired
private ReEncryptionOperation reEncryptionOperation;
public ReEncryptionResponse submitJob (
final ReEncryptionRequest reEncryptionRequest) throws ReEncryptionException
{
reEncryptionOperation.performOperation(test);
}
}
Your configuration seems ok.
Check that TestConfiguration is located in a package scanned by spring.
To be sure your bean is created on runtime, place a breakpoint in the method getReEncryptionOperation
All the class are implemented from the same interface. What is the best way to create beans depending on the input value we are receiving.
If the value is a it need to invoke one class vs different class if the value is b.
You cloud try something like this:
#Component
public class SomeServiceFactory {
#Autowired
private Someservice someserviceA;
#Autowired
private Someservice someserviceB;
#Autowired
private MyServiceThree SomeserviceC;
public SomeService getSomeService(String serviceType) {
if (serviceType.equals("A")) {
return someserviceA;
} else if (serviceType.equals("B")) {
return someserviceB;
} else {
return someserviceC;
}
}
}
First the interface:
public interface MyService {
void doSomething();
}
Then defining two implementation:
#Service
public class MyServiceA implements MyService {
#Override
public void doSomething() {
// do your business A
}
}
#Service
public class MyServiceB implements MyService {
#Override
public void doSomething() {
// do your business B
}
}
The context:
#Service
#RequiredArgsConstructor(onConstructor = #__(#Autowired))
public class MyServiceContext {
private final Map<String, MyService> strategyMap;
public MyService getMyService(String key) {
// the key is the bean name
return strategyMap.get(key);
}
}
Usage
#Autowired
private MyServiceContext context;
...
// your input key must be the bean name.
context.getMyService(yourInputValue).doSmething();
I am currently working on an spring boot application that wires some beans together in the following way (heavily simplified example):
#Component
#Order(0)
public class PlayingFieldByBeans implements CommandLineRunner {
#Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from lazy beans variant: ");
names.forEach(n -> {
System.out.println(player(n));
});
}
#Bean
#Lazy
public Player player(String name) {
return new Player(name, shoes());
}
#Bean
#Lazy
private Shoes shoes() {
return new Shoes("Adidas");
}
}
The actual beans however, require alot more configuration and setting than is shown here and it takes quite alot of lines of code in the PlayingFieldByBeans class when using the inner Lazy Bean methodology. So I created a different way of wiring it together using Component annotation:
#Component
#Order(1)
public class PlayingFieldByComponents implements CommandLineRunner {
#Autowired
private PlayerComponent playerComponent;
#Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from component variant: ");
names.forEach(n -> {
System.out.println(playerComponent.player(n));
});
}
}
The PlayerComponent class looks like this:
#Component
public class PlayerComponent {
#Autowired
private ShoesComponent shoesComponent;
public Player player(String name) {
return new Player(name, shoesComponent.shoes());
}
}
The ShoesComponent is very similar to the PlayerComponent class.
For maintainablity and TDD purposes I am not sure what is the most proper way to use the spring framework here.
Question
Given the Player and Shoes beans require more then just one line of initialization (multiple settings, multiple dependencies on other beans etc), what is the best way to design and wire them?
Edit - based on suggestion
Added a configuration class to bundle the beans:
#Configuration
public class BeanConfiguration {
#Bean
#Lazy
public Player player(String name) {
return new Player(name, shoes());
}
#Bean
#Lazy
public Shoes shoes() {
return new Shoes("Adidas");
}
}
And the matching executing class:
#Component
#Order(2)
public class PlayingFieldByConfiguration implements CommandLineRunner {
#Autowired
private BeanConfiguration beanConfiguration;
#Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from component variant: ");
names.forEach(n -> {
System.out.println(beanConfiguration.player(n));
});
}
}
Re uses the same first bean, so it doesn't seem to create a new one
Printing from component variant:
Player name: Alex has shoes of brand: Adidas
Player name: Alex has shoes of brand: Adidas
Player name: Alex has shoes of brand: Adidas
One solution would be to change scope of Player bean (and Shoes later on if we want to create different brands) as mentioned by Andriy Slobodyanyk
#Configuration
public class BeanConfiguration {
#Bean
#Lazy
#Scope(BeanDefinition.SCOPE_PROTOTYPE)
public Player player(String name) {
return new Player(name, shoes());
}
#Bean
#Lazy
public Shoes shoes() {
return new Shoes("Adidas");
}
}
If above would not be sufficient (since you mentioned real case scenario is more compilcated) another option is to use FactoryBean
public class PlayerFactoryBean implements FactoryBean<Player> {
private String name;
private Shoes shoes;
public void setName(String name) {
this.name = name;
}
public void setShoes(Shoes shoes) {
this.shoes = shoes;
}
#Override
public Player getObject() throws Exception {
//initialization logic goes here
System.out.println("Creating bean using factory");
return new Player(name, shoes);
}
#Override
public Class<Player> getObjectType() {
return Player.class;
}
#Override
public boolean isSingleton() {
return false;
}
}
#Configuration
public class BeanConfiguration {
#Bean
#Lazy
public Shoes shoes() {
return new Shoes("Adidas");
}
#Bean
public PlayerFactoryBean playerFactoryBean(){
PlayerFactoryBean pfb = new PlayerFactoryBean();
pfb.setShoes(shoes());
return pfb;
}
}
#Component
#Order(2)
public class PlayingFieldByConfiguration implements CommandLineRunner {
#Autowired
private PlayerFactoryBean factoryBean;
#Override
public void run(String... arg0) throws Exception {
List<String> names = new ArrayList<>();
names.add("Alex");
names.add("Benedict");
names.add("Chloe");
System.out.println("Printing from component variant: ");
names.forEach(n -> {
try {
factoryBean.setName(n);
System.out.println(factoryBean.getObject());
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
I'm using Spring Beans with annotations and I need to choose different implementation at runtime.
#Service
public class MyService {
public void test(){...}
}
For example for windows's platform I need MyServiceWin extending MyService, for linux platform I need MyServiceLnx extending MyService.
For now I know only one horrible solution:
#Service
public class MyService {
private MyService impl;
#PostInit
public void init(){
if(windows) impl=new MyServiceWin();
else impl=new MyServiceLnx();
}
public void test(){
impl.test();
}
}
Please consider that I'm using annotation only and not XML config.
1. Implement a custom Condition
public class LinuxCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getEnvironment().getProperty("os.name").contains("Linux"); }
}
Same for Windows.
2. Use #Conditional in your Configuration class
#Configuration
public class MyConfiguration {
#Bean
#Conditional(LinuxCondition.class)
public MyService getMyLinuxService() {
return new LinuxService();
}
#Bean
#Conditional(WindowsCondition.class)
public MyService getMyWindowsService() {
return new WindowsService();
}
}
3. Use #Autowired as usual
#Service
public class SomeOtherServiceUsingMyService {
#Autowired
private MyService impl;
// ...
}
Let's create beautiful config.
Imagine that we have Animal interface and we have Dog and Cat implementation. We want to write write:
#Autowired
Animal animal;
but which implementation should we return?
So what is solution? There are many ways to solve problem. I will write how to use #Qualifier and Custom Conditions together.
So First off all let's create our custom annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
public #interface AnimalType {
String value() default "";
}
and config:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class AnimalFactoryConfig {
#Bean(name = "AnimalBean")
#AnimalType("Dog")
#Conditional(AnimalCondition.class)
public Animal getDog() {
return new Dog();
}
#Bean(name = "AnimalBean")
#AnimalType("Cat")
#Conditional(AnimalCondition.class)
public Animal getCat() {
return new Cat();
}
}
Note our bean name is AnimalBean. why do we need this bean? because when we inject Animal interface we will write just #Qualifier("AnimalBean")
Also we crated custom annotation to pass the value to our custom Condition.
Now our conditions look like this (imagine that "Dog" name comes from config file or JVM parameter or...)
public class AnimalCondition implements Condition {
#Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
if (annotatedTypeMetadata.isAnnotated(AnimalType.class.getCanonicalName())){
return annotatedTypeMetadata.getAnnotationAttributes(AnimalType.class.getCanonicalName())
.entrySet().stream().anyMatch(f -> f.getValue().equals("Dog"));
}
return false;
}
}
and finally injection:
#Qualifier("AnimalBean")
#Autowired
Animal animal;
You can move the bean injection into the configuration, as:
#Configuration
public class AppConfig {
#Bean
public MyService getMyService() {
if(windows) return new MyServiceWin();
else return new MyServiceLnx();
}
}
Alternatively, you may use profiles windows and linux, then annotate your service implementations with the #Profile annotation, like #Profile("linux") or #Profile("windows"), and provide one of this profiles for your application.
Autowire all your implementations into a factory with #Qualifier annotations, then return the service class you need from the factory.
public class MyService {
private void doStuff();
}
My Windows Service:
#Service("myWindowsService")
public class MyWindowsService implements MyService {
#Override
private void doStuff() {
//Windows specific stuff happens here.
}
}
My Mac Service:
#Service("myMacService")
public class MyMacService implements MyService {
#Override
private void doStuff() {
//Mac specific stuff happens here
}
}
My factory:
#Component
public class MyFactory {
#Autowired
#Qualifier("myWindowsService")
private MyService windowsService;
#Autowired
#Qualifier("myMacService")
private MyService macService;
public MyService getService(String serviceNeeded){
//This logic is ugly
if(serviceNeeded == "Windows"){
return windowsService;
} else {
return macService;
}
}
}
If you want to get really tricky you can use an enum to store your implementation class types, and then use the enum value to choose which implementation you want to return.
public enum ServiceStore {
MAC("myMacService", MyMacService.class),
WINDOWS("myWindowsService", MyWindowsService.class);
private String serviceName;
private Class<?> clazz;
private static final Map<Class<?>, ServiceStore> mapOfClassTypes = new HashMap<Class<?>, ServiceStore>();
static {
//This little bit of black magic, basically sets up your
//static map and allows you to get an enum value based on a classtype
ServiceStore[] namesArray = ServiceStore.values();
for(ServiceStore name : namesArray){
mapOfClassTypes.put(name.getClassType, name);
}
}
private ServiceStore(String serviceName, Class<?> clazz){
this.serviceName = serviceName;
this.clazz = clazz;
}
public String getServiceBeanName() {
return serviceName;
}
public static <T> ServiceStore getOrdinalFromValue(Class<?> clazz) {
return mapOfClassTypes.get(clazz);
}
}
Then your factory can tap into the Application context and pull instances into it's own map. When you add a new service class, just add another entry to the enum, and that's all you have to do.
public class ServiceFactory implements ApplicationContextAware {
private final Map<String, MyService> myServices = new Hashmap<String, MyService>();
public MyService getInstance(Class<?> clazz) {
return myServices.get(ServiceStore.getOrdinalFromValue(clazz).getServiceName());
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
myServices.putAll(applicationContext.getBeansofType(MyService.class));
}
}
Now you can just pass the class type you want into the factory, and it will provide you back the instance you need. Very helpful especially if you want to the make the services generic.
Simply make the #Service annotated classes conditional:
That's all. No need for other explicit #Bean methods.
public enum Implementation {
FOO, BAR
}
#Configuration
public class FooCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Implementation implementation = Implementation.valueOf(context.getEnvironment().getProperty("implementation"));
return Implementation.FOO == implementation;
}
}
#Configuration
public class BarCondition implements Condition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Implementation implementation = Implementation.valueOf(context.getEnvironment().getProperty("implementation"));
return Implementation.BAR == implementation;
}
}
Here happens the magic.
The condition is right where it belongs: At the implementating classes.
#Conditional(FooCondition.class)
#Service
class MyServiceFooImpl implements MyService {
// ...
}
#Conditional(BarCondition.class)
#Service
class MyServiceBarImpl implements MyService {
// ...
}
You can then use Dependency Injection as usual, e.g. via Lombok's #RequiredArgsConstructor or #Autowired.
#Service
#RequiredArgsConstructor
public class MyApp {
private final MyService myService;
// ...
}
Put this in your application.yml:
implementation: FOO
👍 Only the implementations annotated with the FooCondition will be instantiated. No phantom instantiations. 👍
Just adding my 2 cents to this question. Note that one doesn't have to implement so many java classes as the other answers are showing. One can simply use the #ConditionalOnProperty. Example:
#Service
#ConditionalOnProperty(
value="property.my.service",
havingValue = "foo",
matchIfMissing = true)
class MyServiceFooImpl implements MyService {
// ...
}
#ConditionalOnProperty(
value="property.my.service",
havingValue = "bar")
class MyServiceBarImpl implements MyService {
// ...
}
Put this in your application.yml:
property.my.service: foo
MyService.java:
public interface MyService {
String message();
}
MyServiceConfig.java:
#Configuration
public class MyServiceConfig {
#Value("${service-type}")
MyServiceTypes myServiceType;
#Bean
public MyService getMyService() {
if (myServiceType == MyServiceTypes.One) {
return new MyServiceImp1();
} else {
return new MyServiceImp2();
}
}
}
application.properties:
service-type=one
MyServiceTypes.java
public enum MyServiceTypes {
One,
Two
}
Use in any Bean/Component/Service/etc. like:
#Autowired
MyService myService;
...
String message = myService.message()