Heim  >  Artikel  >  Java  >  Erstellen Sie einen Zwischendienst für den unabhängigen Datenbankzugriff

Erstellen Sie einen Zwischendienst für den unabhängigen Datenbankzugriff

巴扎黑
巴扎黑Original
2017-06-23 10:57:051682Durchsuche

Mit den kontinuierlichen Veränderungen im Geschäftsleben des Unternehmens wurden Projekt A und die zugrunde liegende DB_A-Datenbank vor einigen Jahren in Kerngeschäftsdienste und Kerndatenbanken umgewandelt.

Es gibt immer mehr Webdienste, die Daten aus der DB_A-Datenbank abrufen möchten, und die Beziehung zwischen Projekten hat sich nach und nach wie folgt entwickelt:

Es ist leicht zu erkennen, dass es gemäß dem Entwicklungstrend im Bild oben viele Probleme geben wird (die Projektbeziehung ist eine vereinfachte, von Einzelpersonen abstrahierte Version). die tatsächliche Situation ist viel komplizierter).

a. Wenn während der Ausführung von webappA eine Ausnahme auftritt und nicht darauf zugegriffen werden kann, können die DB_A-Daten normal abgerufen werden?

b. Verschiedene Dienste, die für webappB/webappC bereitgestellt werden, um DB_A-Daten zu erhalten, werden in webappA ins Unendliche erweitert, was niemandem gefällt ?

c. Während des laufenden Prozesses muss das webappA-Projekt nicht nur normalerweise seine eigenen Dienste für Benutzer bereitstellen, sondern auch die Anforderungen anderer Projekte zum Abrufen von Daten berücksichtigen, was zwangsläufig der Fall sein wird einen Leistungsengpass verursachen.

Einige dieser Probleme sind bereits während der Online-Fortsetzung des Projekts aufgetreten. Es ist wirklich unangenehm, dass es ab und zu zu Wartungsstillständen kommt, die zu einer lauten Ohrfeige für das Projektteam werden .

Off-Topic: Entsprechend der aktuellen Entwicklungsgeschwindigkeit des Internets und der Geschäftsausweitung verschiedener Unternehmen können Architekten die Entwicklungsrichtung des Projekts innerhalb von zwei Jahren genau vorhersagen/und vorbereiten Erweiterung im Vorfeld sind bereits sehr gut.

Jemand im Projektteam hat vorgeschlagen, das Projekt webappA und den Rest von webappB/webappC zu umgehen ... zur Interaktion direkt mit DB_A zu verbinden, aber es wurde schnell abgelehnt (Sie müssen verwenden). die Datenbankzugriffsschicht jedes Projekts muss neu definiert und geschrieben werden).

Kann die Datenbankzugriffsschicht getrennt und als Dienst verwendet werden, um den Zugriff auf autorisierte Elemente zu ermöglichen? Wie folgt:

Die Kernidee besteht darin, einer unbegrenzten Anzahl von N Zugriff auf eine bestimmte Datenbank zu ermöglichen Wabapps. Dies vermeidet nicht nur die Kopplung zwischen Projekten, sondern verbessert auch die Wiederverwendungsrate der Datenzugriffsschicht.

Sie haben bereits die Idee, fangen wir an, BB kann das Problem nicht lösen. Es dauerte ungefähr zwei Tage, es zu bauen und unzählige Löcher zu füllen, und schließlich stellte sich heraus, dass es so passend war, wie ich es erwartet hatte.

Das Originalprojekt kann aufgrund kommerzieller Nutzung nicht als Open Source bereitgestellt werden. Nachdem ich die Demo neu organisiert habe, wurde sie als Open Source bereitgestellt:

Für Schüler, die in diesem Bereich üben müssen, wird alles klar, wenn Sie es lokal klonen und lokal ausführen.

1. Service-Schnittstellenschicht

Erfordert DB_A-Datenprojektabhängigkeit dap -service-api kann auf den Dienst dao-service-impl zugreifen.

dao-service-api ist die Schnittstelle zur äußeren Schicht. Die endgültige Präsentationsmethode ist jar, und das Maven-Projekt kann direkt davon abhängen.

Wenn es alte Nicht-Maven-Projekte gibt, verwenden Sie Maven-Jar-Plugin/Maven-Assembly-Plugin, um davon abzuhängen on Die Gläser werden zusammengestellt und der Projektbibliothek hinzugefügt.

2. Service-Implementierungsschicht

dao-service-impl wird von cxf + spring + druid + jpa (hibernate impl) Open Source erstellt Klassenbibliothek Es handelt sich um einen reinen Back-End-Komponentendienst.

Als Implementierungsschicht der Serviceschnittstelle ist die endgültige Präsentationsmethode War, die im Cluster oder eingesetzt werden kann verteilt, gebend Andere Projekte bieten Dienstleistungen an.

Die Verzeichnisstruktur ist auf einen Blick klar und die Entwicklungsgeschwindigkeit ist sehr hoch. Es wurde eine einfache Codegenerierung (GenCodeServlet) implementiert, und die Schnittstellen und Implementierungen der Dao-Schicht + WebService-Schicht sind möglich automatisch generiert werden.

