【问题标题】:Spring port Forwarding for remote database before start application启动应用程序之前远程数据库的Spring端口转发
【发布时间】:2018-03-27 16:52:34
【问题描述】:

您好,我之前在服务器上有一个需要 SSH 连接的数据库。

为此,我按照post 的说明创建隧道和端口转发。

我没有做同样的事情,但我实现了这个class(我直接创建了没有所有对话框..)

然后在我的 application.properties 中有这一行:

spring.datasource.url = jdbc:mysql://localhost:3307/my_database?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8

但是当我手动启动第一堂课时,这项工作会起作用,然后我启动我的 spring boot 应用程序。

如何在应用程序启动此类之前自动执行此操作。

那是我的 PortFrowarding 类:

    package com.demo.demo;

/* -*-mode:java; c-basic-offset:2; indent-tabs-mode:nil -*- */
/**
 * This program will demonstrate the port forwarding like option -L of
 * ssh command; the given port on the local host will be forwarded to
 * the given remote host and port on the remote side.
 *   $ CLASSPATH=.:../build javac PortForwardingL.java
 *   $ CLASSPATH=.:../build java PortForwardingL
 * You will be asked username, hostname, port:host:hostport and passwd. 
 * If everything works fine, you will get the shell prompt.
 * Try the port on localhost.
 *
 */
import com.jcraft.jsch.*;
import java.awt.*;
import javax.swing.*;

public class PortForwardingLR{
  public static void main(String[] arg){

    int lport;
    String rhost;
    int rport;

    try{
      JSch jsch=new JSch();

      String host=null;
      if(arg.length>0){
        host=arg[0];
      }
      else{
        host="demo@8.8.8.8"; 
      }
      String user=host.substring(0, host.indexOf('@'));
      host=host.substring(host.indexOf('@')+1);

      Session session=jsch.getSession(user, host, 22);

      String foo="3307:8.8.8.8:3306";
      lport=Integer.parseInt(foo.substring(0, foo.indexOf(':')));
      foo=foo.substring(foo.indexOf(':')+1);
      rhost=foo.substring(0, foo.indexOf(':'));
      rport=Integer.parseInt(foo.substring(foo.indexOf(':')+1));

      // username and password will be given via UserInfo interface.
      UserInfo ui=new MyUserInfo();
      session.setUserInfo(ui);

      session.connect();

      //Channel channel=session.openChannel("shell");
      //channel.connect();

      int assinged_port=session.setPortForwardingL(lport, rhost, rport);
      System.out.println("localhost:"+assinged_port+" -> "+rhost+":"+rport);
    }
    catch(Exception e){
      System.out.println(e);
    }
  }

  public static class MyUserInfo implements UserInfo, UIKeyboardInteractive{
    public String getPassword(){ return passwd; }
    public boolean promptYesNo(String str){
//      Object[] options={ "yes", "no" };
//      int foo=JOptionPane.showOptionDialog(null, 
//             str,
//             "Warning", 
//             JOptionPane.DEFAULT_OPTION, 
//             JOptionPane.WARNING_MESSAGE,
//             null, options, options[0]);
//       return foo==0;
        return true;
    }

    String passwd;
//    JTextField passwordField=(JTextField)new JPasswordField(20);

