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);
...
答
您有几种选择。
- 您可以明确地从您的主要方法调用
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类是从来没有端口转发运行。
但要小心,因为如果有另一个进程正在监听正在转发的端口,则此方案将失败。
我也试过,它不工作。应用程序尝试在发生之前连接到端口forwrd。并根本我编写sysout,并没有看到它在我的控制台,这意味着它不是执行此方法 – shmoolki
方法必须执行,如果你把它放在弹簧引导之前, - 只有我能想到的事情是,它可能需要一段时间来建立连接/监听器,这就是为什么它失败。你能否尝试一些阻塞,直到你知道该方法被执行并且转发已经到位? – emirb
但我写了一个sysout,它不显示在我的控制台中 – shmoolki