// 调度中心注册表会否为空

if (XxlJobExecutor.getAdminBizList() == null) {

logger.warn(“>>>>>>>>>>> xxl-job, executor callback config fail, adminAddresses is null.”);

return;

}

// callback

triggerCallbackThread = new Thread(new Runnable() {

@Override

public void run() {

// 监听阻塞队列

while(!toStop){

try {

HandleCallbackParam callback = getInstance().callBackQueue.take();

if (callback != null) {

// 组装callback返回的参数

List<HandleCallbackParam> callbackParamList = new ArrayList<HandleCallbackParam>();

int drainToNum = getInstance().callBackQueue.drainTo(callbackParamList);

callbackParamList.add(callback);

// 执行回调

if (callbackParamList!=null && callbackParamList.size()>0) {

doCallback(callbackParamList);

}

}

} catch (Exception e) {

if (!toStop) {

logger.error(e.getMessage(), e);

}

}

}

// last callback

try {

List<HandleCallbackParam> callbackParamList = new ArrayList<HandleCallbackParam>();

int drainToNum = getInstance().callBackQueue.drainTo(callbackParamList);

if (callbackParamList!=null && callbackParamList.size()>0) {

doCallback(callbackParamList);

}

} catch (Exception e) {

if (!toStop) {

logger.error(e.getMessage(), e);

}

}

logger.info(“>>>>>>>>>>> xxl-job, executor callback thread destory.”);

}

});

triggerCallbackThread.setDaemon(true);

triggerCallbackThread.setName(“xxl-job, executor TriggerCallbackThread”);

triggerCallbackThread.start();

// retry

triggerRetryCallbackThread = new Thread(new Runnable() {

@Override

public void run() {

while(!toStop){

try {

retryFailCallbackFile();

} catch (Exception e) {

if (!toStop) {

logger.error(e.getMessage(), e);

}

}

try {

TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);

} catch (InterruptedException e) {

if (!toStop) {

logger.error(e.getMessage(), e);

}

}

}

logger.info(“>>>>>>>>>>> xxl-job, executor retry callback thread destory.”);

}

});

triggerRetryCallbackThread.setDaemon(true);

triggerRetryCallbackThread.start();

}

doCallback(callbackParamList)如下

/**
  • do callback, will retry if error

  • @param callbackParamList

*/

private void doCallback(List<HandleCallbackParam> callbackParamList){

boolean callbackRet = false;

// 向所有的调度中心发送回调信息

for (AdminBiz adminBiz: XxlJobExecutor.getAdminBizList()) {

try {

//本质上是调用注册中心的api/callback接口。记录调用结果。

ReturnT<String> callbackResult = adminBiz.callback(callbackParamList);

if (callbackResult!=null && ReturnT.SUCCESS_CODE == callbackResult.getCode()) {

callbackLog(callbackParamList, “<br>----------- xxl-job job callback finish.”);

callbackRet = true;

break;

} else {

callbackLog(callbackParamList, “<br>----------- xxl-job job callback fail, callbackResult:” + callbackResult);

}

} catch (Exception e) {

callbackLog(callbackParamList, “<br>----------- xxl-job job callback error, errorMsg:” + e.getMessage());

}

}

if (!callbackRet) {

appendFailCallbackFile(callbackParamList);

}

}

adminBiz.callback(callbackParamList)

调用注册中心api接口

@Override

public ReturnT<String> callback(List<HandleCallbackParam> callbackParamList) {

return XxlJobRemotingUtil.postBody(addressUrl+“api/callback”, accessToken, timeout, callbackParamList, String.class);

}

initAdminBizList( adminAddresses, accessToken); 初始化注册中心列表,用于后期和注册中心交互

//扫描xxl.job.admin.addresses配置,将他们加入注册中心列表adminBizList对象中。用于后期发送回调