    public String getPassphrase(){ return null; }
    public boolean promptPassphrase(String message){ return true; }
    public boolean promptPassword(String message){
//      Object[] ob={passwordField}; 
//      int result=
//    JOptionPane.showConfirmDialog(null, ob, message,
//                  JOptionPane.OK_CANCEL_OPTION);
//      if(result==JOptionPane.OK_OPTION){
    passwd="ItsNotMyPwd";
    return true;
//      }
//      else{ return false; }
    }
    public void showMessage(String message){
      JOptionPane.showMessageDialog(null, message);
    }
    final GridBagConstraints gbc = 
      new GridBagConstraints(0,0,1,1,1,1,
                             GridBagConstraints.NORTHWEST,
                             GridBagConstraints.NONE,
                             new Insets(0,0,0,0),0,0);
    private Container panel;
    public String[] promptKeyboardInteractive(String destination,
                                              String name,
                                              String instruction,
                                              String[] prompt,
                                              boolean[] echo){
      panel = new JPanel();
      panel.setLayout(new GridBagLayout());

      gbc.weightx = 1.0;
      gbc.gridwidth = GridBagConstraints.REMAINDER;
      gbc.gridx = 0;
      panel.add(new JLabel(instruction), gbc);
      gbc.gridy++;

      gbc.gridwidth = GridBagConstraints.RELATIVE;

      JTextField[] texts=new JTextField[prompt.length];
      for(int i=0; i<prompt.length; i++){
        gbc.fill = GridBagConstraints.NONE;
        gbc.gridx = 0;
        gbc.weightx = 1;
        panel.add(new JLabel(prompt[i]),gbc);

        gbc.gridx = 1;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weighty = 1;
        if(echo[i]){
          texts[i]=new JTextField(20);
        }
        else{
          texts[i]=new JPasswordField(20);
        }
        panel.add(texts[i], gbc);
        gbc.gridy++;
      }

      if(JOptionPane.showConfirmDialog(null, panel, 
                                       destination+": "+name,
                                       JOptionPane.OK_CANCEL_OPTION,
                                       JOptionPane.QUESTION_MESSAGE)
         ==JOptionPane.OK_OPTION){
        String[] response=new String[prompt.length];
        for(int i=0; i<prompt.length; i++){
          response[i]=texts[i].getText();
        }
    return response;
      }
      else{
        return null;  // cancel
      }
    }
  }
}

我试图在应用程序像这样运行之前启动此方法,但它不起作用:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class SymspringdemoApplication {

    public static void main(String[] args) {
        someMethodThatDoesForwarding();
        SpringApplication.run(SymspringdemoApplication.class, args);
    }

    private static void someMethodThatDoesForwarding() {

        PortForwardingLR.main(null);;

    }
}

谢谢。

【问题讨论】:

    标签: java mysql spring spring-mvc ssh


    【解决方案1】:

    如果您实际上发布了自己的代码,会更容易帮助/理解,但是如果您想在 Spring 启动它自己的引导之前建立端口转发,只需在 Spring 开始创建 bean 之前执行代码(最终与 DB 相关豆子)。

    例如:

    ...
        /* Execute your custom port-forwarding here */
        someMethodThatDoesForwarding();
        /* SpringBoot code continues.. */
        SpringApplication.run(DemoApplication.class, args);
    ...
    

    【讨论】:

    • 我也试过了,但它不起作用。该应用程序尝试在它发生之前连接到端口转发。而且我写了 sysout 并且在我的控制台中看不到它,这意味着它没有执行这个方法
    • 如果将方法放在 Springs 引导之前,则必须执行该方法,-我认为 f 可能需要一段时间才能建立连接/侦听器,这就是它失败的原因。在您知道方法已执行并且转发到位之前,您可以尝试一些阻塞吗?
    • 但是我写了一个系统输出,但它没有显示在我的控制台中
    【解决方案2】:

    您有多种选择。

    • 您可以在 main 方法中显式调用 PortForwardingLR.main()
    • 您可以使用 shell 脚本/批处理文件在您的程序之前调用您的PortForwardingLR。您也可以使用 OpenSSH 进行端口转发。
    • 您可以让PortForwardingLR.main() 调用您的主方法。

    在我看来,最好将PortForwardingLR 中的代码修改为两种方法:一种用于打开连接,另一种用于关闭连接。目标是拥有这样的东西:

    class MyDatabaseWorker {
        public void run() {
            // Do stuff here
        }
    
        public static void main(String[] args) {
            PortForwardingLR forwarder = new PortForwardingLR(hostname, user, password);
            forwarder.addPortForward(3306);
            forwarder.connect();
            MyDatabaseWorker worker = new MyDatabaseWorker();
            worker.run();
            forwarder.disconnect();
        }
    }
    

    这样,您可以为不同的项目重用 PortForwardingLR 类,您的 DB 类的污染最小,并确保您的 DB 类永远不会在没有端口转发的情况下运行。

    不过要小心,因为如果有另一个进程正在侦听您要转发到的端口,这种情况将会失败。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-19
      • 2015-04-19
      • 1970-01-01
      • 1970-01-01
      • 2017-04-14
      • 2011-02-26
      • 1970-01-01
      • 2014-10-13
      相关资源
      最近更新 更多