当前位置:网站首页>A pit in try with resources

A pit in try with resources

2022-06-24 22:10:00 JAVA Chinese community

How are you guys , Yesterday, I resumed my previous projects ( About a year ago ), To see this  try-catch , And I think of my previous experience of falling into a pit , Made a small demo Let's feel it ~  

problem 1

A simple example of downloading a file .

What will happen here

131680e6ffc8fdffc30a80351b8b6562.png
@GetMapping("/download")
    public void downloadFile(HttpServletResponse response) throws Exception {
        String resourcePath = "/java4ye.txt";
        URL resource = DemoApplication.class.getResource(resourcePath);
        String path = resource.getPath().replace("%20", " ");
        try( ServletOutputStream outputStream  = response.getOutputStream();
        FileInputStream fileInputStream = new FileInputStream(path)) {


            byte[] bytes = new byte[8192];
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int len = 0;
            while ((len = fileInputStream.read(bytes)) != -1) {
                baos.write(bytes, 0, len);
            }

            String fileName = "java4ye.txt";
            //            response.setHeader("content-type", "application/octet-stream;charset=UTF-8");
//            response.setContentType("application/octet-stream");
//            response.setHeader("Access-Control-Expose-Headers", "File-Name");
//            response.setHeader("File-Name", fileName);
   //  abnormal 
            int i = 1/0;

            response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

            outputStream.write(baos.toByteArray());

        } catch (Exception e) {
            throw new DownloadException(e);
        }

    }
aa7e6730105946782ee19c4d6ae5af08.png

What do you think to choose after reading ?

  1. The exception is captured by the global exception handler and returned to the front end .

  2. The front end cannot be received response Error messages for .

99737f03804a0f5360be79636ac39600.png

The answer, of course, is 2 La , ha-ha If it is normal, it will not be written

01c92b5fbf7b70552b39b007a4124223.png

bug memories

During the joint commissioning with the front end , I found that the front end of this exception message did not give a corresponding prompt , I thought it was the front-end problem , Ha ha ha After all, there is nothing wrong with my code .

And the project is separated from the front end and the back end ,response Of content-type and header All of them have been handled , Front end used axios To intercept these responses , There seems to be another one responseType: blob Such things . Then it happens that the front end is not familiar with this thing , He also thought there was something wrong with his front end , however debug When , To see this post Requested response Why is it empty , adopt chrome Browser found .

At this time, I still wonder , Ask him , Are you this Front end intercept Got rid of , Otherwise, I can't see ( I'm so stupid , Now I really want to give myself two slaps to wake up This is nonsense )

Later, I also felt something wrong , Just look at your code carefully , I also asked another colleague to watch it together   Guess together ( In the middle of the trip, I got another hole in the front Sin ……)

784c9a58e725238bfd88e90fb5c55233.png

An hour or two later , I finally got the hang of it , I wonder if it could be this   The stream is closed first  , That led to this farce ( I was wondering Nine is not separated from ten )

So I try to modify the code , Open  try-with-resources , Change to regular  try-catch , And in  finally  Rewrites the closing logic of this flow in , When the program is normal , To close the flow normally , Otherwise don't close .

As a result, the problem was solved smoothly ……

At that time, I thought I was stupid , I didn't think of this for the first time The stream is closed The problem of , And foolishly suspected the browser , Is there a problem with some writing of the front end , Very embarrassed Such a pit ,, I just want to find a hole to drill into ..

4ef1ad242f5dd8827d3a615866c93153.png

See this code again , I think there should be something inside that can be dug out , So there is this article ~ ( Public execution , Take warning )

2fb216726a45ccab760a097b543f2785.png

problem 2

You have seen  try-with-resources   and  try-catch  Compiled and decompiled code ? Have you compared their differences ~

f7d410ce89226fc83044aeda70d3d8c6.png
whole
f191cbc4c7b86e53c191fe312868147b.png
details

