In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces "how to deal with Service layer exceptions in Java". In daily operation, I believe many people have doubts about how to deal with Service layer exceptions in Java. Xiaobian consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful for you to answer the doubts of "how to deal with Service layer exceptions in Java". Next, please follow the editor to study!
Dealing with errors is to write the right program.
What exactly is "correct"? Is determined by the problem to be solved. If the problem is different, the solution is different.
For example, a web interface accepts a user's request, which needs to be passed in a parameter "age". Perhaps the business requires that this field should be an integer between 0,150. If the user enters a string or a negative number, it is definitely not accepted. Usually, somewhere in the backend, the validity of the input is checked, but an exception is thrown. But in the final analysis, the "right" solution to this problem always prompts the user in some form. The prompt that the user is some kind of front-end work depends on whether the interface is app,H5 + ajax or an interface generated by a server like jsp. Either way, you need to "design a process to fix bugs" according to your requirements. For example, a common process requires the back-end to throw an exception, and then go all the way to a centralized error-handling code, convert it into a HTTP error (a specific business error code) and provide it to the front-end, and the front-end makes a "prompt". If the user enters an illegal request, the back end logically cannot fix it on its own, which is a "correct" strategy.
For another example, for example, if a user wants to upload an avatar, the backend sends the image to a cloud storage, and the cloud storage reports a 500 error. What should I do? You may have thought of retrying several times, because maybe the problem is just a temporary network jitter, and retry will work properly. But if you retry multiple times, it won't work. If some kind of hot backup scheme is designed when working on the system, it may be sent to another server instead. "retry" and "dependency to use backup" are both "processed immediately".
But if the retry doesn't work and all backup services don't work, you might be able to throw the error to the front end as above, prompting the user to "server desertion." From this solution, it's easy to see where you want to throw the mistake because that catch place is the most convenient place to deal with the problem. A solution to a problem may require a combination of several different error handling.
In another example, your program throws a NPE. This is usually the programmer's bug--, or the programmer wants to express something "no", and as a result, in subsequent processing, he forgets to judge whether it is null; or a null appears in a place where he thinks it is impossible to null when writing code. In either case, the user of this error will always see a very vague error message, which is far from enough. The "right" way is for programmers to find it and fix it as soon as possible. To do this, the monitoring system needs to constantly climb the log and report the problem to the police. Instead of waiting for users to find customer service to complain.
For another example, for example, your back-end program suddenly OOM and dies. The program that hangs up cannot recover itself. To be "correct", you must consider this issue in a container outside the service. For example, if your service runs on k8s, they will monitor the status of your program, then restart the new service instance to make up for the dead service, and have to adjust the traffic to cut off the traffic to the hanging service and replace it with the new instance. Recovery here cannot be achieved only with exceptions because it is cross-system, but the truth is the same. But is it "right" to restart alone? If the service is completely stateless, it's not a problem. But if it is stateful, some of the user data may be messed up by half of the requests executed. Therefore, when restarting, we should pay attention to "restore the data to the legal state". This goes back to what you need to know is the "right" thing to do. Relying on simple grammatical functions alone cannot solve this problem without a brain.
We can generalize that the "external container" of a worker thread is the "master" that manages the worker thread. The "external container" of a network request is an web server. The "external container" of a user process is the operating system. Erlang integrates this supervisor-worker mechanism into the design of the language.
(recommended micro-class: Java micro-class)
There are three main reasons why Web programs can throw exceptions to the top level to a large extent:
The request comes from the front end, and the final high probability can only tell the user the problems caused by the incorrect user request (data legitimacy, permissions, user context status). Therefore, it is reasonable to throw an exception to a place where errors are handled centrally and convert the exception to a business error code.
Back-end services are generally stateless. This is also the general principle of Internet system design. Statelessness means that you can restart at will. There will be no problem with the user's data because of the next item.
Back-end modifications to data depend on DB transactions. So a half-changed uncommitted transaction will not cause side effects.
But you should know that the above three rules are not always true. There will always be some processing logic that is not completely stateless, and not all data modifications can be protected with a single transaction. Special attention should be paid to the invocation of micro-services, there is no transaction protection for the modification of memory state, and the problem of messing up user data will occur if you are not careful. For example:
Try {int res1 = doStep1 (); this.statusVar1 + = res1; int res2 = doStep2 (); this.statusVar2 + = res2; int res3 = doStep3 (); / / throw an exception this.statusVar3 = statusVar1 + statusVar2 + res3;} catch (...) {/ /...}
Let's assume that some kind of invariant constraint (invariant) needs to be maintained among this.statusVar1, this.statusVar2, and this.statusVar3. When this code is then executed, the assignment to statusVar3 will not be executed if an exception is thrown under the doStep3. At this time, if the modified rollback of statusVar1 and statusVar2 can not be returned, the data will violate the constraint. However, it is generally difficult for programmers to directly find that this data has been modified. The broken data may secretly cause other code logic that depends on the data to go wrong (for example, it should have been given points, but did not). Such errors are generally very difficult to investigate, and it is very difficult to find an incorrect handful of data from a large amount of data.
What is more difficult to deal with than the above paragraph is this code:
/ / controllervoid controllerMethod (/ * some params*/) {try {return svc.doWorkAndGetResult (/ * some params*/);} catch (Exception e) {return ErrorJsonObject.of (e);} / / class svcvoid doWorkAndGetResult (/ * some params*/) {int res1 = otherSvc1.doStep1 (/ * some params*/); this.statusVar1 + = res1; int res2 = otherSvc2.doStep2 (/ * some params*/); this.statusVar2 + = res2 Int res3 = otherSvc3.doStep3 (/ * some params * /); this.statusVar3 = statusVar1 + statusVar2 + res3; return SomeResult.of (this.statusVar1, this.statusVar2, this.statusVar3);}
The scary thing about this code is that when you write it, you might think that something like doStep1~3 can be catch in Controller even if it throws an exception. You don't have to handle any exceptions on the svc layer, so you don't write try. Catch is only natural. But in fact, any exception thrown by doStep1, doStep2 or doStep3 will cause the data state of svc to be inconsistent. Even you can use documentation or other means of communication to make sure that doStep1, doStep2, and doStep3 will be successful in the first place, so the code you wrote was right in the first place. But you may not be able to control their implementation (for example, they are provided by lib developed by another team), and their implementation may be changed to throw errors. Your code may change from "no problem" to "possible problem" without knowing it. What's even more frightening is that code like this doesn't work correctly:
Void doWorkAndGetResult (/ * some params*/) {try {int res1 = otherSvc1.doStep1 (/ * some params*/); this.statusVar1 + = res1; int res2 = otherSvc2.doStep2 (/ * some params*/); this.statusVar2 + = res2; int res3 = otherSvc3.doStep3 (/ * some params*/); this.statusVar3 = statusVar1 + statusVar2 + res3; return SomeResult.of (this.statusVar1, this.statusVar2, this.statusVar3) } catch (Exception e) {/ / do rollback}}
You may think that this will deal with the data rollback, and you may even think the code is very elegant. But in fact, every place where doStep1~3 goes wrong, the code of rollback is different. You have to write:
Void doWorkAndGetResult (/ * some params*/) {int res1, res2, res3; try {res1 = otherSvc1.doStep1 (/ * some params*/); this.statusVar1 + = res1;} catch (Exception e) {throw e;} try {res2 = otherSvc2.doStep2 (/ * some params*/); this.statusVar2 + = res2;} catch (Exception e) {/ / rollback statusVar1 this.statusVar1-= res1; throw e } try {res3 = otherSvc3.doStep3 (/ * some params * /); this.statusVar3 = statusVar1 + statusVar2 + res3;} catch (Exception e) {/ / rollback statusVar1 & statusVar2 this.statusVar1-= res1; this.statusVar2-= res2; throw e;}}
This is the code that gets the right results-data consistency can be maintained wherever errors occur. Is it elegant? It looks ugly. This is even uglier than go's if err! = nil. But if I have to make a choice between correctness and elegance, I will not hesitate to choose the former. As a programmer, you can't directly think that throwing an exception can solve any problem. You must learn to write a program with correct logic, even if it is difficult and looks ugly. In order to achieve a high degree of correctness, you can't always focus most of your attention on the "everything OK process" and regard mistakes as work that can be done casually, or simply believe that exception can take care of everything automatically.
At this point, the study on "how to deal with Service layer exceptions in Java" is over. I hope to be able to solve your doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.