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

问题描述:

嗨我在服务器上有一个需要SSH连接的数据库。Spring端口在启动应用程序之前转发远程数据库

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

我没有做相同的,但我实现这个class(我directely创建,无需所有对话框..)

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

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

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

我应该怎么做,自动启动这个类的应用程序之前是instanciate。

这是我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="[email protected]"; 
     } 
     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);; 

    } 
} 

谢谢。

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

例如为:

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

我也试过,它不工作。应用程序尝试在发生之前连接到端口forwrd。并根本我编写sysout,并没有看到它在我的控制台,这意味着它不是执行此方法 – shmoolki

+0

方法必须执行,如果你把它放在弹簧引导之前, - 只有我能想到的事情是,它可能需要一段时间来建立连接/监听器,这就是为什么它失败。你能否尝试一些阻塞,直到你知道该方法被执行并且转发已经到位? – emirb

+0

但我写了一个sysout,它不显示在我的控制台中 – shmoolki

您有几种选择。

  • 您可以明确地从您的主要方法调用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类是从来没有端口转发运行。

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