1. 程式人生 > >Spring 一個介面多個實現,如何根據外部條件來實時替換具體實現類

Spring 一個介面多個實現,如何根據外部條件來實時替換具體實現類

程式碼:

<T> Map<String, T> getBeansOfType(Class<T> var1) throws BeansException;

作用:

1. 傳入一個介面的Class 型別,獲取這個class 的所有具體實現,不包括抽象類

2. 還可以將 applicationContext 單獨設定一個值,寫成一個工具類,結合ApplicationContext 類的其他方法,比如:

getBean(String var1)

需求:

定義了一個介面,來對外提供服務,這個介面下的方法不能隨便改變,而介面有一系列實現,且實現還在不斷新增,如何在傳入外部不同的條件下,實現實時更換介面的實現類

之前的解決辦法:

是在controller 中分別引入具體的實現,通過一個外部條件在controller 判斷使用那個實現,

弊端:

1.每次增加新的介面,都需要在controller 中在@Autowired 一個依賴,都必須修改Controller 類的程式碼,

2.之前最多引入的實現類有9個,但是實現還在不斷增加,如果繼續引入更多類,spring 建立這個controller的時間大大增加,因為引入載入太多類,

修改的辦法:

通過spring 的ApplicationContext(應用上下文)的getBeansOfType 方法傳入介面型別,一次性獲取所有實現類

問題:

1怎麼獲得實時的應用上下文物件 applicationContext

任何類 實現 ApplicationContextAware 介面,實現setApplicationContext 方法,就會在啟動時,向實現類的實現方法注入applicationContext物件

例子:

package com.util;

import com.service.TestService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Component
public class TestServiceFactory implements ApplicationContextAware {

    private static Map<TypeEnum, TestService> testServiceMap;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        Map<String,TestService> map = applicationContext.getBeansOfType(TestService.class);
        testServiceMap = new HashMap<>();
        map.forEach((key,value) -> testServiceMap.put(value.getCode(),value));
    }

    public TestService getTestService(TypeEnum typeEnum) {
        return testServiceMap.get(typeEnum);
    }
}

2. 怎麼根據外部條件實現獲得對應的實現類?

可以在介面中加一個getCode方法,實現類實現這個方法,然後返回一個定義的列舉型別,然後將getBeansOfType獲得map進行轉換

例子:

package com.util;

public enum  TypeEnum {
    impl1,
    impl2
}

介面

package com.service;

import com.util.TypeEnum;
import org.springframework.stereotype.Service;

@Service
public interface TestService {

    public TypeEnum getCode();

    public String test();

}

實現類

package com.service.impl;

import com.service.TestService;
import com.util.TypeEnum;
import org.springframework.stereotype.Service;

@Service
public class TestServiceImpl1 implements TestService {
    @Override
    public TypeEnum getCode() {
        return TypeEnum.impl1;
    }

    @Override
    public String test() {
        return this.toString();
    }
}
package com.service.impl;

import com.service.TestService;
import com.util.TypeEnum;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Service
public class TestServiceImpl2  implements TestService {
    @Override
    public TypeEnum getCode() {
        return TypeEnum.impl2;
    }

    @Override
    public String test() {
        return this.toString();
    }
}

controller類

package com.controller;

import com.util.TestServiceFactory;
import com.util.TypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.service.TestService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
@RequestMapping("test")
public class TestController {

    @Autowired
    TestServiceFactory testServiceFactory;

    private TestService testService;

    @ResponseBody
    @RequestMapping("test")
        public String test(HttpServletRequest request, HttpServletResponse response){
        String type = request.getParameter("type");
        testService = getTestService(type);
        return testService.test();
    }

    public TestService getTestService(String type) {
        TypeEnum typeEnum = null;
        if(type.equals("1")) typeEnum = TypeEnum.impl1;
        if(type.equals("2")) typeEnum = TypeEnum.impl2;
        return testServiceFactory.getTestService(typeEnum);
    }

}