我们在使用flink的时候,经常会有自定义函数的时候,我们可以继承相关的richXXXFunction类,这个类里面会有open,close方法进行相关初始化和关闭的操作,那么这些方法是什么时候执行的呢?带着这个问题,我们以自定义SourceFunction为例,进行研究。
我们可以自定义source,也比较方便,extends RichSourceFunction 这个类就可以实现,下面的例子就是我们定义一个mysql的source
public class MySource extends RichSourceFunction<Student> {
PreparedStatement ps;
private Connection connection;
/**
* open() 方法中建立连接,这样不用每次 invoke 的时候都要建立连接和释放连接。
*
* @param parameters
* @throws Exception
*/
@Override
public void open(Configuration parameters) throws Exception {
super.open(parameters);
connection = getConnection();
String sql = "select * from stu;";
ps = connection.prepareStatement(sql);
}
/**
* 程序执行完毕就可以进行,关闭连接和释放资源的动作了
*
* @throws Exception
*/
@Override
public void close() throws Exception {
super.close();
if (connection != null) { //关闭连接和释放资源
connection.close();
}
if (ps != null) {
ps.close();
}
}
/**
* DataStream 调用一次 run() 方法用来获取数据
*
* @param ctx
* @throws Exception
*/
@Override
public void run(SourceContext<Student> ctx) throws Exception {
ResultSet resultSet = ps.executeQuery();
while (resultSet.next()) {
Student student =
new Student(
resultSet.getString("name"),
resultSet.getInt("age"));
ctx.collect(student);
}
}
@Override
public void cancel() {}
private static Connection getConnection() {
Connection con = null;
try {
Class.forName("com.mysql.jdbc.Driver");
con =
DriverManager.getConnection(
"jdbc:mysql://localhost:3306/hyhdb?useUnicode=true&characterEncoding=UTF-8", "root", "root");
} catch (Exception e) {
System.out.println("-----------mysql get connection has exception , msg = " + e.getMessage());
}
return con;
}
}
那么这个例子中的open和close方法什么时候执行呢?
我们可以通过源码了解到,AbstractUdfStreamOperator 这个类中的open和close方法调用的,
@Override
public void open() throws Exception {
super.open();
FunctionUtils.openFunction(userFunction, new Configuration());
}
@Override
public void close() throws Exception {
super.close();
functionsClosed = true;
FunctionUtils.closeFunction(userFunction);
}
我们可以从代码看到open和close方法里面又调用了FunctionUtils的相关方法,FunctionUtils这个类是一个工具类,里面的代码实现如下:
public static void openFunction(Function function, Configuration parameters) throws Exception {
if (function instanceof RichFunction) {
RichFunction richFunction = (RichFunction)function;
richFunction.open(parameters);
}
}
public static void closeFunction(Function function) throws Exception {
if (function instanceof RichFunction) {
RichFunction richFunction = (RichFunction)function;
richFunction.close();
}
}
我们看到FunctionUtils里的相关方法,最后判断函数是不是RichFunction类型,如果是的话,那么久调用我们自定义函数的open和close方法。
通过代码我们知道最尾端的调用过程,那么AbstractUdfStreamOperator 这个类中的open和close方法是在什么地方被调用的呢?通过源码的调用过程,我们发现StreamTask类中的
private void openAllOperators() throws Exception {
for (StreamOperator<?> operator : operatorChain.getAllOperators()) {
if (operator != null) {
operator.open();
}
}
}
private void closeAllOperators() throws Exception {
// We need to close them first to last, since upstream operators in the chain might emit
// elements in their close methods.
StreamOperator<?>[] allOperators = operatorChain.getAllOperators();
for (int i = allOperators.length - 1; i >= 0; i--) {
StreamOperator<?> operator = allOperators[i];
if (operator != null) {
operator.close();
}
}
}
我们知道我们的开发的程序,最后会转换成相应的task任务,在work上执行,那么flink的框架中,最后会调用到StreamTask,在这个类里面进行操作链的open和close方法执行。
关于操作链operatorChain的相关内容,后续进行分析