Dynamic Proxies in Java

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] so good evening and welcome to the java user group event of tonight um with heinz kabut about dynamic proxies in java i'm still waiting a bit to make sure that everyone can transition from the waiting room over to the presentation and i think we are done already great it's me it's patrick from the java user group and i will do a short introduction and also mention a few organizational topics um we have now an online format with big macro and you probably attended already some of the talks online and the talks will be actually recorded and published in a few days on youtube so just make sure that you can register on youtube as well like sign up for the java user group and site and get notified for future talks we also have a slack channel so you can ask questions or you'll get informed there so also sign up there and make sure um you get in touch with others it's usually also nice place to meet afterwards after the talk and just like mingle and talk to others and discuss about topic as well as you know at the end of the talk you will be automatically forwarded to the feedback form as we usually have it right and from the feedback forms every month we will draw a winner of an intellij idea license be aware of that there is a delay in the video stream so while i'm talking it takes about 15 seconds or a bit more until you can actually hear and see it so that means also when you're writing in the chat probably heinz may already go a little bit forward with with his talking so we will have to deal with this um thing there is actually a chat and use the chat to ask questions or mention technical difficulties so marcus and i can take care about that if you have questions in general and put them to the q a section because it's easier and we can mark them as well as answer so it's easier to track for us heinz actually loves to answer the questions during the talk so you don't have to wait until the end and no the polls we don't do tonight we just found out before now i'm really happy actually to have heinz here because heinz is the author of the well-known java specialist newsletter where he sends out a lot of um funny puzzles and things like um from the java ecosystem i met him a few years ago at the um jay creed conference and then also afterwards for example at j alba and other conferences and i'm really happy to have him here to have a talk about um java and proxies because he did a book and he recently i think it was like at the end of august he released this book on infocu so he is really knowledgeable in the topic right okay great so then i would say welcome to heinz and enjoy the talk all right i thought there was going to be a 30-minute intro i all misunderstood let me share my screen so there's that 13-minute intro it's a sounds like a 30-second intro okay fantastic all right so um thanks so much for inviting me um really appreciate it i am i i tweeted a few months ago that i'm very happy to speak at any remote event at the moment and uh and so patrick kindly said hey you know we've got ch wouldn't you like to speak here again i think i've spoken with your group once or twice before i've got this really cool pocket knife this absolutely amazing swiss pocket knife from which i got from i think it's i think it's from you from drug ch so um good times very good times so um yeah um so i'm i'm the presenter i've got um my wonderful friend john green in the background he's he's monitoring the um the conversations if there's any any questions he will send them to me on a different channel so that i can actually um so that i can answer them as we go through this to the talk so i'm going to stand because it's easier talking when you're standing it's not just because you're then taller which i'm obviously taller than i would otherwise be but it's easier to concentrate when you when you're standing um as we all know right it's more creative and it's easier also speaking is easier when you're standing up so standing is a bit easier um now with i want to talk a little bit about where these dynamic proxies come from and they originally come from um well the idea is the following that sometimes we need to to create um code in order to build ecosystems and a long long time ago there was a system called rmic which would create stubs and skeletons in order to manage remote method calls with rmi now i don't know if anybody still uses rmi if you do you can post in the chat maybe don't because people go like what you're still using that but it's all technology but even all those rmic where well it's as old as rmi but it's it's what it would do is it would generate stubs and skeletons in order to to manage remote method calls and the the thing is that that um it was a bit of a pain because you would write your code and then you generate the stubs and skeletons from remote interfaces which is really quite quite quite annoying um and what they did in java 1.3 which is already 20 years ago is they gave us the option of of generating all of these things dynamically with the thing called dynamic proxies and the idea is that you you basically write an invocation handler this invocation handler is used for all of the methods on the proxy and so we didn't wouldn't really need to to use rmic or similar build tools or to build our system we would just define an interface and an invocation handler would then run whenever any method is called so this gives you abilities to write flexible dynamic systems and it can give us great wins so one example we had was quite amazing because there's lots and lots of generated code you know i did an analysis of the system it was 600 000 code statements which is it's not 600 000 lines of code it's probably about 100 000 lines of code generated code so it was a really big chunk of code and this was all generated code from another language so they taken another language that converted it to java and that particular part was very repetitive and so what we were able to do is to replace the entire 600 000 code statements with a single dynamic proxy so that that was a really big win and all we need to do is write one invocation handler and reuse it for hundreds or thousands of classes um and so it's really useful to be able to to not have to repeat yourself to sort of write the code once and then reuse it over and over again so that's one of the many benefits of the cinema coding and it's used in lots of different infrastructure code and frameworks you'll see it in spring annotations are implemented as dynamic proxies that's why annotations are actually interfaces and they implement today's dynamic proxies when you use them in at runtime dependency injection hibernate gradle a lot of these all of these use dynamic proxies and if you want to know which of your systems use it i'll show you a trick that you can use to figure that out now patrick mentioned that i've got a book i've written i've actually written two books on dynamic proxies the first was a book in german with a friend of mine and it's quite good but it was a long time ago and i've done lots of revisions of that topic and you can get it from here and there's a new version coming out soon i got a forward by by brian goetz and that's going to be the second edition but you know you can get this in the meantime now before i show you how to use these dynamic proxies i want to show you how we can use how we can write handcrafted proxies in others how we can write them by hand and the reason is before you automate something it is useful to see how you would go about doing it by hand first so that you you've got some idea of of the process involved and then we automate later so of course you could use the ide for generating all your code and i'll i'll do that in the beginning but in the next section i'll show you how to use a dynamic proxy to do it instead because using it generating code with the ide is also kind of pedestrian and what i mean by that is we might generate the code it might have all this code generated but then after we have to maintain it by hand and quite often the generated code isn't exactly what we really wanted my example here is that of the virtual proxy and the virtual proxy that i deal with that is that if we've got an expensive object we we don't want to necessarily create it immediately because we might never need it it's a bit like um my annual tax return which i don't i know i have to do it at some point but always delayed for the last possible moment because all this paperwork and things to do and i basically give it to my accountant and when he says okay heinz we're going to do it now then we do it so it's a virtual proxy and uh uh you know maybe the world will end before i have to do the tax return which will save me all the work of having to do the tax return that's always my hope every year but i'm not hoping that the world will end but i'm hoping that something will happen that i don't have to do it but it never happens i always have to do it they say they're they're two most uh reliable things are death and taxes unfortunately but it's the example you know you've got this thing they have to do i don't really want to do it so i delay it until later and that's the idea of a virtual proxy we've got this placeholder object and we only create the costly object when we when we use it for the first time so in the meantime there's this just proxies schneifer substitute object and um so the example i've got is of something that's very similar to a normal map that i call it custom map because it's a slightly reduced version of the normal map instead of having like 50 methods only have six methods size get put removed clear and for reach and this custom and if i want to have an implementation of that i can delegate all of the method calls through to the traditional normal hashmap so for example here i've made my custom map this is my little hash map and inside i've got my private final map map equals new hash map and [Music] in the constructor i print out that i'm constructing it just so we know when it gets constructed and then all of the methods are delegated through to the hashmap right size get put remove clear for each and twostring all well not all you see i've forgotten a few and it's easy to forget if you if you're not being very careful um so that's the custom hash map and it's basically it's all delegating through to the actual hashmap implementation um now what the virtual proxy would look like um i would have inside the virtual custom map there's now a virtual proxy appointed to a real map but that will start off as null so it starts off as null and also the supplier of custom map so the supply of custom map is is used to to create the map when we use it for the first time and there's a method at the bottom here called get real map that gets the actual map and it's a private method that gets called by the other methods you'll see that in a moment and here i'm constructing the real map on demand so the first time that i call it real map will be null and i'm going to call mapsupply.get and i make this new map and then i assign it into the field and have got your your all the methods all delegate through to the get real map method so just lots of delegation going on each of the methods simply calls get real map and when i when i call any method on this virtual proxy it's then going to call get real map and that is going to then create the actual map by calling the supplier right so that's nice and easy and so the virtual custom map um is made when when any method is called it doesn't matter which one you called whatever you call is going to be constructed so if you look here i'm constructing a virtual custom map with a method reference that will construct a custom hash map and so i print out virtual map created and the moment i use the map in some way for example i put or clear or set or get whatever then it's going to say custom hash map constructed so it gets constructed when it's used for the very first time all right um so that's how you did by hand now dynamic proxies have the benefit that you write the code once you can you use it for any sort of done a virtual proxy you might want it could be for for hashmap it could be for heinz's tax return it could be for anything where you want to have something later created you want to make a data source on demand this is your friend this will do it for you one of the problems that we have a problem we face all the time in software development is this copy and paste programming so you have a you have a bug and the bug appears somewhere and then you copy and paste the code and now the bug is somewhere else so and the bug sort of moves throughout the whole code base um we actually had this with this presentation uh john and i my lovely assistant we had we as part of my dynamic proxies book i also wrote the dynamic proxies course and and so i had one one mistake on a slide and then i copied that i copied that that course to make a presentation and i copied and pasted that mistake along with that presentation and eventually found i had about 10 different places where that same bug had been copied and pasted that's always a problem with presentations and of course in source code that's the problem because you fix one bug but then it appears again in other places we all know what this is and it's a real pain it's horrible so a better approach is to either statically or dynamically generate the code it's a much better approach so here's how you do it there's a class called proxy it's been around since for 20 years and it's a proxy.new proxy.newproxy instance and we pass in three parameters first of all a class loader where the new proxy class is loaded and then a class array that contains all interfaces our proxy must implement could be more than one because we can of course implement lots and lots of interfaces at the same time and then we also pass in a function interface invocation handler and this is called when any proxy method is invoked so you call the method it goes through this one place it all goes to one place and invocation handler this is the function interface with a single method called invoke this is called when any method is called on the proxy uh it contains a method called invoke which has three parameters the first parameter is the dynamic proxy class that is calling invoke so it's the actual instance of your dynamic proxy the second is the method the class the the method that's being invoked and i'll show you how we get that and then the third is an array containing all the parameters right and the array might be null so if it's a method that doesn't have any parameters the array is not so it's not going to be an empty array it's just a null array something else which is interesting is the method is going to be one of the interface methods or equals hashcode or string one of those three so and because those are those are public non-final methods on objects the interface methods or one of those three and if you remember when we did the cust the the virtual proxy uh by hand we forgot to implement those three so if you said tostring you would see this virtual custom figure what's that what's this virtual custom app you you'd see the default two-string method you wouldn't see the actual method you would expect to be to be calling all right so um i want to show you an example of a logging invocation handler and the way that it works is we want to log every time we go into method entering and we leave exiting and also optionally measure the time how long it takes so the way that it oh hold on um forgot about this um okay sorry uh so patrick already introduced me very nicely and i certainly can't do anything nearly as nice as patrick did but i've got a present for you right last time i went to switzerland i got this amazing pocket knife and i've got something back for you which is if you look at the top the tinyurl.com slash jug ch911 i thought a nice nice car i thought put that in there then you'll get a little gift now that gift expires um about an hour and 10 minutes from now so if you're watching the live stream you you made the effort on friday night to come and watch the live stream you're getting it but if you're watching the recording well you're not gonna get it so unfortunately that's how life is next time go to the live event and you can get whatever gifts they're giving away and uh yeah i've been doing this remote teaching for a very long time last week we spent a whole week actually john and i teaching design patterns and refactoring together with sns media which is really a lot of fun so if you'd like to know more about my online courses send me an email i'm happy to hear from you and don't forget to get that that gift uh gift as in uh present not gift as in this the german gift and a swiss friend in south africa who made that mistake he sent a packet of of some food from south africa to switzerland and as a description he wrote on the gift and it was dried meat from south africa they eat that it's a bit like beef beef jerky but just a bit more unrefined and his parents got this parcel from their son in switz in south africa and it said on the description gift was and they looked at it and they opened it up and they couldn't figure out what that stuff would be they tried to boil it they tried to plant it and they couldn't figure it out with the name gift so it's not that type of gift it's it's a present right so enjoy it all right let's go back to our logging vacation handler and we want to log all the method calls and optionally measure how long they take so when you pass construct will have the the logger and the object that we need to delegate the course to now it's very important that the object that we pass in implements the interface or interfaces that we what we want to um or that we're proxy otherwise you're going to get and get an exception um and this is what the invoke method looks like that's the most important part here um again three three parameters proxy method and args and the two things i haven't mentioned before but i'll just mention that quickly invoke returns objects they can't return anything from that method but you'd have to be careful because what you return has to be compatible with the actual method otherwise you'll get exceptions it also throws throwable and again you could throw anything you could throw a checked exception but again you have to be careful that what you throw actually is compatible with the method signature otherwise you're going to have a problem and i'll explain why that happens in a moment so here i'm just printing something logging entering and logging exiting and and i've got an opt an asset optimization here where i figure out what the log level of is if log fine is true um then i measure system nanotime because that's not a very quick call um otherwise i don't i don't do that so i only measure the time if i've got log fine enabled all right then the two string i'm not going to spend too much on this the space heaters prints out the class name the method name and the parameters if there are parameters so here i've got my my my map and if you look carefully at this i'm saying proxy dot new proxy instance i'm passing in the class load of map so what is that a of map what is that the closet of map is your bootstrap class loader that's that's the cluster that's loading all your jd jvm jdk classes so the the system the class that belong to your to virtual machine are loaded with your bootstrap class loader the classes that are loaded with that's loading the class layer which is loading our own classes is the system class loader or application class loader they're different names for it um and it's important that the class loader can obviously see our interface if it can't then it won't be it won't work so the way i normally do it is i use the the same class loader as that of the interface so that's why i'm saying map.class.getclassloader and then i pass in a class array containing only the map.class and because it's a class array i could have several interfaces here but i'm just kind of one and then i've got my login invocation handler which is my the one i showed you a month ago with a concurrent hashmap so of course that implements map so if i call any method on map it's going to delegate that through to the concurrent hashmap but measure before and after to see how long it took there's my output for the first method for put before and after and also the time all right now i find it useful to look at how things work to sort of open it up and peek inside and what's actually going on here and we're going to start with a simple interface called iso date parser which takes a string and returns a local date throwing a pause exception so this interface um it's very simple just one method and if i if i if i load that with the with the if i create a dynamic proxy with that and i say proxy new proxy instance with the class loader of the iso date parser which now is the system class loader and the class array which contains icd-pos oh see there's a question ah yeah a good question about from christian thanks um okay so is this the same get class loaded for java modules java 9 plus with modules so when when i read the book the the the latest one that's now you know available um i was writing it and i thought you know it is 2019 when i started the book and i probably should just double check that everything that i expect to be working also works with modules so the java modules and and so i started digging into that and the more i dug into it the more issues i found with i wouldn't say with with the modules themselves but rather with my code to work with the modules it gets really interesting um and i'll mention this again a little bit a little bit when we talk about um the naming of of of these proxies because here when i was saying get class loader um and and i'm and i'm constructing this new class because the dynamic proxy is actually a new class given that interface it's going to insert it into that class loader right so here i'm going to write it into the system class loader and the previous one i put into the bootstrap class loader so it kind of seems that it seems dangerous to be able to inject the class into somebody else's class loader however the dynamic proxy class itself doesn't actually do anything all it does is it delegates all the methods through to the invocation handler and that is not inside the inside whichever you know class loader you've injected it to that's going to be in your own class loader so um and the modules basically are going to be a similar type of situation um if for example i have an interface um that's inside my module but it's inside a package which is not exported you're actually going to have have a different name a different package a different module where it gets constructed then then then otherwise and i'll show you an example of that a little bit it's a really good question and um so with us with these modules um i then try to get it working with um intellij and trinity modules and maven modules and jpms modules all working together and luckily i've got my my friend john uh green who who helped a lot in getting my so getting stuff like that figured out um but that wasn't enough it was two of us and then then we got simone bourdain bourdain i think it was simone bourdain and it wasn't it wasn't him yeah i think cinema day and robert uh um also helped us to get this all working like the tech lead for for maven and i'm not sure i think i might have even asked somebody from intellij as well because it was really really hard for some reason i'm not quite sure why it was so difficult to get this all working and um and the samples are all available um on on my github repository and and and on maven central as well now for the next version of the book which is ready um uh john has sent me the link the pdf i just haven't had a chance to look at it yet to to proof it but it is ready for publishing uh the the next version um but in the next version we've we've split up our packages and modules were better so that you don't get unnecessary dependencies and so it's it's a bit better but yeah the module system is a very interesting piece of machinery which i think in the end i'm very happy that we have it but it took a crazy amount of effort to make everything work all right ah yes so that's the like typically you're going to find a name like this com sun proxy dollar proxy zero right now um when you look at that to say what is actually inside that dollar proxy zero and there's a way you can find out by dumping the generated proxy classes to your disk so this is java um for example driver nine plus you just say minus d jdk proxy proxy generated dot save generated files equals true and then when you run it on your disk you see all these different files and and so if you've got a system that you're using and you want to know do they use dynamic proxies you can actually do that you can generate all the proxy files and you'll see what classes are generated but the the classes do get reused so if you've got multiple uh places using the dynamic proxy of the same interfaces they'll all uh be there um or they'll all share one one actual generated class so you won't know how many instances of dynamic proxies you'll have but you will know how many um like combinations of interfaces are supported by or are implemented as dynamic proxies in your system so that's that's very useful and then when you've got your generated classes then you can decompile them with the tool like cfr now of course you need to make sure that wherever you are working that you're actually allowed to decompile your classes be really a bit absurd if you if you weren't allowed to decompile classes that you compiled yourself right but um i think one does have to be careful with things like that um so there you go cfr is a very very nice tool for that and here's what you'll find something like this you'll see a class within a funny name like dollar proxy zero which extends proxy and implements iso date parser and um so it's a final class which means we can't subclass it further and we've got four methods inside m naught m1 m2 m3 and when we load the class static initializer block we set up all the methods m naught m one over two three m naught is the hash code method m one is the equals method m two is the two string method and m three is the pause method from isolateposit now i've simplified the code a little bit in the actual code they use class.4 name for each of the classes as well um but i'm just using object.class rather than class.4 name javalang object it's a bit shorter but if you look at the actual code the actual generated code it's a bit more verbose in the end we've loaded all the methods and this is normal java lang reflection nothing really special about that and then um the constructor of dollar proxy zero takes the vocation handler and simply passes that to the super class so there we go and and then we've got different methods like hashcode and equals and hashcode and what it does is i call h.invoke so i'm calling the handler.invoke this the current dynamic proxy command m not that's that method that we found earlier and null for an object array and then we return we take the hash code we return it as an end now here's already a problem because if my hash code function is a little bit complex it can happen that the integer object exceeds the size of my cached int integers and so it might happen that actually end up with making a new integer objective which might call hashcode so it can happen that you have object creation because of the return type it all depends how it's being used sometimes it can be optimized away but not always and all right equals is a is a little bit different because here i've got a parameter that i'm passing it to the method so the parameter is wrapped as an object array or inside an object array and so then again the second thing is sometimes it happens that the object array has to be actually allocated um sometimes it can be optimized away depends on how it's used inside your method so that's something which one has to consider okay so oliver said asks i guess that's done with reflection the does that also mean i have to export my classes when using java 9 modules to able to use proxies no it doesn't if you want to use proxies within your module for your interface which not exported that's completely fine you can do that and what it will do is actually generate a dynamic module i think that's what it's called i'm not sure maybe johnny can just double check that for me if you can i think it's for the dynamic module or an unnamed module maybe but what happens is it generates a model and loads that class in that module so we can see that but no one else can see it so it managed all that for us and but nobody else from outside could use our interface to make a dynamic proxy so it does work and it is managed quite nicely but it's not something we have to to worry about too much but it there is one there is one thing which can happen um so one of the java champions had a had a case where um some code was using reflection to discover or to try to discover the methods instances inside this dynamic proxy and then what it was doing is it was trying to make these methods to be said accessible true you might wonder why i'll explain why in a moment but that's what the code was trying to do but the problem was that the the interface was living inside an unexported module a package unexported package inside a module and so um the um and so and so the code that was trying to do the method said accessible true uh simply got an exception and of course um it wasn't it was quite quite hard to get the work around to be able to to then you know override that that that exception that security exception or illegal access exception or something like that they managed to do it with i think bite buddy eventually but it was it was quite uh quite tough the reason i don't immediately respond to your questions is that uh is this this delay lag like a 30 second lag all right and then two string very much like hashcode and i'll go to the pause method the pause method takes a string as a parameter and now we can see it throws pause exception now something i haven't really looked at before is the exceptions and you'll see that the tostring method for example i say try catch time exception and error and so if i get one of those i'll just re-throw it otherwise if i get throwable then i'm going to throw an undeclared throwable exception that's a runtime exception an unchecked runtime exception and in the pass method the pause method declares that it throws past exception so there are character right time exception pause exception and error and i rethrow those but if it's a thr any other throwable i'm going to wrap that and and throw it as undercared throwable exception so this is something we have to consider and if you go back just to a few slides back to this code over here there was actually a bug in this code and uh i didn't realize that there was a bug until quite late into the book i was like wait a moment this doesn't it's actually not necessarily going to work and the reason is the invoke method this invocation and invoke declares that it throws throwables it can throw anything but then inside them saying return method dot invoke object marks i'm calling via reflection the invoke method on the method object but that can cause an invocation target exception if an exception occurs all right and so if that happens let's say for example you get a null point exception during your equals it shouldn't happen but let's say it does then that's going to be wrapped with an invocation target exception and then it's going to get wrapped again with an undeclared trouble exception that we see over here this undeclared trouble exception so it gets wrapped twice all this exception being constructed so but i'll show you a trick how we get around that if you have any questions you're welcome to pop them into the chat and john will get them to me all right um now let's have a look at how we can make a virtual dynamic proxy because i've got the building blocks to build this thing and um here's my virtual proxy handler which implements in vocational serializable and it's got a supplier inside just like our custom just like our virtual custom map and appointed to the actual subject as well and then when i constructed a pass in the supplier as you would expect and i've got this private get subject method which is very similar to what we had before if subject is equal to null then subject equals supplier.get and then our invoke method returns method.invoke getsubject commax right so i do the same trick that i did before where i'm simply delegating to the actual object by saying method.invoke and you might be wondering didn't heinze say that there's a problem with the exceptions because if an exception occurs whilst calling the method um won't that be wrapped by invocation target exception and then wrapped again as an undeclared throwable exception only if you thought that then you would be thinking along the right tracks so in my book i i've got a bunch of i've got a facade that has a whole bunch of useful methods inside and for example i've got a virtual proxy method which takes as a parameter interface and the supplier and produces a virtual proxy and one of the methods is cast proxy you see there are a bunch of issues here they want issues that when i make a dynamic proxy what is returned from the new proxy instance method is a plain object you see the dynamic proxy can implement lots of interfaces you wouldn't really know which one to use it could be any one right so they don't know who to cast to in most of the times i only make dynamic process of a single interface so um i don't need to have the ability to support lots and lots of interfaces um and so um the cost proxy does a cost first of all to the correct type so if i have custom map virtual proxy it'll come back with a custom map for example and then the other thing it does is it makes dynamic proxies faster uh how does it work i'll expand it a bit when we get to the performance chapter we'll explain why it becomes faster but it makes them faster with the trick and the other thing i do is um if if an invocation target exception occurs then i unwrap that and i throw the content of that rather than than the invocation target exception itself so um so this this gives you the ability to get the correct exception back right so uh yeah it's right i know i unwrapped the invocation target exception and i throw the content of of the invocation target exception so so that it won't get wrapped otherwise the invocation target exception would get wrapped by the inv by the undercard throwable exception it's like you know wrapping wrapping wrapping wrapping until eventually you get the final answer all right um okay so we can create the virtual proxy of anything we want right even your tax return okay it might not help much but because it's enough to do it at some point but you could do a data source anything we've got an interface you can make a virtual proxy of and here what i've done is i've made a i just it's proxies at virtual proxy passing a custom map and a custom hash map and again it works exactly like before now that's the good news so far there are some restrictions the first restriction is that this only works for interfaces right and there's a reason because dynamic proxies all extend the java lang reflect proxy class now that might have been a mistake but it is what it is if you if you want if you want something different you need to use something like cg lib byte buddy or do it more manually since java 15 we've got a mechanism called hidden classes that's new jet that's just been been implemented so that's something new that that you might want to use instead of this but this is really convenient because it's super easy to make a dynamic proxy other ones need a bit more bit more work the other ones about the undeclared throbbing exception as i said if you have an exception that you don't expect like from a runnable i'm throwing an i o exception which of course is not allowed then it gets wrapped as an undeclared throwable exception and then that's then that's thrown so we only need to we should only throw declared exceptions methods exceptions declared by the interface method or error errand runtime exception also will always work right we have to make sure that the runtime return types are correct so if you've got an interface fubar with void foo you can return anything because the return type is not used if you've got a boolean it needs to be boolean if you pass in for example an int like 42 you get to get a class cast exception and um int pass return null well that's going to give you null point exception as you'd probably expect so that's a bit you know it's a little bit of a pain it's it's a pity that they don't have the ability to have um the actual values coming back like you like you do with method handles but it is what it is the the javalang reflect method predates um method handles by quite a few years so we didn't have that option right um when i was writing the book i um i felt really nervous about it because um one of the problems i i have is is i when i go to conferences i i i'm walking around and i i want to talk to people because i'm at the conference to meet people and i'll walk up to somebody and i'll say um hi i'm heinz and you know in the days we could shake hands though remember those days and often and say hi i'm heinz heinz carpets and they'd go like yes we know who you are i'm going like okay great um that's nice but in my mind i'm thinking but i don't i don't know who they are i mean i would love to meet some people um and it's it's really it's really a problem um when you when you're too recognized in a in like a conference because you don't get to speak to anybody except maybe some other speakers who who you know as well right but if it's um someone fritz meyer i don't know they don't know who that is i don't know the name and you know want to get to know some people and talk to them and uh and uh you can't because you start talking and they're like we know you are they're all scared and run away and go like okay it didn't work too well so um so when i was writing my book i sort of had a had a real fear because i thought if i publish something terrible people are going to read that and go this is this is really bad this is a really bad book it's really bad book why is this guy so famous in the java world right i mean i'm not famous in wales but but but and i thought i could really ruin my reputation by publishing a bad book and that's one reason why i took so many years to actually write something and um and so i was very nervous about that and and at some point i thought well maybe i should use my disadvantage or my my feeling of of not being able to do this to my advantage and so i sent an email to like thousands of people i said hey would you like to help review my book you got like this hoarder 500 reviewers jumping on me and saying yeah we'll join you you know great so this is really fun and um of those 500 about 100 actually gave me some useful feedback so normally a book has like three or four reviews we had 500 reviewers right and some of them were absolutely unbelievably amazing and i remember the one of them joe joseph ottinger he's he used to do reviews for the server side java symposium i think it was and and some other other publications as well and he he was he was just he was brutal i mean when i read his comments i actually um i wanted to quit for a while this is just awful i don't know a book was that bad because i thought it was actually quite good but one of the things i said is i said well you know the these are slower dynamic proxies are slower than calling it directly and he just dug in and he said no you need to say exactly why they're slower maybe exactly why why are they slow why should they be slower and at the time i said i don't know i mean notice that it's slower right um you know it's dynamic code it's going to be slower he said but why but why okay so then i went and did a proper jmh benchmark um you know jmh you know we all know that is and um the the challenge with that was that um well first of all it took a long time took really a lot of effort to to to test and to write the code with jmh and to test it and test it test to make sure that everything was correct um and there were a few things which we noticed for example return types and parameter types parameters might be boxed so that of course converts it from into to integer objects and that of course will slow us down um parameters get wrapped with object arrays and they can be eliminated sometimes but not always and then the third one was that methods have this amnesia and they check our permission on every call and so basically every time you make a method call with reflection it says uh excuse me who are you i'm going like uh i'm heinz and they go uh check check check and i say ah yes you've got permission to call this method and then you can call the method and the next time you go again and say hello i'd like to call the math and go like uh who are you i'm heights oh okay check check check oh yes you can call the method and this slows us down um and so the trick that i used was um i by reflection i went and and found all the method objects inside all the dynamic proxies well the ones that you registered with that where you said cast proxy and then i set them to be accessible true now the methods are public anyway because well it's a interface so interface the dynamic proxies are only going to be implementing methods which are public methods it won't implement the private methods of interfaces but they all are public anyway so making these methods public successful true doesn't really harm us that much and what i did was i would i would basically if for some reason it wouldn't allow me to do that i would simply just silently ignore that and just just move on and and this making the accessible true makes makes quite a big difference i'll show you the performance a little bit so i spent a lot of time writing this performance code and and and then afterwards uh joseph gave me the thumbs up so this is now it's good now i can actually you know not just do hand waving and say well it's slow because it's gonna make code but you can actually see why it's slower rather than just explaining you know it must be slow because it's dynamic that's no good excuse so i've got a worker the work has an increment method with a long counter which simply gets incremented and consume cpu which consumes just a tiny bit of work you see the overhead is actually quite low with these things and if you give it any more work to do you won't really be able to tell the difference between the various approaches and then i have five different types of method calls the first one is direct call i'm calling it directly on the actual real worker recording the methods on that and i'm quoting the increment here then i've got the static proxy i've got a handwritten proxy i've got a dynamic proxy redirect core and the dynamic proxy direct call what that means is i've i've got a dynamic proxy but i've basically got one dynamic proxy per method or rather one invocation handler per method in other words it's not correct it doesn't matter what method you call on the object i'm always going to call increment for example i'm always going to call compute consume cpu so the dynamic proxy i recall is not a correct implementation it's just for comparison to compare where where the performance gets lost and and then i've got the dynamic proxy reflective call that's using normal reflection and turbo means that that i've got the that i've gone and said set accessible true on the methods we'll call this method two are boosting and then with artemis you can see it that's that's another another timeline here now in the rightmost column you'll see bytes to operation ea escape analysis on and off so um bytes on so you can see that direct call and static proxy don't make any objects because it's just uh just a long there's no object allocation at all but the direct dynamic proxy diary core um since driver 14 would would also not have any object allocation if you've got the scap analysis on now the times are with the scape analysis on um now the the the figure that's really interesting is the one dynamic proxy reflective call so that's your with turbo on so you see 9.7 nanoseconds and it allocates 24 bytes doesn't matter for scap analysis on off it always allocates 24 bytes so when we do a comparison need to compare the 3.5 nanoseconds for the static proxy with the 9.7 nanoseconds of the reflective chord and it is a big difference but don't forget that the well the actual operation is is nothing it's like long plus plus it's it's really really little all right the consumed cpu here that's a lot closer because you don't have object allocation so there's no objects allocated and you can see that the diary course 4.8 static proxy 5.5 and then i'll skip down to the dynamic proxy reflective called turbo is 7.6 so you need to compare the 7.6 with a 5.5 so it's about that's 2.1 nanoseconds slower so it's it's really really close with this one and you can see that the the total overhead is 6.2 for the increment but part of that cost is the object allocation and then 2.1 for the consumer it's very very little and um in a typical business application that's hardly going to be noticeable you know if you're doing a online you know like a high-frequency trading you're not going to do it like this anyway so it's not going to be a problem um one of the things i've always said is that a lot of the patterns are closely related and i call them the design patterns cousins and the the proxies the structure of the proxy is very similar to that of the decorate or filter and object adapter and composite so what i did in the book was i i went and implemented uh different mechanisms for for each of these patterns as well because um it can be very useful to do that and for example remember we did this custom map at the beginning of the of the talk and we started with this interface custom map and then we had all this duplicated code uh copy and paste you know autogenerated it's it's really pain painful to do this luckily the idea can help us but when you see the id helping us too much we realize that maybe we shouldn't maybe we should find a different way to not have to do it without with at all you know and um and so a lot a lot of firm a lot of duplication here so what we can do i've written a dynamic decorator and all you do is say proxies.filter and you pass in a custom map interface and the hashmap now i'm using i'm leaving out lots of lots of information here there's like a whole chapter on this in the book because when i do that when i pass in an interface and an unrelated class you can't just match you can't just do method.invoke on the object that won't work because the get method on custom map is a different method to the get method on the hashmap so two different completely different methods so they're not compatible so what i did was i wrote something called a v table which is a fast match between different methods and so when you call the custom map it then finds the method with the same signature in the hashmap and calls that instead and it even manages for example default methods which is quite difficult because the default method is automatically implemented in the dynamic proxy instance but then what happens is when you when you call it you're calling the the dynamic proxy version not the one interface and um yeah in the book i've got a way of how how to do that which which is quite fast but it's quite complicated and then another thing here i'm making a virtual proxy of custom map in the second example which takes a filter that makes this custom hashmap and if i want it to be thread safe then i simply make a synchronized proxy that points a custom app and virtual proxy and fills it now at the moment i i i haven't really made the cascading easier you one could probably do something to make it so we don't have to repeat custom mapped or class over and over again but for now i've just left it like that um that's the end of my my talk um so the thing is do we have any questions um and don't forget to get the gift the present uh tinyurl.comch911 and um if you're not on my newsletter you're welcome to subscribe and a saylord java special hindsight specially you and you can get the book if you want so 30 seconds of silence whilst i wait for any questions that might pop up we had some questions already there's something i wanted to show you but it wasn't a different talk i took it out of this talk and that was the naming of the naming of the classes so if your if your interface is package um package access so it's declared inside a package it's a but it's not public in other words then it's going to have the same package name your dynamic proxy will have the same package name as your interface um that's the first restriction the other thing is that if it's inside a module it's going to be and it's not exported it'll be some other funny name in fact i've got an example i'll just run that and i'll show it to you you'll see it so [Music] i can find that it wasn't um not that one this one so samples chapter three proxy name no not that one gotchas proxy name so this is the idea is we've got an interface based component the base component interface has got um is a public interface and it's exported from this module and so that one is going to be um in the com sun i think comstone dollar proxy like that naming if you run that you'll see the output something like that and yeah so it's com com sun proxy dollar proxy zero it doesn't have to be that it can also be something else but that's what most of the time you'll see um and then the comson the second one is a public interface this one here but it's not exported from the module and then you get this sort of a dynamic i think it's i'm not sure what this this module is called that that lives in but it's it's a module that's i think it's an unnamed module or something like that but from outside of this module you can't see that at all it's really hidden away from you and then the other one is a hidden class which is package access that's kind of the same package as as the interface so it's eu java specialist books dynamic proxy samples cho three gotchas so there's a question i saw from patrick reinhardt hi patrick i was actually wondering if you were there i thought i'm sure patrick's going to be there patrick is famous for adding transfer 2 to java thanks patrick i love that method um and many other things too not just that so is there a dynamic method variant for the vacation handler unfortunately not unfortunately don't have that option we're asked to have that also to have sort of the method handles supported directly in there because that then you could make it as fast as um as calling it directly but no we didn't have that unfortunately any other questions sounds like weird silent times now there's a question that john sent me are we limited to just method proxy and arcs and vacation handler uh yeah so that that's it's very specific like you can only have those those types in here although those values in here um let me quickly open my slides again and it's basically that's it um and it's sort of what happens is that everything gets multiplexed so you then have to inside inside your invocation and you've got to figure out what was actually called so that's this over here uh my throng wrong slide this is the slide here so inside your vocation invoke method you need to then figure out what is what actually happened what was the method it was called all right so friday evening fun evening no more questions yeah it seems like everyone is already like having their firearm beer and then so how is free during these days it's wonderful except except we have um we've had lots of cases in chania so well lots not not lots like you know like one or two per day but that's a lot for us and so they've basically shut down the whole city um now it's it's stabilized again but um it's it's wonderful i mean yesterday we spent today on the morning on the beach and swimming here just where i'm sitting here you know and had lunch in kalatha so it's really nice fantastic but um the restaurants are really suffering everybody's suffering because crete you know you probably heard about the greek catastrophe catastrophe a few years ago and at the time when the whole of greece was just suffering like crazy crete was okay because we had lots of tourists so now now we're completely messed up i mean it's really bad really bad because i mean without the tourists and the tourists that have come have made us sick so um it's become really a problem yeah and also you don't want to go from switzerland there because you probably need to go to quarantine afterwards so that's also not fun no no it's um that's the problem it's just traveling around at the moment it's really horrible but it's always a you know patrick the funny thing was um last year last september october i decided i'm going to write a book and i was actually i was going to write a different book not this book that i've written and i said to myself i'm going to dedicate this year to writing a book um so i decided i'm not going to accept any conference invitations for 2020 not one and the only one where i was really tempted to go because my daughter wanted to go there because um well she she liked it the last time i went was voxt milan so he wanted actually it was an april march or something and like at the last minute i said no you know i know i i know she wants to go but let's let's not go this year so i mean obviously i've lost flight flights and stuff you know i mean i've lost money obviously everyone's lost money on this whole thing but but it could be a lot worse and i've spoken a lot because you know i've spoken in nigeria last saturday and then i spoke in kenya and i spoke in bulgaria and i've spoken in serbia i think it was i spoke with lots of different places because and places i've never been to because of this so you know there you go it's always good and bad yeah exactly and the nice thing is actually you can stay at home um yeah that's perfect actually no traveling and um horrible airports and so on yeah but you know i i really do like getting some supplies or swiss chocolates and getting some you know against some schweitzer schwarzerkeiser to take home and yeah i do like getting my supplies you know the one the one easter i went to switzerland and on the way back i got you know all these gold houses right about easter time and you know this big supply of gold towers and this year my kids said to me now this is the first year that we can remember where we're not getting gold gold tarzan for free i said well you know i was i wasn't traveling at all so no gold thousand free stuff so maybe we can work on the chocolate supply let's see and yeah thank you very much for the talk thank you very much for having me and also thanks to all the um and participants just make sure and sorry heinz i'm not switching to the slides again to mine um so you are actually transferring afterwards to the feedback form so please enter the the data and you might win something but also i want to say thank you like to heinz actually making it here and also the the people behind all this so for example ursula with the administration and the registration and so on and also marcus who was actually supporting us in the background making sure that all the participants are doing well getting connected and so on so and obviously also our sponsors which you saw when you were in the waiting room and we also need to thank you them because they um help us to run these events so um heinz thanks a lot again yeah thank you i think should work now yes and um yeah it was a pleasure having you thanks a lot yeah keep safe bye stay safe bye bye you
Info
Channel: Java User Group Switzerland
Views: 1,341
Rating: 4.5294118 out of 5
Keywords: Heinz Kabutz, Java, Proxies, Dynamic Proxies
Id: r43IH5Qhz_Q
Channel Id: undefined
Length: 71min 1sec (4261 seconds)
Published: Sat Sep 12 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.