Spring端口在启动应用程序之前转发远程数据库

时间:2017-10-16 08:11:48

标签: java mysql spring spring-mvc ssh

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

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

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

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

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

但是当我手动启动第一个类时,这个工作,然后我启动我的春季启动应用程序。

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

那是我的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);;

    }
}

感谢。

2 个答案:

答案 0 :(得分:1)

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

E.g:

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

答案 1 :(得分:1)

您有几种选择。

  • 您可以从主要方法中明确调用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类,您的数据库类受到最低程度的污染,并确保您的数据库类永远不会在没有端口转发的情况下运行。

但要小心,因为如果有另一个进程监听您要转发的端口,则此方案将失败。