Die WebService-Implementierungsschicht fügt die Dao-Schicht-Schnittstelle ein und kapselt 5 Methoden zum Hinzufügen, Löschen, Ändern und Überprüfen einer einzelnen Tabelle. Im Allgemeinen besteht keine Notwendigkeit, redundante Methoden zu schreiben und das Schreiben von 90 % von SQL zu vermeiden.

@WebService
@SOAPBinding(style = SOAPBinding.Style.RPC)public interface UserWs {/** * 通过 ID 过去单个 User 实体对象
     * cxf 传输返回对象不可为null,Dao 层获取为null时
     * 实例化返回空对象,判空时使用对象主键进行判断即可
     *
     * @param id 主键ID     */UserPO getUser(String id);/** * 通过类似的 PO 获取多个 User 实体对象
     *
     * @param userPO 对照的实体对象     */List<UserPO> listUser(UserPO userPO);/** * 通过类似的 PO 获取多个 User 实体对象
     *
     * @param userPO  对照的实体对象
     * @param orderby 排序字段
     * @param asc     是否升序     */List<UserPO> listUserOrdrBy(UserPO userPO, String orderby, Boolean asc);/** * 新增 User 实体对象
     *
     * @param userPO 要新增的对象     */UserPO addUser(UserPO userPO);/** * 更新 User 实体对象
     *
     * @param userPO 要更新的对象     */UserPO updateUser(UserPO userPO);
}

Die Entwicklungsmethode ist einfach und grob. Verwenden Sie Tools, um den Ruhezustand der Datenbank umgekehrt zu generieren, und greifen Sie auf GenCodeServlet zu, um eine Dao/WS-Layer-Schnittstelle und -Implementierung zu generieren .

Konfigurationsdateioptionen hinzufügen und den cxf webService-Dienst veröffentlichen. Es dauert nicht länger als 5 Minuten.

3. Dienstaufrufer

Der veröffentlichte Einzeltabellendienst wird als Datenbankzugriffsschicht im Aufrufer verstanden, in der er angegeben ist Ihr Projekt Geschäftslogik injizieren und koppeln.

Der Zweck dieses Moduls besteht darin, zu demonstrieren, wie von cxf veröffentlichte Dienste integriert werden.

a Spring wurde in das Caller-Projekt integriert (abhängig von dao-service-api)

    <jaxws:client id="UserWs" serviceClass="com.rambo.dsd.sys.ws.inter.UserWs"  address="${cxf.server.url}/UserWs"><jaxws:outInterceptors><ref bean="wss4JOutInterceptor"/></jaxws:outInterceptors></jaxws:client>

Spezifische Verwendung (unter der Voraussetzung der Frühlingseinspritzung)

        Map<String, Object> map = new HashMap<>();
        UserWs userWs = (UserWs) SpringContextUtil.getBean("UserWs");
        UserPO user = userWs.getUser("031e7a36972e11e6acede16e8241c0fe");
        map.put("1.获取单个用户:", user);

        user.setPhone("18975468245");
        UserPO userPO1 = userWs.updateUser(user);
        map.put("2.更新单个用户:", userPO1);

        UserPO userPO2 = new UserPO();
        userPO2.setName("rambo");
        userPO2.setPasswd(SecurityUtil.encryptMD5("123456"));
        userPO2.setSex("男");
        userPO2.setYxbz("Y");
        UserPO userPO3 = userWs.addUser(userPO2);
        map.put("3.新增单个用户:", userPO3);

        UserPO userPO4 = new UserPO();
        userPO4.setSex("男");
        List<UserPO> userPOList = userWs.listUser(userPO4);
        map.put("4.获取所有的男用户:", userPOList);

        UserPO userPO5 = new UserPO();
        userPO5.setSex("男");
        List<UserPO> userPOList1 = userWs.listUserOrdrBy(userPO5, "sorts", true);
        map.put("5.获取所有的男用户并按照 sorts 字段排序:", userPOList1);return map;

b. Spring ist nicht im Caller-Projekt integriert (abhängig von dao-service-api)

Verwenden Sie Tools oder Befehle, um CXF-Service-Clients zu generieren und Factory einzuführen Modus Holen Sie sich die Dienstinstanz, in der sie verwendet wird, und koppeln Sie sie.

            UserWsImplService userWsImplService = new UserWsImplService(new URL(cxfServerUrl + "/UserWs?wsdl"));
            UserWs userWs = userWsImplService.getUserWsImplPort();
            addWSS4JOutInterceptor(userWs);

            UserPO user = userWs.getUser("031e7a36972e11e6acede16e8241c0fe");
            map.put("1.获取单个用户:", user);

            user.setPhone("18975468245");
            UserPO userPO1 = userWs.updateUser(user);
            map.put("2.更新单个用户:", userPO1);

            UserPO userPO2 = new UserPO();
            userPO2.setUuid(StringUtil.getUUID());
            userPO2.setName("rambo");
            userPO2.setPasswd(SecurityUtil.encryptMD5("123456"));
            userPO2.setSex("男");
            userPO2.setYxbz("Y");
            UserPO userPO3 = userWs.addUser(userPO2);
            map.put("3.新增单个用户:", userPO3);

            UserPO userPO4 = new UserPO();
            userPO4.setSex("男");
            UserPOArray userPOArray1 = userWs.listUser(userPO4);
            map.put("4.获取所有的男用户:", userPOArray1);

            UserPO userPO5 = new UserPO();
            userPO5.setSex("男");
            UserPOArray userPOArray2 = userWs.listUserOrdrBy(userPO5, "sorts", true);
            map.put("5.获取所有的男用户并按照 sorts 字段排序:", userPOArray2.getItem());