private void initAdminBizList(String adminAddresses, String accessToken) throws Exception {

if (adminAddresses!=null && adminAddresses.trim().length()>0) {

for (String address: adminAddresses.trim().split(“,”)) {

if (address!=null && address.trim().length()>0) {

AdminBiz adminBiz = new AdminBizClient(address.trim(), accessToken);

if (adminBizList == null) {

adminBizList = new ArrayList<AdminBiz>();

}

adminBizList.add(adminBiz);

}

}

}

}

// init executor-server

initEmbedServer(address, ip, port, appname, accessToken);<核心>

//初始化xxljob执行器服务

private void initEmbedServer(String address, String ip, int port, String appname, String accessToken) throws Exception {

//初始化ip和端口,如果没有ip则自动获取本地ip

port = port>0?port: NetUtil.findAvailablePort(9999);

ip = (ip!=null&&ip.trim().length()>0)?ip: IpUtil.getIp();

// generate address

if (address==null || address.trim().length()==0) {

String ip_port_address = IpUtil.getIpPort(ip, port); // registry-address:default use address to registry , otherwise use ip:port if address is null

address = “http://{ip_port}/”.replace(“{ip_port}”, ip_port_address);

}

// 启动服务

embedServer = new EmbedServer();

embedServer.start(address, port, appname, accessToken);

}

embedServer.start(address, port, appname, accessToken); 本质上是一个Netty服务,标准的Netty服务启动,我们只看EmbedHttpServerHandler,Netty处理请求的handler

public void start(final String address, final int port, final String appname, final String accessToken) {

executorBiz = new ExecutorBizImpl();

thread = new Thread(new Runnable() {

@Override

public void run() {

// param

EventLoopGroup bossGroup = new NioEventLoopGroup();

EventLoopGroup workerGroup = new NioEventLoopGroup();

ThreadPoolExecutor bizThreadPool = new ThreadPoolExecutor(

0,

200,

60L,

TimeUnit.SECONDS,

new LinkedBlockingQueue<Runnable>(2000),

new ThreadFactory() {

@Override

public Thread newThread(Runnable r) {

return new Thread(r, “xxl-rpc, EmbedServer bizThreadPool-” + r.hashCode());

}

},

new RejectedExecutionHandler() {

@Override

public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {

throw new RuntimeException(“xxl-job, EmbedServer bizThreadPool is EXHAUSTED!”);

}

});

try {

// start server

ServerBootstrap bootstrap = new ServerBootstrap();

bootstrap.group(bossGroup, workerGroup)

.channel(NioServerSocketChannel.class)

.childHandler(new ChannelInitializer<SocketChannel>() {

@Override

public void initChannel(SocketChannel channel) throws Exception {

channel.pipeline()

.addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS)) // beat 3N, close if idle

.addLast(new HttpServerCodec())

.addLast(new HttpObjectAggregator(5 * 1024 * 1024)) // merge request & reponse to FULL

.addLast(new EmbedHttpServerHandler(executorBiz, accessToken, bizThreadPool));

}

})

.childOption(ChannelOption.SO_KEEPALIVE, true);

// bind

ChannelFuture future = bootstrap.bind(port).sync();

logger.info(“>>>>>>>>>>> xxl-job remoting server start success, nettype = {}, port = {}”, EmbedServer.class, port);

//注册到调度中心

startRegistry(appname, address);

// wait util stop

future.channel().closeFuture().sync();

} catch (InterruptedException e) {

if (e instanceof InterruptedException) {

logger.info(“>>>>>>>>>>> xxl-job remoting server stop.”);

} else {

logger.error(“>>>>>>>>>>> xxl-job remoting server error.”, e);

}

} finally {

// stop

try {

workerGroup.shutdownGracefully();

bossGroup.shutdownGracefully();

} catch (Exception e) {

logger.error(e.getMessage(), e);

}

}

}

});

thread.setDaemon(true); // daemon, service jvm, user thread leave >>> daemon leave >>> jvm leave

thread.start();

}

public static class EmbedHttpServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

private static final Logger logger = LoggerFactory.getLogger(EmbedHttpServerHandler.class);

private ExecutorBiz executorBiz; //执行器

private String accessToken; //token

