사용자 정의 bean 용기 코드 가 독성 향상
특정한 유형의 표지 에 따라 서로 다른 업무 논리 에 따라 우 리 는 보통 if (type. equals (xxxx) 나 switch 문 구 를 사용 하여 논리 적 으로 처리한다.
이렇게 하 는 것 은 당연히 아무런 문제 가 없다.
업무 논리 가 점점 복잡 해 지고 유형 표지 가 많아 지면 if 판단 이 증가 하거나 switch case 분기 가 많아 지 는 것 을 피하 기 어렵다. 이런 코드 는 너무 지루 하고 코드 의 중복 성 이 비교적 크 거나 강요 격 이 높 지 않다.
본 고 는 사용자 정의 Bean 용기 의 개발 방식 을 바탕 으로 코드 의 판단 가 지 를 없 애고 코드 의 가 독성 을 향상 시 키 는 것 을 소개 한다.
우 리 는 demo 를 통 해 어떻게 이런 인 코딩 방식 을 실현 하 는 지 보 았 다.
1. 정의 인터페이스
먼저 하나의 인 터 페 이 스 를 정의 하 는데 주로 두 가지 방법 이 있다.
public interface AbstractService {
/**
* serviceName
* bean
* @return
*/
String serviceName();
/**
* service
* @param parm
* @return
*/
T execute(Object parm);
}
구현 클래스 는 serviceName 을 실행 하고 구체 적 인 유형 을 되 돌려 야 합 니 다. 서로 다른 bean 구현 클래스 는 이 반환 값 이 중복 되 지 않도록 주의 하 십시오.
execute 방법 은 업무 방법 입 니 다. 여 기 는 시범 일 뿐 실제 개발 에 서 는 임의의 통용 업무 방법 이 될 수 있 습 니 다.
2. 인터페이스 구현
이어서 실현 클래스 를 작성 하여 인 터 페 이 스 를 실현 합 니 다.
2.1. ServiceAImpl 태그 유형 은 ServiceA
@Component
public class ServiceAImpl implements AbstractService {
@Override
public String serviceName() {
return "ServiceA";
}
@Override
public DemoA execute(Object parm) {
System.out.println("ServiceAImpl execute");
return new DemoA().setName("DemoA");
}
}
2.2 ServiceBImpl 태그 유형 은 ServiceB
@Component
public class ServiceBImpl implements AbstractService {
@Override
public String serviceName() {
return "ServiceB";
}
@Override
public DemoB execute(Object parm) {
System.out.println("ServiceBImpl execute");
return new DemoB().setName("DemoB");
}
}
2.3, 사용자 정의 Bean 컨 텍스트 작성
중요 한 장면 입 니 다. 빈 컨 텍스트 를 만 들 고 AbstractService 집합 을 주입 해 야 합 니 다.
@Component
public class ServiceContext {
// IService ,key=serviceName,velue=
private static Map SERVICE_CONTEXT;
@Autowired
List services;
@PostConstruct
void init() {
SERVICE_CONTEXT = new ConcurrentHashMap<> ();
if (services == null) {
return;
}
// IService serviceContext
for(AbstractService service : services) {
SERVICE_CONTEXT.put(service.serviceName(), service);
}
System.out.println(JSON.toJSONString(SERVICE_CONTEXT));
}
/**
* serviceName
* @param serviceName
* @return
*/
public AbstractService getServiceImpl(String serviceName) {
return SERVICE_CONTEXT.get(serviceName);
}
}
사실 설명 은 잘 알 고 있 습 니 다. 먼저 맵 을 정의 합 니 다. key 는 String 입 니 다. 위의 인터페이스 에서 돌아 온 serviceName 을 대표 합 니 다.
value 는 인터페이스 구현 클래스 bean 인 스 턴 스 입 니 다.
이 어 @ Autowired 를 통 해 AbstractService 집합 을 주입 합 니 다. 여 기 는 List 입 니 다.Spring 용기 초기 화가 완료 되면 AbstractService 의 구현 클래스 를 모두 List 에 불 러 옵 니 다.
@ PostConstruct 태그 의 초기 화 방법 을 옮 겨 다 닙 니 다. List < AbstractService > 이 며, 우리 가 초기 화 한 맵 에 순서대로 불 러 옵 니 다.key = AbstractService. serviceName () 의 반환 값, value 는 AbstractService 인 스 턴 스 입 니 다.
getServiceImpl (String serviceName) 을 업무 에 사용 하도록 정의 합 니 다. 구체 적 인 serviceName 표 지 를 통 해 Bean 인 스 턴 스 를 얻 을 수 있 습 니 다.이것 도 서비스 Name 이 중복 되 지 않 는 이유 입 니 다.
2.4 테스트
이 주요 논리 작성 이 완료 되 었 습 니 다. 테스트 클래스 를 만들어 서 구체 적 으로 어떻게 사용 하 는 지 테스트 해 보 겠 습 니 다.
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(DemoApplication.class, args);
// bean Context
ServiceContext serviceContext = applicationContext.getBean("serviceContext", ServiceContext.class);
// serviceName
AbstractService serviceA = serviceContext.getServiceImpl("ServiceA");
AbstractService serviceB = serviceContext.getServiceImpl("ServiceB");
// service
serviceA.execute(null);
serviceB.execute(null);
}
Spring 컨 텍스트 에서 ServiceContext 를 가 져 오고 구체 적 인 serviceName 을 통 해 해당 하 는 Bean 인 스 턴 스 를 가 져 오고 인 스 턴 스 의 execute 방법 을 호출 합 니 다.실행 결 과 는 다음 과 같 습 니 다.
ServiceAImpl execute
ServiceBImpl execute
이것 은 아직 직관 적 이지 않 은 것 같 아서 우 리 는 업무 장면 을 모 의 했다.
업 무 는 serviceName 을 먼저 판단 한 다음 에 구체 적 인 값 에 따라 실행 논 리 를 선택해 야 합 니 다.
정상 적 인 상황 에서 우 리 는 이렇게 업무 코드 를 작성 할 것 이다.
if ("ServiceA".equals(serviceName)) {
serviceA.execute()
return;
}
if ("ServiceB".equals(serviceName)) {
serviceB.execute()
return;
}
...
서비스 Name 이 100 개 있 으 면 100 개의 if 분기 가 있어 야 합 니 다. switch 도 마찬가지 입 니 다.
그러나 본 논문 의 인 코딩 방식 을 취하 면 이렇게 써 야 한다.
... serviceContext , @Autowired/@Resource ...
AbstractService service = serviceContext.getServiceImpl(serviceName);
service.execute()
이렇게 하면 우 리 는 서비스 Name 형식 을 추가 한 후에 대응 하 는 실현 클래스 를 개발 하면 된다.
전통 적 인 인 인 코딩 방식 이 라면 서비스 구현 을 추가 하 는 것 외 에 if / switch 판단 논 리 를 수정 해 야 하 며 유연성 이 부족 하고 오류 가 발생 하기 쉽다.
이곳 은 사실상 개방 폐쇄 원칙 의 구현 이다.전통 적 인 방식 은 수정 과 확장 에 모두 개방 적 이 고 이런 방식 은 확장 개발 에 대해 폐쇄 적 이다.특히 복잡 한 업무 장면 의 개발 에 적합 하 다.
3. 원리
원 리 를 간단히 말 하 다.
Spring 프레임 워 크 는 집합 유형 에 대한 의존 주입 을 지원 합 니 다. 집합 유형 에 대한 의존 주입 과 검색 에 작용 하 는 applicationContext 구현 클래스 는? ListableBeanFactory。
우 리 는 소스 코드 가 어떻게 이 특성 을 실현 하 는 지 보 자.
구체 적 인 논 리 는 org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency 이 방법 은
이 방법 을 열 고 아래 줄 에 중점 을 두 세 요.
Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
resolve Dependency 방법 에 들 어가 면 다음 줄 을 보고 doResolve Dependency 방법 으로 이동 합 니 다.
result = doResolveDependency(descriptor, requestingBeanName,
autowiredBeanNames, typeConverter);
아래 의 논리 에 중점 을 두다.
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
이 곳 의 resolve MultipleBeans 방법 은 여러 조건 에 맞 는 Bean 을 분석 하면 분석 결 과 를 되 돌려 주 는 것 으로 논리 적 이다.
그렇다면 구체 적 인 해석 결 과 는 무엇 일 까?resolve MultipleBeans 방법 으로 들 어 갑 니 다.
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class> type = descriptor.getDependencyType();
//
if (type.isArray()) {
Class> componentType = type.getComponentType();
ResolvableType resolvableType = descriptor.getResolvableType();
Class> resolvedArrayType = resolvableType.resolve();
if (resolvedArrayType != null && resolvedArrayType != type) {
type = resolvedArrayType;
componentType = resolvableType.getComponentType().resolve();
}
if (componentType == null) {
return null;
}
Map matchingBeans = findAutowireCandidates(beanName, componentType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (getDependencyComparator() != null && result instanceof Object[]) {
Arrays.sort((Object[]) result, adaptDependencyComparator(matchingBeans));
}
return result;
}
// , List set
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
Map matchingBeans = findAutowireCandidates(beanName, elementType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (getDependencyComparator() != null && result instanceof List) {
((List>) result).sort(adaptDependencyComparator(matchingBeans));
}
return result;
}
// Map
else if (Map.class == type) {
ResolvableType mapType = descriptor.getResolvableType().asMap();
Class> keyType = mapType.resolveGeneric(0);
if (String.class != keyType) {
return null;
}
Class> valueType = mapType.resolveGeneric(1);
if (valueType == null) {
return null;
}
Map matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
return matchingBeans;
}
else {
return null;
}
}
여기 가 바로 @ Autowired 주입 집합 유형의 핵심 입 니 다.
// Map key
Class> keyType = mapType.resolveGeneric(0);
if (String.class != keyType) {
return null;
}
// Map value
Class> valueType = mapType.resolveGeneric(1);
if (valueType == null) {
return null;
}
즉, 업무 상 외부 type 에 의존 하지 않 으 면 우 리 는 맵 집합 을 직접 주입 할 수 있다. 예 를 들 어 @Autowired
private Map map;
이렇게 하면 인터페이스 Bean Interface 의 실현 을 모두 맵 에 주입 할 수 있 고 key 의 값 은 구체 적 인 Bean 의 name 이 며 value 는 Bean 인 스 턴 스 이다.4. 소결 본 고 에서 우 리 는 사례 와 소스 코드 를 통 해 전방위 적 으로 Spring 이 집합 유형 에 대한 주입 방식 을 나 타 냈 다.요약:
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
thymeleaf로 HTML 페이지를 동적으로 만듭니다 (spring + gradle)지난번에는 에서 화면에 HTML을 표시했습니다. 이번에는 화면을 동적으로 움직여보고 싶기 때문에 입력한 문자를 화면에 표시시키고 싶습니다. 초보자의 비망록이므로 이상한 점 등 있으면 지적 받을 수 있으면 기쁩니다! ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.