4. cxf-Sicherheitsauthentifizierungsmechanismus

cxf verwendet schließlich das Soap-Kommunikationsprotokoll Für Dienstleistungen ist die Sicherheit immer noch sehr wichtig.

Die Sicherheitsauthentifizierung wird in cxf ws-security wss4j-Interceptor-Implementierung eingeführt, wodurch Authentifizierungsinformationen zum Soap-Header hinzugefügt werden.

a. Serverkonfiguration

   <!--服务端安全认证回调函数--><bean id="serverAuthCallback" class="com.rambo.dsd.base.handler.CXFServerAuthHandler"/><!--安全日志认证拦截器--><bean id="wss4JInInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor"><constructor-arg><map><entry key="action" value="UsernameToken"/><entry key="passwordType" value="PasswordDigest"/><entry key="passwordCallbackRef" value-ref="serverAuthCallback"/></map></constructor-arg></bean>

Serverimplementierung javax.security Sicherheitsrückruf Funktion von .auth.callback.CallbackHandler:

public class CXFServerAuthHandler implements CallbackHandler {
    protected final static Logger log = LoggerFactory.getLogger(CXFServerAuthHandler.class);
    private static final Map<String, String> userMap = new HashMap<String, String>();

    static {
        userMap.put("webappA", "webappA2017");
        userMap.put("webappB", "webappB2017");
    }

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            WSPasswordCallback pc = (WSPasswordCallback) callback;

            String clientUsername = pc.getIdentifier();
            String serverPassword = userMap.get(clientUsername);
            log.info(" client:{} is starting webservice...", clientUsername);
            int usage = pc.getUsage();
            if (usage == WSPasswordCallback.USERNAME_TOKEN) {
                pc.setPassword(serverPassword);
            } else if (usage == WSPasswordCallback.SIGNATURE) {
                pc.setPassword(serverPassword);
            }
        }
    }
}

b. Integrieren Sie die Spring-Client-Konfiguration

    <!--客户端安全认证回调函数--><bean id="wsClientAuthHandler" class="com.rambo.dsc.handler.WsClientAuthHandler"/><!--安全认证对外拦截器--><bean id="wss4JOutInterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor"><constructor-arg><map><entry key="action" value="UsernameToken"/><entry key="user" value="webappA"/><entry key="passwordType" value="PasswordDigest"/><entry key="passwordCallbackRef" value-ref="wsClientAuthHandler"/></map></constructor-arg></bean>

Eingefügter WebService-Service-Konfigurations-Interceptor:

        <jaxws:outInterceptors><ref bean="wss4JOutInterceptor"/></jaxws:outInterceptors>

Client-Implementierung Javax Sicherheitsrückruffunktion von .security. auth.callback.CallbackHandler:

public class WsClientAuthHandler implements CallbackHandler {

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            WSPasswordCallback pc = (WSPasswordCallback) callback;
            pc.setPassword("webappA2017");
        }
    }
}

c. Codierung ohne Spring-integrierten Client

  private void addWSS4JOutInterceptor(Object wsClass) {
        Endpoint cxfEndpoint = ClientProxy.getClient(wsClass).getEndpoint();
        Map outProps = new HashMap();
        outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        outProps.put(WSHandlerConstants.USER,"webappA");
        outProps.put(WSHandlerConstants.MUST_UNDERSTAND, "0");
        outProps.put(WSHandlerConstants.PASSWORD_TYPE, "PasswordDigest");
        outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, WsClientAuthHandler.class.getName());
        cxfEndpoint.getOutInterceptors().add(new WSS4JOutInterceptor(outProps));
    }

Die serverseitige Sicherheitsauthentifizierung im Projekt verwendet UsernameToken. Natürlich können Sie auch die Sicherheitsauthentifizierungsmethode anpassen.

4. Fazit

Die Servicearchitektur von Internetunternehmen ist Blut und Gewohnheiten. Die Details sind Anders, aber die Kernkonzepte sind die gleichen.

Diese Praxis ähnelt ein wenig einem Microservice, reicht aber bei weitem nicht aus, z. B. Dienstregistrierung/Routing/Fehlertoleranz/Caching ... es gibt viele, viele und mehr Das Projekt ist Open Source, falls Sie daran interessiert sind, es gemeinsam zu perfektionieren.

Das obige ist der detaillierte Inhalt vonErstellen Sie einen Zwischendienst für den unabhängigen Datenbankzugriff. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn