先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
正文
private void init() {
if (initialized) {
return;
}
initialized = true;
if (interfaceName == null ||interfaceName.length() == 0) {
throw new IllegalStateException(“<dubbo:reference interface=”" />interface not allow null!");
}
// 获取消费者全局配置
checkDefault();
appendProperties(this);
if (getGeneric() == null &&getConsumer() != null) {
setGeneric(getConsumer().getGeneric());
}
if(ProtocolUtils.isGeneric(getGeneric())) {
interfaceClass =GenericService.class;
} else {
try {
interfaceClass =Class.forName(interfaceName, true, Thread.currentThread()
.getContextClassLoader());
} catch (ClassNotFoundException e){
throw newIllegalStateException(e.getMessage(), e);
}
checkInterfaceAndMethods(interfaceClass, methods);
}
String resolve =System.getProperty(interfaceName);
String resolveFile = null;
if (resolve == null || resolve.length()== 0) {
resolveFile =System.getProperty(“dubbo.resolve.file”);
if (resolveFile == null ||resolveFile.length() == 0) {
File userResolveFile = newFile(new File(System.getProperty(“user.home”)),“dubbo-resolve.properties”);
if (userResolveFile.exists()) {
resolveFile =userResolveFile.getAbsolutePath();
}
}
if (resolveFile != null &&resolveFile.length() > 0) {
Properties properties = newProperties();
FileInputStream fis = null;
try {
fis = newFileInputStream(new File(resolveFile));
properties.load(fis);
} catch (IOException e) {
throw new IllegalStateException("Unload " + resolveFile + ", cause: "+ e.getMessage(), e);
} finally {
try {
if (null != fis)fis.close();
} catch (IOException e) {
logger.warn(e.getMessage(), e);
}
}
resolve =properties.getProperty(interfaceName);
}
}
if (resolve != null &&resolve.length() > 0) {
url = resolve;
if (logger.isWarnEnabled()) {
if (resolveFile != null&& resolveFile.length() > 0) {
logger.warn(“Usingdefault dubbo resolve file " + resolveFile + " replace " +interfaceName + “” + resolve + " to p2p invoke remoteservice.”);
} else {
logger.warn(“Using-D” + interfaceName + “=” + resolve + " to p2p invokeremote service.");
}
}
}
if (consumer != null) {
if (application == null){
application =consumer.getApplication();
}
if (module == null) {
module = consumer.getModule();
}
if (registries == null) {
registries =consumer.getRegistries();
}
if (monitor == null) {
monitor =consumer.getMonitor();
}
}
if (module != null) {
if (registries == null) {
registries = module.getRegistries();
}
if (monitor == null) {
monitor = module.getMonitor();
}
}
if (application != null) {
if (registries == null) {
registries =application.getRegistries();
}
if (monitor == null) {
monitor =application.getMonitor();
}
}
checkApplication();
checkStubAndMock(interfaceClass);
Map<String, String> map = new HashMap<String, String>();
Map<Object, Object> attributes =new HashMap<Object, Object>();
map.put(Constants.SIDE_KEY,Constants.CONSUMER_SIDE);
map.put(Constants.DUBBO_VERSION_KEY,Version.getVersion());
map.put(Constants.TIMESTAMP_KEY,String.valueOf(System.currentTimeMillis()));
if (ConfigUtils.getPid() > 0) {
map.put(Constants.PID_KEY,String.valueOf(ConfigUtils.getPid()));
}
if (!isGeneric()) {
String revision =Version.getVersion(interfaceClass, version);
if (revision != null &&revision.length() > 0) {
map.put(“revision”,revision);
}
String[] methods =Wrapper.getWrapper(interfaceClass).getMethodNames();
if (methods.length == 0) {
logger.warn("NO method found in service interface " + interfaceClass.getName());
map.put(“methods”,Constants.ANY_VALUE);
} else {
map.put(“methods”,StringUtils.join(new HashSet(Arrays.asList(methods)),“,”));
}
}
map.put(Constants.INTERFACE_KEY,interfaceName);
appendParameters(map, application);
appendParameters(map, module);
appendParameters(map, consumer,Constants.DEFAULT_KEY);
appendParameters(map, this);
String prifix =StringUtils.getServiceKey(map);
if (methods != null &&methods.size() > 0) {
for (MethodConfig method : methods){
appendParameters(map, method,method.getName());
String retryKey =method.getName() + “.retry”;
if (map.containsKey(retryKey)){
String retryValue =map.remove(retryKey);
if (“false”.equals(retryValue)) {
map.put(method.getName() + “.retries”, “0”);
}
}
appendAttributes(attributes,method, prifix + “.” + method.getName());
checkAndConvertImplicitConfig(method,map, attributes);
}
}
//attributes通过系统context进行存储.
StaticContext.getSystemContext().putAll(attributes);
ref = createProxy(map);
}
基本意思就是集成各种配置,比如类名、方法、版本等等,组成一个map,最终通过createProxy()方法生成代理类,createProxy()方法的代码如下:
@SuppressWarnings({“unchecked”, “rawtypes”,“deprecation”})
private T createProxy(Map<String, String> map) {
URL tmpUrl = new URL(“temp”,“localhost”, 0, map);
final boolean isJvmRefer;
if (isInjvm() == null) {
if (url != null &&url.length() > 0) { //指定URL的情况下,不做本地引用
isJvmRefer = false;
} else if(InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl)) {
//默认情况下如果本地有服务暴露,则引用本地服务.
isJvmRefer = true;
} else {
isJvmRefer = false;
}
} else {
isJvmRefer =isInjvm().booleanValue();
}
if (isJvmRefer) {
URL url = new URL(Constants.LOCAL_PROTOCOL,NetUtils.LOCALHOST, 0, interfaceClass.getName()).addParameters(map);
invoker =refprotocol.refer(interfaceClass, url);
if (logger.isInfoEnabled()) {
logger.info("Using injvmservice " + interfaceClass.getName());
}
} else {
if (url != null &&url.length() > 0) { // 用户指定URL,指定的URL可能是对点对直连地址,也可能是注册中心URL
String[] us =Constants.SEMICOLON_SPLIT_PATTERN.split(url);
if (us != null &&us.length > 0) {
for (String u : us) {
URL url =URL.valueOf(u);
if (url.getPath() ==null || url.getPath().length() == 0) {
url =url.setPath(interfaceName);
}
if(Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
urls.add(url.addParameterAndEncoded(Constants.REFER_KEY,StringUtils.toQueryString(map)));
} else {
urls.add(ClusterUtils.mergeUrl(url, map));
}
}
}
} else { // 通过注册中心配置拼装URL
List us =loadRegistries(false);
if (us != null &&us.size() > 0) {
for (URL u : us) {
URL monitorUrl =loadMonitor(u);
if (monitorUrl != null){
map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
}
urls.add(u.addParameterAndEncoded(Constants.REFER_KEY,StringUtils.toQueryString(map)));
}
}
if (urls == null || urls.size()== 0) {
throw newIllegalStateException(“No such any registry to reference " +interfaceName + " on the consumer " + NetUtils.getLocalHost() +” use dubbo version " + Version.getVersion() + “, please config<dubbo:registry address=”…" /> to your springconfig.");
}
}
if (urls.size() == 1) {
invoker =refprotocol.refer(interfaceClass, urls.get(0));
} else {
List<Invoker<?>>invokers = new ArrayList
URL registryURL =null;
for (URL url : urls) {
invokers.add(refprotocol.refer(interfaceClass, url));
if(Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
registryURL = url; // 用了最后一个registryurl
}
}
if (registryURL != null) { // 有 注册中心协议的URL
// 对有注册中心的Cluster只用 AvailableCluster
URL u = registryURL.addParameter(Constants.CLUSTER_KEY,AvailableCluster.NAME);
invoker = cluster.join(new StaticDirectory(u, invokers));
} else { // 不是 注册中心的URL
invoker = cluster.join(new StaticDirectory(invokers));
}
}
}
Boolean c = check;
if (c == null && consumer !=null) {
c = consumer.isCheck();
}
if (c == null) {
c = true; // default true
}
if (c && !invoker.isAvailable()){
throw new IllegalStateException("Failed to check the status of the service " +interfaceName + “. No provider available for the service " + (group== null ? “” : group + “/”) + interfaceName + (version ==null ? “” : “:” + version) + " from the url " +invoker.getUrl() + " to the consumer " + NetUtils.getLocalHost() +” use dubbo version " + Version.getVersion());
}
if (logger.isInfoEnabled()) {
logger.info("Refer dubboservice " + interfaceClass.getName() + " from url " +invoker.getUrl());
}
// 创建服务代理
return (T)proxyFactory.getProxy(invoker);
}
一开始调用isInjvm()方法判断目标接口是否在本地就有,如果本地就有,直接调用本地的接口。
如果本地没有,就在配置中找有没有用户指定的url,如果指定了就使用用户指定的url提供的接口。
如果没有指定url,则从注册中心中获得目标url列表。
如果urls.size()==1,则直接用这个url获得invoker,这个invoker就是最后用来创建动态代理用的。
当urls.size()>1时,有registryURL属性,如果配置了注册中心协议Protocol,则只用AvailableCluster得到invoker。
cluster.join()方法是用来获得invoker的,cluster属性的定义:
private transient volatile Invoker<?> invoker;
Invoker是个接口,根据配置的不同会使用不同的实现类,比如上面的AvailableCluster,他的join()方法是这样的:
public Invoker join(Directory directory)throws RpcException {
return new AbstractClusterInvoker(directory) {
public Result doInvoke(Invocationinvocation, List<Invoker> invokers, LoadBalance loadbalance)throws RpcException {
for (Invoker invoker :invokers) {
if (invoker.isAvailable()){
returninvoker.invoke(invocation);
}
}
throw new RpcException("No provider available in " + invokers);
}
};
}
实际上这个join()方法返回了一个AbstractClusterInvoker对象,并重写了他的doInvoke()方法,这个方法在动态代理实际被调用时会用到。
现在回到createProxy()方法,最后用得到的invoker通过proxyFactory创建动态代理,至此动态代理就创建完了。
消费端动态代理部分
当我们在代码中配置好的SequenceService进行远程调用时,实际上调用的是对应Invoker的invoke()方法,invoker是一个接口,对于这个接口的实现大概是这样的:
Invoker
----AbstractInvoker
----AbstractClusterInvoker
----AbstractProxyInvoker
----DelegateInvoker
----MockClusterInvoker
----MergeableClusterInvoker
----InvokerListenerAdapter
----InvokerListenerAdapter
……
还有很多
AbstractInvoker就是用来远程通信的Invoker
AbstractClusterInvoker是provider是集群时使用Invoker,比AbstractInvoker多了负载均衡,选择provider的过程,最终确定了调用的provider之后还是会调用AbstractInvoker中的invoke()方法。
我们先看AbstractClusterInvoker的invoke()方法:
public Result invoke(final Invocation invocation) throws RpcException {
checkWhetherDestroyed();
LoadBalanceloadbalance;
List<Invoker> invokers = list(invocation);
if (invokers !=null && invokers.size() > 0) {
loadbalance =ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
.getMethodParameter(invocation.getMethodName(),Constants.LOADBALANCE_KEY, Constants.DEFAULT_LOADBALANCE));
} else {
loadbalance=ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(Constants.DEFAULT_LOADBALANCE);
}
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
return doInvoke(invocation, invokers, loadbalance);
}
首先判断当前consumer是否已经destory了,然后用list(invocation)方法获得所有的provider信息,获得负载均衡算法LoadBalance,设置同步属性,最后调用doInvoke方法。
AbstractClusterInvoker的doInvoke()方法是个抽象方法:
protected abstract Result doInvoke(Invocation invocation,List<Invoker> invokers,
LoadBalance loadbalance) throws RpcException;
他的子类有很多,比如:
AvailableClusterInvoker 选择第一个可用的provider。
FailBackClusterInvoker失败自动恢复,后台记录失败请求,定时重发,通常用于消息通知操作。
FailfastClusterInvoker快速失败,只发起一次调用,失败立即报错,通常用于非幂等性的写操作。
FailoverClusterInvoker失败转移,当出现失败,重试其它服务器,通常用于读操作,但重试会带来更长延迟。
FailsafeClusterInvoker失败安全,出现异常时,直接忽略,通常用于写入审计日志等操作。
ForkingClusterInvoker并行调用,只要一个成功即返回,通常用于实时性要求较高的操作,但需要浪费更多服务资源。
具体使用哪个得看配置
我们以之前提到的AvailableClusterInvoker为例,看一下doInvoke()方法:
public Result doInvoke(Invocation invocation, List<Invoker> invokers,LoadBalance loadbalance) throws RpcException {
for(Invoker invoker : invokers) {
if(invoker.isAvailable()) {
return invoker.invoke(invocation);
}
}
throw new RpcException("No provider available in " + invokers);
}
就是判断invoker是否可用,可用就直接调用invoker的invoke()方法,实际上调用的还是AbstractInvoker的invoke()方法,如果不是集群就直接调这个方法了,该方法代码如下:
public Result invoke(Invocation inv) throws RpcException {
if(destroyed.get()) {
throw new RpcException(“Rpc invoker for service " + this + " on consumer” + NetUtils.getLocalHost()
+" use dubbo version " + Version.getVersion()
+" is DESTROYED, can not be invoked any more!");
}
RpcInvocation invocation = (RpcInvocation) inv;
invocation.setInvoker(this);
if (attachment!= null && attachment.size() > 0) {
invocation.addAttachmentsIfAbsent(attachment);
}
Map<String,String> context = RpcContext.getContext().getAttachments();
if (context !=null) {
invocation.addAttachmentsIfAbsent(context);
}
if(getUrl().getMethodParameter(invocation.getMethodName(), Constants.ASYNC_KEY,false)) {
invocation.setAttachment(Constants.ASYNC_KEY, Boolean.TRUE.toString());
}
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
try {
return doInvoke(invocation);
} catch(InvocationTargetException e) { // biz exception
Throwablete = e.getTargetException();
if (te ==null) {
return new RpcResult(e);
} else {
if (te instanceof RpcException) {
((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
}
return new RpcResult(te);
}
} catch(RpcException e) {
if(e.isBiz()) {
return new RpcResult(e);
} else {
throw e;
}
} catch(Throwable e) {
return new RpcResult(e);
}
}
还是先判断consumer是否是destory的,其实destroyed是destory的过去分词,不是人家拼错了。
然后经历一堆和AbstractClusterInvoker的invoke一样的参数设置,最后调用doInvoke()方法,而且这个方法在这个Invoker里面也是抽象的。
AbstractInvoker的doInvoke()方法在DubboInvoker类里面有具体实现,这个DubboInvoker是AbstractInvoker的子类,doInvoke()方法如下:
@Override
protected Result doInvoke(final Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation) invocation;
final String methodName = RpcUtils.getMethodName(invocation);
inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
inv.setAttachment(Constants.VERSION_KEY, version);
ExchangeClient currentClient;
if(clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
try {
boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
总结
就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运!
金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
ntClient = clients[index.getAndIncrement() % clients.length];
}
try {
boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
总结
就写到这了,也算是给这段时间的面试做一个总结,查漏补缺,祝自己好运吧,也希望正在求职或者打算跳槽的 程序员看到这个文章能有一点点帮助或收获,我就心满意足了。多思考,多问为什么。希望小伙伴们早点收到满意的offer! 越努力越幸运!
金九银十已经过了,就目前国内的面试模式来讲,在面试前积极的准备面试,复习整个 Java 知识体系将变得非常重要,可以很负责任的说一句,复习准备的是否充分,将直接影响你入职的成功率。但很多小伙伴却苦于没有合适的资料来回顾整个 Java 知识体系,或者有的小伙伴可能都不知道该从哪里开始复习。我偶然得到一份整理的资料,不论是从整个 Java 知识体系,还是从面试的角度来看,都是一份含技术量很高的资料。
[外链图片转存中…(img-EQ0RlLjE-1713599492222)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-rngNdNsd-1713599492222)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!