개발/spring boot

spring 인터페이스의 구현체를 동적으로 선택

nix-be 2022. 12. 12. 10:22
728x90

1. 내가 원하는 것 : properties에 설정 값에 따라 다른 implement 가 실행되는 것을 구현하고 싶었습니다.

 

1-1. 비효율적인 implement 생성 

 단점은 implement 가 추가되면  bean 등록을 해줘야 됩니다.

@PropertySource("classpath:url.properties")
@RestController
@RequiredArgsConstructor
public class BeanImpl2Controller {
	
	private final FserviceImpl fserviceImpl;
	
	private final SserviceImpl sserviceImpl;
	
	@Value("${server.impl}")
	private String values;
	
	@GetMapping("/beanImple2")
	public String beanimpl() {
		
		switch(values) {
			case "FserviceImpl": 
				fserviceImpl.fire();
				break ;
			case "SserviceImpl":
				sserviceImpl.fire();
				break;
		}
		
		
		return values;
	}
}

 

package com.example.demo.domain.diTest.beanImpl2Properties;

public interface BeanService {
	public void fire();
}
package com.example.demo.domain.diTest.beanImpl2Properties;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class FserviceImpl implements BeanService{

	@Override
	public void fire() {
		System.out.print("test2");
		
	}

}

 

package com.example.demo.domain.diTest.beanImpl2Properties;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class SserviceImpl implements BeanService{

	@Override
	public void fire() {
		System.out.print("test1 ");
		
	}

}

- url.properties

#server.impl = FserviceImpl
server.impl = SserviceImpl

 

하지만 내가 원하는 그림은 아니였습니다. 그래서 검색을 하여 아래와 같은 제가 원하는 것을 찾게 되었습니다.

 

1-2.  implement를 각자 생성 안 해도 되는 코드

 

package com.example.demo.domain.diTest.multipleImplement;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@PropertySource("classpath:url.properties")
@RestController
public class MultipleImplController {
	
	private final Map<String,MultipleImplService> multipleImplServiceMap;
	
	@Value("${server2.multipleImpl}")
	private String interfaceName;
	
	@Autowired
	public MultipleImplController(List<MultipleImplService> multipleImplServices) {
		this.multipleImplServiceMap = multipleImplServices.stream()
				.collect(Collectors.toMap(MultipleImplService::getISOCountryCode, Function.identity()));
	}
	
	@GetMapping("/MultipleImpl")
	public String MultipleImple() {
		
		switch(interfaceName) {
			case "FirstMultipleImplService":
				MultipleImplService impl = multipleImplServiceMap.get("first");
				impl.sampleMethod();
				break;
			case "SecondMultipleImplService":
				MultipleImplService impl2 = multipleImplServiceMap.get("second");
				impl2.sampleMethod();
				break;
		}
		
		return "test";
	}
}
package com.example.demo.domain.diTest.multipleImplement;

public interface MultipleImplService {
	public void sampleMethod();
	public String getISOCountryCode();
}
package com.example.demo.domain.diTest.multipleImplement;

import org.springframework.stereotype.Service;

@Service
public class FirstMultipleImplService implements MultipleImplService{

	@Override
	public void sampleMethod() {
		System.out.print("first 1 method");
		
	}

	@Override
	public String getISOCountryCode() {
		
		return "first";
	}

}
package com.example.demo.domain.diTest.multipleImplement;

import org.springframework.stereotype.Service;

@Service
public class SecondMultipleImplService implements MultipleImplService {

	@Override
	public void sampleMethod() {
		System.out.print("second 2 method");
		
	}
	
	@Override
	public String getISOCountryCode() {
		
		return "second";
	}

}

-url.properties

server2.multipleImpl = FirstMultipleImplService
#server2.multipleImpl = SecondMultipleImplService

 

 

3. 위에 코드는 이해하기 어렵기 때문에  쉬운 코드로 예시를 들어보겠습니다.

- 컨트롤러

 


import com.onetoone.onetoonetest.multiImpl.service.Circle;
import com.onetoone.onetoonetest.multiImpl.service.DrawingService;
import com.onetoone.onetoonetest.multiImpl.service.Rectan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@PropertySource("classpath:url.properties")
@RestController
@RequestMapping("/controller")
public class DrawingController {

    private final DrawingService circle;

    private final DrawingService rectan;

    @Value("${localtion}")
    private String type;
    
    public DrawingController(Circle circle, Rectan rectan){
        this.circle = circle;
        this.rectan = rectan;
    }

    private DrawingService getType(String type){
        return type.equals("center") ? this.circle : this.rectan;
    }

    @GetMapping("/shapes")
    public void drawShapes() {
        getType(type).draw();
    }
}

- url.properties

localtion=center

- 인터페이스

public interface DrawingService {
    public void draw();
}

- implements

@Service
public class Circle implements DrawingService{
    @Override
    public void draw() {
        System.out.println("Circle test 1");

    }
}
@Service
public class Rectan implements DrawingService{
    @Override
    public void draw() {
        System.out.println("Rectan test 1");
    }
}
728x90