private ThreadPoolExecutor bizThreadPool;//执行器线程池

public EmbedHttpServerHandler(ExecutorBiz executorBiz, String accessToken, ThreadPoolExecutor bizThreadPool) {

this.executorBiz = executorBiz;

this.accessToken = accessToken;

this.bizThreadPool = bizThreadPool;

}

@Override

protected void channelRead0(final ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {

// request parse

//final byte[] requestBytes = ByteBufUtil.getBytes(msg.content()); // byteBuf.toString(io.netty.util.CharsetUtil.UTF_8);

String requestData = msg.content().toString(CharsetUtil.UTF_8);//获取请求数据

String uri = msg.uri();

HttpMethod httpMethod = msg.method();

boolean keepAlive = HttpUtil.isKeepAlive(msg);

String accessTokenReq = msg.headers().get(XxlJobRemotingUtil.XXL_JOB_ACCESS_TOKEN);

// invoke

bizThreadPool.execute(new Runnable() {

@Override

public void run() {

// 处理请求

Object responseObj = process(httpMethod, uri, requestData, accessTokenReq);

// 格式化为JSON

String responseJson = GsonTool.toJson(responseObj);

// 写回客户端

writeResponse(ctx, keepAlive, responseJson);

}

});

}

private Object process(HttpMethod httpMethod, String uri, String requestData, String accessTokenReq) {

// valid

if (HttpMethod.POST != httpMethod) {

return new ReturnT<String>(ReturnT.FAIL_CODE, “invalid request, HttpMethod not support.”);

}

if (uri==null || uri.trim().length()==0) {

return new ReturnT<String>(ReturnT.FAIL_CODE, “invalid request, uri-mapping empty.”);

}

if (accessToken!=null

&& accessToken.trim().length()>0

&& !accessToken.equals(accessTokenReq)) {

return new ReturnT<String>(ReturnT.FAIL_CODE, “The access token is wrong.”);

}

// services mapping

try {

//接收注册中心请求接口处理

if (“/beat”.equals(uri)) {

return executorBiz.beat();

} else if (“/idleBeat”.equals(uri)) {

IdleBeatParam idleBeatParam = GsonTool.fromJson(requestData, IdleBeatParam.class);

return executorBiz.idleBeat(idleBeatParam);

} else if (“/run”.equals(uri)) { //注册中心执行接口

TriggerParam triggerParam = GsonTool.fromJson(requestData, TriggerParam.class);

return executorBiz.run(triggerParam);

} else if (“/kill”.equals(uri)) {

KillParam killParam = GsonTool.fromJson(requestData, KillParam.class);

return executorBiz.kill(killParam);

} else if (“/log”.equals(uri)) {

LogParam logParam = GsonTool.fromJson(requestData, LogParam.class);

return executorBiz.log(logParam);

} else {

return new ReturnT<String>(ReturnT.FAIL_CODE, “invalid request, uri-mapping(”+ uri +“) not found.”);

}

} catch (Exception e) {

logger.error(e.getMessage(), e);

return new ReturnT<String>(ReturnT.FAIL_CODE, “request error:” + ThrowableUtil.toString(e));

}

}

我们主要看下run方法的执行过程

@Override

public ReturnT<String> run(TriggerParam triggerParam) {

// 根据jobid加载对应的job执行信息,第一次执行为null

JobThread jobThread = XxlJobExecutor.loadJobThread(triggerParam.getJobId());

IJobHandler jobHandler = jobThread!=null?jobThread.getHandler():null;//根绝jobThread获取job处理handler

String removeOldReason = null;

// valid:jobHandler + jobThread

GlueTypeEnum glueTypeEnum = GlueTypeEnum.match(triggerParam.getGlueType()); //获取任务类型

if (GlueTypeEnum.BEAN == glueTypeEnum) {

// new jobhandler

IJobHandler newJobHandler = XxlJobExecutor.loadJobHandler(triggerParam.getExecutorHandler());//获取任务的执行器

// 校验新老job是否一致,不一致将老的进行初始化。有可能任务更新。通过jobid获取的是老的

if (jobThread!=null && jobHandler != newJobHandler) {

// change handler, need kill old thread

removeOldReason = “change jobhandler or glue type, and terminate the old job thread.”;

jobThread = null;

jobHandler = null;

}

// valid handler

if (jobHandler == null) {

jobHandler = newJobHandler; //将新处理handler赋值给老的

if (jobHandler == null) {

return new ReturnT<String>(ReturnT.FAIL_CODE, “job handler [” + triggerParam.getExecutorHandler() + “] not found.”);

}

}

} else if (GlueTypeEnum.GLUE_GROOVY == glueTypeEnum) {

// valid old jobThread

if (jobThread != null &&

!(jobThread.getHandler() instanceof GlueJobHandler

&& ((GlueJobHandler) jobThread.getHandler()).getGlueUpdatetime()==triggerParam.getGlueUpdatetime() )) {

// change handler or gluesource updated, need kill old thread

removeOldReason = “change job source or glue type, and terminate the old job thread.”;

jobThread = null;

jobHandler = null;

}

if (jobHandler == null) {

try {

IJobHandler originJobHandler = GlueFactory.getInstance().loadNewInstance(triggerParam.getGlueSource());

jobHandler = new GlueJobHandler(originJobHandler, triggerParam.getGlueUpdatetime());

} catch (Exception e) {

logger.error(e.getMessage(), e);

return new ReturnT<String>(ReturnT.FAIL_CODE, e.getMessage());

}

}

} else if (glueTypeEnum!=null && glueTypeEnum.isScript()) {

// valid old jobThread

if (jobThread != null &&

!(jobThread.getHandler() instanceof ScriptJobHandler

&& ((ScriptJobHandler) jobThread.getHandler()).getGlueUpdatetime()==triggerParam.getGlueUpdatetime() )) {

// change script or gluesource updated, need kill old thread

removeOldReason = “change job source or glue type, and terminate the old job thread.”;

jobThread = null;

jobHandler = null;

}

// valid handler

if (jobHandler == null) {

jobHandler = new ScriptJobHandler(triggerParam.getJobId(), triggerParam.getGlueUpdatetime(), triggerParam.getGlueSource(), GlueTypeEnum.match(triggerParam.getGlueType()));

}

} else {

return new ReturnT<String>(ReturnT.FAIL_CODE, “glueType[” + triggerParam.getGlueType() + “] is not valid.”);

}

// executor block strategy

if (jobThread != null) {

ExecutorBlockStrategyEnum blockStrategy = ExecutorBlockStrategyEnum.match(triggerParam.getExecutorBlockStrategy(), null);

if (ExecutorBlockStrategyEnum.DISCARD_LATER == blockStrategy) {

// discard when running

if (jobThread.isRunningOrHasQueue()) {

return new ReturnT<String>(ReturnT.FAIL_CODE, “block strategy effect:”+ExecutorBlockStrategyEnum.DISCARD_LATER.getTitle());

}

} else if (ExecutorBlockStrategyEnum.COVER_EARLY == blockStrategy) {

// kill running jobThread

if (jobThread.isRunningOrHasQueue()) {

removeOldReason = “block strategy effect:” + ExecutorBlockStrategyEnum.COVER_EARLY.getTitle();

jobThread = null;

}

} else {

// just queue trigger

}

}

// 如果jobThread 为null,则将任务信息注册到jobThreadRepository对象进行缓存,并启动线程

if (jobThread == null) {

jobThread = XxlJobExecutor.registJobThread(triggerParam.getJobId(), jobHandler, removeOldReason);

}

//将任务推送到自己现成的任务队列中区

ReturnT<String> pushResult = jobThread.pushTriggerQueue(triggerParam);

return pushResult;

}

看下registJobThread方法,该方法主要是根据任务信息,创建一个jobThread,之后启动该线程。然后将其缓存到jobThreadRepository中。如果存在老的任务,则将老的任务停掉。

private static ConcurrentMap<Integer, JobThread> jobThreadRepository = new ConcurrentHashMap<Integer, JobThread>();

public static JobThread registJobThread(int jobId, IJobHandler handler, String removeOldReason){

JobThread newJobThread = new JobThread(jobId, handler);//创建新得jobThread对象

newJobThread.start();//启动线程

logger.info(“>>>>>>>>>>> xxl-job regist JobThread success, jobId:{}, handler:{}”, new Object[]{jobId, handler});

//将新的jobThread放入map中,并弹出老的。

JobThread oldJobThread = jobThreadRepository.put(jobId, newJobThread); // putIfAbsent | oh my god, map’s put method return the old value!!!

if (oldJobThread != null) {

//将老的停掉

oldJobThread.toStop(removeOldReason);

oldJobThread.interrupt();

}

return newJobThread;

}

该线程执行如下,主要就是获取队列中的任务,然后通过新建FutureTask线程执行任务。之后将执行结果推到TriggerCallbackThread的队列中。通过TriggerCallbackThread推到任务调度中心,进行记录结果信息。

 @Override

public void run() {

// init

try {

handler.init();

} catch (Throwable e) {

logger.error(e.getMessage(), e);

}

// execute

while(!toStop){

running = false;

idleTimes++;

TriggerParam triggerParam = null;

ReturnT<String> executeResult = null;

try {

// to check toStop signal, we need cycle, so wo cannot use queue.take(), instand of poll(timeout)

//弹出队列任务

triggerParam = triggerQueue.poll(3L, TimeUnit.SECONDS);

if (triggerParam!=null) {

running = true;

idleTimes = 0;

triggerLogIdSet.remove(triggerParam.getLogId());

// log filename, like “logPath/yyyy-MM-dd/9999.log”

String logFileName = XxlJobFileAppender.makeLogFileName(new Date(triggerParam.getLogDateTime()), triggerParam.getLogId());

XxlJobContext.setXxlJobContext(new XxlJobContext(

triggerParam.getLogId(),

logFileName,

triggerParam.getBroadcastIndex(),

triggerParam.getBroadcastTotal()));

// execute

XxlJobLogger.log(“<br>----------- xxl-job job execute start -----------<br>----------- Param:” + triggerParam.getExecutorParams());

if (triggerParam.getExecutorTimeout() > 0) {

// limit timeout

Thread futureThread = null;

try {

final TriggerParam triggerParamTmp = triggerParam;

//创建futureTask线程任务,并执行

FutureTask<ReturnT<String>> futureTask = new FutureTask<ReturnT<String>>(new Callable<ReturnT<String>>() {

@Override

public ReturnT<String> call() throws Exception {

return handler.execute(triggerParamTmp.getExecutorParams());

}

});

futureThread = new Thread(futureTask);

futureThread.start();

//获取执行结果

executeResult = futureTask.get(triggerParam.getExecutorTimeout(), TimeUnit.SECONDS);

} catch (TimeoutException e) {

XxlJobLogger.log(“<br>----------- xxl-job job execute timeout”);

XxlJobLogger.log(e);

executeResult = new ReturnT<String>(IJobHandler.FAIL_TIMEOUT.getCode(), "job execute timeout ");

} finally {

futureThread.interrupt();

}

} else {

// just execute

executeResult = handler.execute(triggerParam.getExecutorParams());

}

if (executeResult == null) {

executeResult = IJobHandler.FAIL;

} else {

executeResult.setMsg(

(executeResult!=null&&executeResult.getMsg()!=null&&executeResult.getMsg().length()>50000)

?executeResult.getMsg().substring(0, 50000).concat(“…”)

:executeResult.getMsg());

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

最后

分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。

面试经验技巧篇
  • 经验技巧1 如何巧妙地回答面试官的问题
  • 经验技巧2 如何回答技术性的问题
  • 经验技巧3 如何回答非技术性问题
  • 经验技巧4 如何回答快速估算类问题
  • 经验技巧5 如何回答算法设计问题
  • 经验技巧6 如何回答系统设计题
  • 经验技巧7 如何解决求职中的时间冲突问题
  • 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
  • 经验技巧9 在被企业拒绝后是否可以再申请
  • 经验技巧10 如何应对自己不会回答的问题
  • 经验技巧11 如何应对面试官的“激将法”语言
  • 经验技巧12 如何处理与面试官持不同观点这个问题
  • 经验技巧13 什么是职场暗语

面试真题篇
  • 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
  • 真题详解2 某知名社交平台软件工程师笔试题
  • 真题详解3 某知名安全软件服务提供商软件工程师笔试题
  • 真题详解4 某知名互联网金融企业软件工程师笔试题
  • 真题详解5 某知名搜索引擎提供商软件工程师笔试题
  • 真题详解6 某初创公司软件工程师笔试题
  • 真题详解7 某知名游戏软件开发公司软件工程师笔试题
  • 真题详解8 某知名电子商务公司软件工程师笔试题
  • 真题详解9 某顶级生活消费类网站软件工程师笔试题
  • 真题详解10 某知名门户网站软件工程师笔试题
  • 真题详解11 某知名互联网金融企业软件工程师笔试题
  • 真题详解12 国内某知名网络设备提供商软件工程师笔试题
  • 真题详解13 国内某顶级手机制造商软件工程师笔试题
  • 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
  • 真题详解15 某著名社交类上市公司软件工程师笔试题
  • 真题详解16 某知名互联网公司软件工程师笔试题
  • 真题详解17 某知名网络安全公司校园招聘技术类笔试题
  • 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题

资料整理不易,点个关注再走吧

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。

面试经验技巧篇
  • 经验技巧1 如何巧妙地回答面试官的问题
  • 经验技巧2 如何回答技术性的问题
  • 经验技巧3 如何回答非技术性问题
  • 经验技巧4 如何回答快速估算类问题
  • 经验技巧5 如何回答算法设计问题
  • 经验技巧6 如何回答系统设计题
  • 经验技巧7 如何解决求职中的时间冲突问题
  • 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
  • 经验技巧9 在被企业拒绝后是否可以再申请
  • 经验技巧10 如何应对自己不会回答的问题
  • 经验技巧11 如何应对面试官的“激将法”语言
  • 经验技巧12 如何处理与面试官持不同观点这个问题
  • 经验技巧13 什么是职场暗语

[外链图片转存中…(img-XQujMS11-1712815154020)]

面试真题篇
  • 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
  • 真题详解2 某知名社交平台软件工程师笔试题
  • 真题详解3 某知名安全软件服务提供商软件工程师笔试题
  • 真题详解4 某知名互联网金融企业软件工程师笔试题
  • 真题详解5 某知名搜索引擎提供商软件工程师笔试题
  • 真题详解6 某初创公司软件工程师笔试题
  • 真题详解7 某知名游戏软件开发公司软件工程师笔试题
  • 真题详解8 某知名电子商务公司软件工程师笔试题
  • 真题详解9 某顶级生活消费类网站软件工程师笔试题
  • 真题详解10 某知名门户网站软件工程师笔试题
  • 真题详解11 某知名互联网金融企业软件工程师笔试题
  • 真题详解12 国内某知名网络设备提供商软件工程师笔试题
  • 真题详解13 国内某顶级手机制造商软件工程师笔试题
  • 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
  • 真题详解15 某著名社交类上市公司软件工程师笔试题
  • 真题详解16 某知名互联网公司软件工程师笔试题
  • 真题详解17 某知名网络安全公司校园招聘技术类笔试题
  • 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题

[外链图片转存中…(img-gWlTX6C0-1712815154020)]

资料整理不易,点个关注再走吧

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-CpivlRQS-1712815154021)]

GitHub 加速计划 / xx / xxl-job
27.16 K
10.79 K
下载
xxl-job: 是一个分布式任务调度平台,核心设计目标是开发迅速、学习简单、轻量级、易扩展。
最近提交(Master分支:3 个月前 )
e5d26ba2 - 4 个月前
977ad87b - 4 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