The above is given here  try-with-resources   Module decompiled code , It can be found that there is no... In the decompiled code finally The block .

If you look at the picture above , try-with-resources   The function of is the following two points

  1. catch Exception when , Turn off the stream first , Throw an exception again

  2. Add code that normally closes the flow

Did you find this line of code

var15.addSuppressed(var12);

This will lead to  Throwable  coming

053d7372faa8b20493446d84c8b19f32.png
image-20220413230827492

See the function of this method

link :https://blog.csdn.net/qiyan2012/article/details/116173807

c6fa54d3e7fbb5427cd015a1a9032345.png

It means Hang the exception in the outermost exception   , However, you can know from the method comments , This is usually  try-with-resources   Did it for us secretly .

5053b8d4bcd78bbefce034393fb389d5.png

It's not over here , Please continue to look at it.

problem 3

This anomaly has not yet debug Well , Don't go , Verify the above The closure of the stream Logic

stay OutputStream Of close Method , Finally, it will come to  Tomcat  Of  CoyoteOutputStream  in , You can see the flag bit at this time closed and doFlush All are false.

e8b03b4bc24dcfe7e8943bd6ad9dd147.png

After execution close After the method is closed , This initial from true Turn into false , and closed Also become a true.

meanwhile , This   In heap memory buffer HeapByteBuffer There is no time to write new data in , It was shut down directly , The contents are still from my last visit .

0439156fd02e8e1f268d591004e9cf76.png

After closing the flow , To catch this exception , This is consistent with the code logic we see after decompiling

0faca6e84f9201099abd9b9c5964eeb2.png

The following steps are a bit long , Just briefly summarize the key points ~

After the flow is closed , This part of the code is executed as usual .

  1. The exception thrown is  SpringMVC  Framework of the  AbstractHandlerMethodExceptionResolver  Capture , And implement  doResolveHandlerMethodException  To deal with

  2. utilize  jackson  Of  UTF8JsonGenerator  To serialize , And use  NonClosingOutputStream   Yes  OutputStream  For packaging .

  3. Data write buffer ( Key steps Here's the picture )

a08f70865c4f1dd90ebf7a88917d443a.png

You can see that after the flow is closed , here closed Also become true, So the customized information cannot be written to the buffer .

Others in the back flush The operation can't brush out anything .

f76b80e8d6e45ecfbf4775b7e235ec61.png

For example, put it in  GitHub  Yes ……   It is directly put on it together with the examples to be written in the next issue

https://github.com/Java4ye/springboot-demo-4ye

580da2e36f5360830655d74fd48d7f44.png

summary

After watching the , You know that I have made a very low-level mistake ( I don't want my face this time , Just dig up some other content and write it together )

  1. Pay attention to the problem of flow closing

  2. Use caution  try-with-resources , Consider exceptions , Can this flow be closed .

  3. At the same time, I know  try-with-resources  Some technical details of , Will not generate finally modular ( My previous mistakes ), Instead, it will help us close the flow in exception capture , At the same time, the exception of the closing process is appended to the outermost exception , And add code to close the flow at the end of the program .

  4. After the flow is closed , The data is no longer written to the buffer , meanwhile nio Of In heap memory cache HeapByteBuffer The data in is still old . Whatever happens in the back flush Can not give effective feedback to the front end .

287be59038b47ba084b86c6ac1d4f897.gif

 Previous recommendation 

346b607aed2556fef617918a600ad69c.png

33 Mid year summary of year old programmers


5e559f09b269c2c0399ba0663239fa3c.png

Face slag counter attack :MySQL Sixty six questions ! Recommended collection


673b29ab1be47fe973667b507724fb7d.png

actual combat :10 A method to implement delayed tasks , The attached code !


c22ff14e064454e0f2b93a94357726cd.gif

原网站

版权声明
本文为[JAVA Chinese community]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/175/202206241547370432.html