tag:blogger.com,1999:blog-36199830831695511502024-03-29T04:35:55.722+01:00Java And MoreMy experience, thoughts and ideas around programmingBartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.comBlogger9125tag:blogger.com,1999:blog-3619983083169551150.post-18062222894841737452018-05-29T17:34:00.000+02:002018-05-29T17:34:05.131+02:00Spring I/O 2018 recap<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Last week I had a chance to attend Spring I/O 2018. It was my first time at Spring I/O conference ever, and it was an honor to share the stage with so many fantastic speakers. The number of participants was doubled comparing to the last year. 1000 people from 46 countries gathered in the wonderful city of Barcelona to get the Spring knowledge from over 50 speakers.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The agenda was full of interesting topics and workshops from numerous different areas, and it was hard to choose where to go. Unfortunately, the quality level was very diverse - from the very poor talks to great ones. Below I tried to summarize my thoughts.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
First of all, I am very happy to see that DDD concepts are being spread around the world, because <span style="font-family: inherit;">this is the way we should make our business software. <a href="https://twitter.com/bitboss" target="_blank">Michael Pl</a></span><span style="font-family: inherit;"><a href="https://twitter.com/bitboss" target="_blank">öd</a> gave a good talk about implementing DDD in Spring ecosystem. He made an overview of DDD concepts, and mentioned the initiative of <a href="https://twitter.com/JakubPilimon" target="_blank">Jakub Pilimon</a> and <a href="https://twitter.com/michal_michaluk" target="_blank">Michał Michaluk</a>, called <a href="https://github.com/ddd-by-examples" target="_blank">ddd-by-examples</a>, which is a solid proof that all DDD enthusiasts collaborate with each other in teaching people what DDD is all about. What's more, Michael gave an example of <a href="https://www.archunit.org/" target="_blank">Archunit</a> library, which I had never used before (but I surely will). Archunit is a tool that enables us to enforce the architectural conventions within our application by writing tests that stand guard.</span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;">In most of my projects I used Swagger as a way of documenting my APIs. The problem with it is that it can very easily contribute to technology debt, as there are no mechanisms that would enforce the <span style="font-family: inherit;">consistency between the documentation and the actual implementation. Alternative solution was proposed by </span></span><span style="caret-color: rgb(20, 21, 20);"><span style="font-family: inherit;">Mathias Düsterhöft in his talk about Documenting RESTful APIs with Spring REST Docs and RAML. With the help of <a href="https://projects.spring.io/spring-restdocs/" target="_blank">Spring REST Docs</a> we are able to produce an accurate documentation from our Spring MVC tests. I will surely give it a try.</span></span></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
As I am pretty up to date with Spring 5.0.x and Spring Boot 2.0.x, I didn't get any new information but I'm sure that all attendees that were new to these releases could get an insight into the roadmap and features presented by <a href="https://twitter.com/springjuergen" target="_blank">Juergen Hoeller</a> (Roadmap, Features' highlights), <a href="https://twitter.com/ankinson" target="_blank">Andy Wilkinson</a> (Actuator) or <a href="https://twitter.com/madhurabhave23" target="_blank">Madhura Bhave</a> (Spring Boot 2.0).<br /><br />Unfortunately I had my flight back to Poland too early to attend talks of <a href="https://twitter.com/spencerbgibb" target="_blank">Spencer Gibb</a> (Introducing Spring Cloud Gateway), <a href="https://twitter.com/MGrzejszczak" target="_blank">Marcin Grzejszczak</a> (Continuous Deployment of your Application), and <a href="https://twitter.com/JakubPilimon" target="_blank">Jakub Pilimon</a> (Testing your Message-Driven Application), but as I already had a possibility to see those presentations during polish conferences and meetups I'm sure they rocked the place!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Now something about myself. First day of conference, at 5:30 PM, I started my talk about <a href="https://speakerdeck.com/bslota/springio-2018-dynamic-configuration-management-in-microservice-architecture-with-spring-cloud" target="_blank">Dynamic Configuration Management in Microservice Architecture with Spring Cloud</a>, and... I had a full room. If you don't believe me, look at this photo:</div>
<div style="text-align: justify;">
<br /></div>
<div class="separator" style="clear: both; text-align: justify;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJCGGjR_wnAOf6JecMxS5IeJX23TeZhqpn5XzrpaB3UYKgIEN-IAoiygVvFdfGjokaz-bIY6VRaMyEB8Doh44HQriGrxo_JiQjpLTqM0NfmVq2n6uFcNAYnfOHgWUZav05IFkItAvZkUqO/s1600/IMG_20180524_172656_HHT.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1197" data-original-width="1600" height="476" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJCGGjR_wnAOf6JecMxS5IeJX23TeZhqpn5XzrpaB3UYKgIEN-IAoiygVvFdfGjokaz-bIY6VRaMyEB8Doh44HQriGrxo_JiQjpLTqM0NfmVq2n6uFcNAYnfOHgWUZav05IFkItAvZkUqO/s640/IMG_20180524_172656_HHT.jpg" width="640" /></a></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The best thing about the talk is that I got fantastic feedback from the audience. People were approaching me, shaking my hand, asking questions, and from many of them I heard that it was the best talk of the day. This is exactly what keeps me going! Thank you all for your precious feedback!</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
From this place I wanted to thank <a href="https://twitter.com/sergialmar" target="_blank">Sergi Almar</a> for giving me a chance to speak in front of such a fantastic audience and for organizing this great event. Well done, Sergi! Many thanks to <a href="https://twitter.com/HLTechCentre" target="_blank">HL Tech</a> as well for handling all the logistics and supporting my speaker's career all the way through.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
I hope to join the next edition of Spring I/O. See you next year! Cheers! </div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
Bartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.com23tag:blogger.com,1999:blog-3619983083169551150.post-61619932362615313662018-05-28T10:02:00.000+02:002018-05-28T10:02:47.892+02:00Microservices - what you give and what you get<div>
<div style="text-align: justify;">
<span style="font-family: inherit;">If you read my article about <a href="https://bartslota.blogspot.com/2018/05/semantic-diffusion-of-microservices.html" target="_blank">semantic diffusion in microservices</a> you might recognize the title. This article is kind of a continuation, and its aim is to emphasize that having <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> and benefitting from them is possible only when we put enough effort to handle both organizational and distributed computing issues we are about to face. In subsequent paragraphs you will find what we get from the real <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> and what they take from us, as well. You won't find any concrete solutions here, but rather a high level overview of how many different, and complex problems we need to solve before we go for <span style="font-family: "courier new" , "courier" , monospace;">microservices</span>. Read on!</span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<h2 style="text-align: justify;">
<span style="font-family: inherit; font-size: x-large;">Multi-dimensional autonomy</span></h2>
<span style="font-family: inherit;"><span style="text-align: justify;"><br /></span>
<span style="text-align: justify;">One of main advantages of </span><span style="text-align: justify;"><span style="font-family: "courier new" , "courier" , monospace;">microservice</span></span><span style="text-align: justify;"> architecture is that each </span><span style="text-align: justify;"><span style="font-family: "courier new" , "courier" , monospace;">microservice</span></span><span style="text-align: justify;"> is an autonomous unit. What does the autonomy mean? Well, we can analyze it from numerous perspectives.</span></span></div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<h3 style="text-align: justify;">
<span style="font-family: inherit; font-size: large;">Deployment</span></h3>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><span style="font-family: inherit;">First of all, an autonomous service</span><span style="font-family: inherit;"> can be deployed at will, independently from other services. The basic way to provide autonomy is to clearly separate business capabilities, so that our bounded contexts don't leak to other services and create tight coupling. If a </span><span style="font-family: "courier new" , "courier" , monospace;">microservice</span><span style="font-family: inherit;"> is autonomous it can be characterized with high cohesion. Now cohesion is a term adapted from physics and in this context high cohesion means that all parts of the application (expressed in source code) are very strongly connected and it requires a lot of energy to separate a thing from it.</span></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<h3 style="text-align: justify;">
<span style="font-family: inherit;"><span style="font-family: inherit; font-size: large;">Technology</span></span></h3>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;">Autonomy is also about technology. Of course while developing our applications you should choose technologies wisely so that they are aligned with company's competences and strategy. However, you should be able to create applications with technology stack that differs from other services. It means that you cannot bind your interfaces with particular technology - your API should be technology agnostic.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<h3 style="text-align: justify;">
<span style="font-family: inherit; font-size: large;">Data management</span></h3>
<span style="font-family: inherit;"><span style="text-align: justify;"><br /></span>
<span style="text-align: justify;">Another thing worth mentioning is that </span><span style="text-align: justify;">microservices</span><span style="text-align: justify;"> are not only about the code - these are databases as well. Firstly, each </span><span style="text-align: justify;">microservice</span><span style="text-align: justify;"> needs to manage data it uses on its own. Secondly, even if you identify bounded contexts perfectly, but some of your services use the same database (schema) your applications will still be coupled, and you won't be able deploy them independently, and in case of a database failure all of them will be unavailable.</span></span></div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<h3 style="text-align: justify;">
<span style="font-family: inherit; font-size: large;">Scalability</span></h3>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;">There are two main reasons to scale our application. The first one is because we want to serve a bigger load. The second one is about resilience that we want to provide in case of failure. In a monolithic architecture we need to scale the whole system with all its components. It is often a pain that the only way to scale a monolith is vertical scaling by adding more CPU or memory. With microservices, in contrary, we have autonomy, which give us the ability to scale applications horizontally, by adding new nodes independently and even automatically.</span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<h3 style="text-align: justify;">
<span style="font-family: inherit; font-size: large;">Resilience</span></h3>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;">I already mentioned resilience in the previous paragraph, but I need to add that apart from providing resilience in the scope of a single service, autonomy gives us the possibility to isolate problems and errors within particular services, so that other ones are not affected, and thus, the system can still work.</span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div>
<h3 style="text-align: justify;">
<span style="font-family: inherit; font-size: large;">Organization culture</span></h3>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><span style="font-family: inherit;">Last but not least, autonomy is also about organization culture. Each </span><span style="font-family: inherit;">microservice</span><span style="font-family: inherit;"> should be managed and developed by a single agile team, that takes full responsibility for its whole lifecycle. In order to deliver the best software possible, the team needs to have the power to decide about how people within the team will work.</span></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<span style="font-family: inherit;"></span><br />
<h2 style="font-size: xx-large; text-align: justify;">
<span style="font-family: inherit;">
<span style="font-family: inherit;"><span style="font-size: x-large;">You don't get it for free</span></span></span></h2>
<span style="font-family: inherit;">
</span>
<div style="text-align: justify;">
<span style="font-family: inherit;">Tradeoffs - they are everywhere. Microservices can give us a lot of benefits. Both business and tech people can drink from the chalice as long as they make the sacrifice. Below you will find things, you need to provide in order to call your architecture a microservice one.</span></div>
<span style="font-family: inherit;">
<div style="text-align: justify;">
<br /></div>
</span></div>
<h3 style="text-align: justify;">
<span style="font-family: inherit;"><span style="font-family: inherit; font-size: large;">Service discovery</span></span></h3>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;">In a traditional environment, where applications run on physical hardware, and their locations are relatively static, services may communicate each other using simple, file based configuration with predefined URLs. However in a cloud-based microservices infrastructure, where a service can have multiple instances with dynamically assigned resources (especially hosts) relying on a static configuration won't be sufficient. In such situations, services should discover each other dynamically using their identifiers (codes/names). And that is what service discovery is all about. In this area you have two options - server-side service discovery and client-side service discovery. In both cases each service instance registers itself in service registry. In the former case calls are directed through a load balancer that queries the registry and forwards requests to the target instances that are currently available. Functionality like this is provided by platforms like Amazon or Kubernetes. In the latter case, though, each application queries the registry itself and it is up to this application to choose the proper instance to call (client-side load balancing). A good example of this is Eureka. If you don't use any of the mentioned options, you neither have scalability nor autonomy, as adding new instance of dependent service or deploying it on some other host implies the necessity of configuration changes in every application that communicates with it.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<h2 style="text-align: justify;">
<span style="font-family: inherit; font-size: large;">Scalability and load balancing</span></h2>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><span style="font-family: inherit;">Horizontal scaling is not only about increasing the number of service instances. It must be also transparent to service consumers (</span>you shouldn't do anything when the instance count changes<span style="font-family: inherit;">), so you need to use either client-side or server-side load balancing, so that the traffic can get to new instances without any extra manual work. When we use cloud platforms like Amazon, Kubernetes, we can scale our applications automatically with the respect to configured policies.</span></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<h2 style="text-align: justify;">
<span style="font-family: inherit; font-size: large;">Design for failure</span></h2>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><b>We cannot avoid failures.</b> It is not always about our code, it might be network or hardware failures as well or it might be too many requests that saturated CPU or memory of our components. A failure in monolithic application usually means total unavailability. In enterprise systems that I worked with resilience was improved by horizontal scaling but if some component was erroneous - the error eventually occurred in all instances and couldn't be easily isolated. In general, prevention is not as vital as coping with failure when it occurs and this is what changes our mindset, especially in the context of microservice architecture, where the number of components that may fail is much higher.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;">Topics that we have already covered should give you some idea of how to handle the failures, but let's systematize it. Regardless the reason, if our the application that we are trying to communicate with is not responsive, we can always scale it up. Then we will be able to both serve bigger traffic and stay resilient in case of a failure. Sometimes, though, we have limited resources and it is impossible to scale our application. What then? In order not to slow down our system as a whole we should set up timeouts. Random backoff policies would also be a good idea to choose, so that we won't overload the target application with retries. We should also think about isolating failures through mechanisms like circuit breaker, so that we prevent the failure to cascade up to clients. My intention is not to describe all possibilities but rather emphasize how difficult it is to deal with failures, especially when they are unavoidable.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;">Almost every article about microservices, especially in terms of databases, contains a few words about the CAP Theorem. It couldn't be any different here. Like we all know, software development is about tradeoffs. In our every day work we make decisions that sacrifice one thing to give us another - the more valuable one for us in a given context. The same choice we face with Consistency, Availability and Partition tolerance. If for example due to some network failure we cannot perform data replication among database nodes, we need to make a decision about what to sacrifice - availability or consistency. If we want to handle requests (keep availability) despite failure we must know that we are working in non consistent (eventually consistent) environment until the problem is solved. If we cannot accept inconsistency at any moment, we need to reject all requests - resign from availability. The vital thing about CAP theorem is that some parts of our system might AP and some CP - we can make the decision on a component level.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<h2 style="text-align: justify;">
<span style="font-family: inherit; font-size: large;">Monitoring</span></h2>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;">When our system consists of a single application residing on one or just few nodes then you can pretty easily locate log files and look into them in case of any problems. If there are no errors, but your users experience very long response times, then you can probably profile your application, and look for bottlenecks in one place. In the distributed environment things get complicated. First of all you have dozens of applications running with several instances each on different nodes, which are very often assigned dynamically, and finding the place where something went wrong is a very tough task. Secondly, if it is not about an error that you can find in logs but about the responsiveness, then finding the guilty is even worse. So with microservice architecture we must accept and handle the complexity in terms of system monitoring.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;">Now the first thing you should provide is a central system that would aggregate logs from all applications' instances and that would enable you to analyze them in one place. A good example would be the ELK stack (Elasticsearch, Logstash, Kibana). Secondly, you should also provide a tracing solution so that you could find out which request exactly caused a problem. In this field an example of a fantastic solution is Spring Cloud Sleuth, which can be easily enhanced with Zipkin, that helps you analyze and visualize dependencies among services in your infrastructure and latencies. With this set of tools you can easily find out which part of your system creates the bottleneck. When we are talking about application logs, we think about finding the source of an error that already occurred. In microservice architecture real-time monitoring of hosts, CPUs, memory, network latencies, response times, etc. is priceless as well. Using tools like Grafana + Graphite and properly configuring your applications you can easily visualize all those metrics. Setting proper threshold values you can trigger alarm and react to it before something really bad happens.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;">This paragraph might seem to be an option in microservice environment. One may say "I can search for logs in each instance. It takes some time but I can deal with it". If you have 3 applications then it might work, but if you have dozens of them the amount of time that you spend on looking for problems will eventually discredit all other benefits you gain with microservice architecture as it would be completely not maintainable. We need to agree, that microservices bring a lot of complexity in the context of system monitoring, but this is something we literally need to provide.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<h2 style="text-align: justify;">
<span style="font-family: inherit; font-size: large;">Continuous delivery</span></h2>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;">Yet another characteristic of microservice architecture is that when you have small, independent applications, you can provide changes much quicker, and they have much smaller impact on the whole system comparing to monolithic approach. That means that you should be ready to deploy the features as quickly as you develop them. The first step to achieve this is to use so called Continuous Integration so that every change you provide into your codebase is automatically verified in terms of integrity with already existing version - does your code compile? do your tests pass successfully? is static code analysis result positive? These and maybe more conditions are checked within your build pipeline. This is the basis of continuous delivery. By delivery I mean producing some artifact, that is a potential release candidate and can be safely deployed on production. It might be a .jar file or even more platform specific creature like docker image for example. The reason for this is that in microservice architecture we need to respond to changes quickly and be ready to deploy them right after pushing the code to repository.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;">Of course sometimes it is not so easy to deploy our changes to production. There might be some regulations and processes containing some manual work, like user acceptance testing, or just clicking the "deploy" button by someone in charge, but this is not how it should look like, as development teams should be a part of company that is responsible for the services throughout their whole lifecycle. Drawing a line between developers, testers, and people in charge is not healthy, but in terms of delivery, we - developers should be ready for call.</span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
</div>
<div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<h2 style="text-align: justify;">
<span style="font-family: inherit; font-size: x-large;">Conclusions</span></h2>
</div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;">Microservices has been very popular for a couple of years, and there are strong reasons for that. The autonomy that concerns organization culture, technology, deployment, data management, scalability and resilience brings a lot of value for both technical and business people, but at the same time it requires a lot effort to reach it. Service discovery, load balancing, design for failure, monitoring, continuous delivery are the very base we need to have, and it is not that cheap after all. Before we go for microservices we need to be aware of all these things. I hope that after reading this article, you will be confident to say if your infrastructure provides you the full microservice autonomy, or if you have just another distributed system. And please, care more for the words, and be pragmatic in your day to day work.</span></div>
<div style="text-align: justify;">
<span style="font-family: inherit;"><br /></span></div>
<span style="font-family: inherit;"><br /></span>Bartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.com11tag:blogger.com,1999:blog-3619983083169551150.post-88356058882332545142018-05-26T20:22:00.001+02:002018-05-27T17:30:30.108+02:00Semantic diffusion of microservices<div style="text-align: justify;">
It has been a couple of years already that we can hear <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> buzzword being mentioned in the IT world. "<i>We have <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> doing this</i>", "<i>Oh, let's write a <span style="font-family: "courier new" , "courier" , monospace;">microservice</span> doing that</i>". If you are completely new to this term you might event think that these guys are smart, experienced, and they are up to date with the latest architectural trends in software development. But if you are really carrying about the words and their meaning, you will quickly get pissed. Right now it is really annoying to hear that the word <span style="font-family: "courier new" , "courier" , monospace;">microservice</span> has become a replacement for the name of almost every application that has been developed. At the same time, programmers often seem to treat <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> just as a set of relatively small applications forgetting both that there are people behind that concept and that they are entering the distributed world, and committing so called fallacies of distributed computing. I might seem to be overreacting because the definition of a <span style="font-family: "courier new" , "courier" , monospace;">microservice</span> is still floating, but for all those years numerous design patterns, good practices and heuristics have been well established, and clearly manifest what <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> are all about.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Do we really need to keep up with times only by using some buzzwords? Or maybe we are trying to find an excuse for not giving enough effort to think of what <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> really are? Or maybe we just want to feel that we are trendy? Regardless the motivation, it is not the first time in the history when we can observe such phenomenon. Even in the late 80s when there was a hype about Object Oriented Programming, developers called every piece of their software an object although they were usually nowhere near the OOP principles. Martin Fowler in one of his articles came up with the term of semantic diffusion:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: center;">
<i>Semantic diffusion occurs when you have a word that is coined a person or group, often with a pretty good definition, but then gets spread through the wider community in a way that weakens that definition. This weakening risks losing the definition entirely - and with it any usefulness to the term.</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
...and this is exactly what I'm talking about. The aim of this article is to shortly tell you what <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> are, how many different areas they cover, and how many things they require and imply. Then I hope you will revise your organization and software architecture and think carefully if you are really doing <span style="font-family: "courier new" , "courier" , monospace;">microservices</span>. I would like to encourage everyone to care for the words and to defend their true meaning.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<h2 style="text-align: justify;">
<span style="font-size: x-large;">Does size matter?</span></h2>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
The first thing that we should talk about is what micro means? How little is little enough and how little is too little? If you are waiting for a concrete line count range that would classify your application as <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> within a given technology stack (language, platform, framework, etc.) - then sorry - <b>there is none</b>.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
There is a couple of <span style="font-family: "courier new" , "courier" , monospace;">heuristics</span>, though. The first one is that if you feel that you start loosing the idea of how things in your code work - then it is probably too big (assuming you wrote it cleanly). Another rule of thumb was given by Jon Eaves, who said that if your application is a <span style="font-family: "courier new" , "courier" , monospace;">microservice</span> it should be rewritable in two weeks. We might also go in another direction - when communication and maintenance costs of your application are much bigger than gains from its usability. This happens very often when we split our domain to separate services too eagerly, and we end up in having too granulated applications doing almost nothing. This is what we call <span style="font-family: "courier new" , "courier" , monospace;">nanoservice</span> - yep, nano is not <span style="font-family: "courier new" , "courier" , monospace;">micro</span> - it is considered an anti-pattern. Of course a very small application is nothing wrong as long as it really brings you enough value that you are ready to accept the costs of distributed computing which we already mentioned.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
All these heuristics might make sense in some specific contexts - when we know our business domain well, we have years of experience in the field of <span style="font-family: "courier new" , "courier" , monospace;">microservices</span>, we learn what micro means for us. In general, however, <span style="font-family: "courier new" , "courier" , monospace;">DDD</span> is what we should follow. If we implement an application for our <span style="font-family: "courier new" , "courier" , monospace;">Core Domain</span> - we might not know how complex it is from the very beginning and it is the complexity that may determine the service size. It is the business functionalities that we care for - not the size. Such application must gather things related to exactly one bounded context so that we can provide high cohesion, and decoupling/autonomy. However, if we implement applications from <span style="font-family: "courier new" , "courier" , monospace;">Supporting</span> or <span style="font-family: "courier new" , "courier" , monospace;">Generic Subdomains</span> should we care about the size? Not really, as this is not what we get money for.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<i>Summing up, service size from any range won't make our application a <span style="font-family: "courier new" , "courier" , monospace;">microservice</span>, so if you try to call you service a micro one and justify that with the number of your code lines you are just doing it wrong. Similarly, if you mix business responsibilities among numerous applications, breaking your core domain's bounded contexts, you loose cohesion and autonomy, which means you are far away from real <span style="font-family: "courier new" , "courier" , monospace;">microservices</span>.</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<h2 style="text-align: justify;">
<span style="font-size: x-large;">Conway's Law</span></h2>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<b><span style="font-family: "courier new" , "courier" , monospace;">Microservices</span> are people</b>. We are not developing software for fun - someone is paying us for bringing value. Now, how many times were you angry at the way applications in your company are communicating? It didn't happen just like that, and it didn't need to be developers' fault. According to Conway's Law, every organization that creates a system will eventually create one that will mirror the communication structure from within this company. Developers often tend to ignore business people, they seem to know what's best and how to solve all their problems. We know how to code, but we might not know the business. Let's talk with people who will use our systems, discover their processes, help them in locating bottlenecks, and... maybe go for <span style="font-family: "courier new" , "courier" , monospace;">DDD</span> - if both developers and business are on the same page, our services will surely reflect that. Developers will be organized in teams corresponding to bounded contexts, and business will know exactly of what's going on in the company.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<i>If you underestimate human factor and ignore the voice of the business you will keep chaos in your services as well. If you don't discover the domain well enough, you won't be able to keep your applications cohesive, and thus you will lose their autonomy - yeah, it means there won't be any <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> any more.</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<h2 style="text-align: justify;">
<span style="font-size: x-large;">What you give and what you get</span></h2>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<span style="font-family: "courier new" , "courier" , monospace;">Microservices</span> wouldn't have been such a popular architecture style if it hadn't been for the concrete benefits that they give us. What benefits I am talking about? <span style="font-family: "courier new" , "courier" , monospace;">Autonomy</span>.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
High cohesion, which is the main <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> characteristics, implies applications’ autonomy. Now the autonomy is multidimensional. It can refer to agile teams’ structure, independent deployments, technology stack, data management, scalability. However, we don’t get it for free. Service discovery, load balancing, design for failure, monitoring, continuous delivery - these are the things we need to provide to deal with the problems of distributed computing, and fully utilize <span style="font-family: "courier new" , "courier" , monospace;">microservice</span> architecture benefits. As this is out of the scope of this article, details on this topic you will find in a separate article.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<i>Each vector of <span style="font-family: "courier new" , "courier" , monospace;">microservice</span> autonomy space must be addressed within your infrastructure, and on the organizational level. There are undeniable benefits, but they are hard to deliver if you don’t have the culture in your company, or don’t solve issues of distributed systems first. <span style="font-family: "courier new" , "courier" , monospace;">Microservices</span> give, but they take as well.</i></div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<h2 style="text-align: justify;">
<span style="font-size: x-large;">Be pragmatic</span></h2>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
As it was already said, in our day to day work we are supposed to bring value, not to be rock stars. If <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> is what you find useful in your case, go for it, but be pragmatic and don't forget that the value is what you are paid for. Remember that <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> are about distributed computing, and before you go into development, think carefully how you will manage all the problems of distributed environment, because they will occur for sure. Make small steps, providing solutions one by another and you will quickly learn a lot, and at the same time you will know if this is what you expected from <span style="font-family: "courier new" , "courier" , monospace;">microservices</span>. Don't worry if you start with monolith, it is not a shame. We, the developers, are adults (mostly), and we are to make conscious decisions as software development is about tradeoffs. Don't pursue buzzwords, study them carefully instead, experiment, use well defined patterns, choose solutions that fit you best, and believe me, you will finally feel confident with them and they won't be buzzwords for you anymore. If the definition won't be crystal clear, the anti-definition will. And for me it is better to tell "<i>I have a distributed system where I use <span style="font-family: "courier new" , "courier" , monospace;">microservice</span> architecture patterns</i>" than call everything a "<i><span style="font-family: "courier new" , "courier" , monospace;">microservice</span></i>", as the second one is really hard to defend.</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
<br /></div>
<h2 style="text-align: justify;">
<span style="font-size: x-large;">Conclusions</span></h2>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: justify;">
Summing up, <span style="font-family: "courier new" , "courier" , monospace;">microservice</span> architecture has become a popular buzzword that every developer would like to use to keep up with the latest architectural trends but <span style="font-family: "courier new" , "courier" , monospace;">microservices</span> are not about nomenclature - these are concrete rules, tradeoffs, decisions, patterns, problems and specific philosophy. Semantic diffusion that we observe nowadays make this term devaluated. In this article you got a brief overview of what stands behind the definition of <span style="font-family: "courier new" , "courier" , monospace;">microservices</span>, and what does not. I will end this article with one more Martin Fowler's quote:</div>
<div style="text-align: justify;">
<br /></div>
<div style="text-align: center;">
<i>"(...) a good term is worth fighting for - particularly since the only bullets you need are words"</i></div>
<div style="text-align: center;">
<i><br /></i></div>
<div style="text-align: center;">
<i><br /></i></div>
Bartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.com21tag:blogger.com,1999:blog-3619983083169551150.post-47286036265956429682018-02-01T13:25:00.000+01:002019-12-17T11:40:57.681+01:00Dynamic configuration management in microservice architecture with Spring CloudIn the scary world of monolithic applications we succeeded in working out numerous design patterns and good practices. When we move towards distributed systems, we should apply them carefully, bearing in mind that in microservice infrastructure we need to deploy, scale, and reconfigure our systems much quicker. In this article I will focus on configuration issues, emphasizing why keeping properties/yml files with your codebase is good, and when it might not suffice. I will also give you an overview of how you can improve your configuration management with Spring Cloud, and how easy it is to reconfigure your application live without rebuilding or rebooting it.<br />
<br />
<h2>
<span style="font-size: x-large;">Configuration files</span></h2>
<br />
It seems to be obvious now to keep your configuration outside of the code, so that anyone can update it without the struggle to find a proper line to be modified. However I find it not so evident for people to build applications independently from the environments they are running on. Anyway, making your build environment-dependent is not a good idea, as you won’t know what environment is a particular package supposed to be used for (unless you provide some crazy naming strategy for your artifacts, but don’t tell me about them, I’m frightened enough while thinking of it). It should be a natural thing to create profiles related to your environments and split the config among profile-dependent .properties files (or separate them within the .yml file), building one profile-agnostic deployment package, passing a proper profile/config file to your application while running it. If you do so, you will see a light in the tunnel. But the light is dimmed as there is still a couple of things you should be aware of.<br />
<br />
<i>Please note that environment is not the only thing that may define the profile. As an example: in projects that I was working on, we had to deploy the same application for three different countries, where each country had its own configuration. Then we had 9 combinations of profiles: dev, test, prod for each of the three countries.</i><br />
<br />
First of all, having config files bounded with the deployment package, you need to rebuild and redeploy it each time some property changes. It is a horror when your configuration changes more frequently than the code. Although you can always keep some of your configuration outside of the jar file, it will usually require rebooting your app after updating your properties there.<br />
<br />
Moreover, having a distributed system, where scalability is one of its key features you need to be able to react to configuration changes quickly, and apply them to all instances that are currently running. Redeploying them one by one can be a tough task if it is not properly automated.<br />
<br />
It might also be a case that developers have restricted access to credentials to production databases, external services, etc. In one of monolithic applications that I was working on, the production deployment required client’s administrator to set particular properties in an external config file before starting the application. No one had any trace about what was changed there, when it happened and by whom. I hope you don’t need any more arguments to see that this is a very bad idea to do so.<br />
<br />
You can see now how complicated and confusing configuration issues might be. Microservices are by definition small independent applications realising some business logic within a bounded context. Each microservice, before being deployed, must be a bundled unit that can be run on any desired environment: dev, test, prod, etc. without the need of rebuilding it for each of them. We should be able to scale and reconfigure them at will, and keep all sensitive settings secured if needed. This is the moment when Spring Cloud Config comes to the rescue. But before that, lets have a look at our simple infrastructure example, that you can find on my github account.<br />
<br />
<h2>
<span style="font-size: x-large;">Example Overview</span></h2>
<div>
<br /></div>
<div>
We have two simple microservices: <a href="https://github.com/bslota/cloud-config/tree/master/customer-manager" target="_blank">Customer Manager</a> and <a href="https://github.com/bslota/cloud-config/tree/master/product-manager" target="_blank">Product Manager</a>, that realise some business logic regarding Customers and Products respectively. The access to both of our applications is available from the WWW only through the <a href="https://github.com/bslota/cloud-config/tree/master/gateway" target="_blank">Gateway</a>, which is an implementation of <a href="https://microservices.io/patterns/apigateway.html" target="_blank">API Gateway pattern</a> with the help of <a href="https://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#_router_and_filter_zuul" target="_blank">Zuul Router</a>. Each application registers itself (we are using <a href="http://microservices.io/patterns/client-side-discovery.html" target="_blank">client-side service discovery</a>) in <a href="https://github.com/bslota/cloud-config/tree/master/discovery-server" target="_blank">Eureka Discovery Server</a>, which maintains service registry. In our case all microservices communicate with each other via HTTP protocol, and all of them are of course SpringBoot applications.</div>
<div style="clear: both; text-align: left;">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRN0J1SaQShp5eDh3vflWFa52I7YDJkPeRad3mUuf1SuhK8svixft4cV4GTkzn0uYYbUbWCGAoHbjg09sPxl7JJ07g4k2SKCPsnFGoPROCPzYPiBPT4zs0gx5Zxd9qU72P9wnt8sfCjQHy/s1600/config-example-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="465" data-original-width="707" height="420" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRN0J1SaQShp5eDh3vflWFa52I7YDJkPeRad3mUuf1SuhK8svixft4cV4GTkzn0uYYbUbWCGAoHbjg09sPxl7JJ07g4k2SKCPsnFGoPROCPzYPiBPT4zs0gx5Zxd9qU72P9wnt8sfCjQHy/s640/config-example-2.png" width="640" /></a></div>
<br /></div>
<br />
When we set up our environment we can take a look at Discovery Server dashboard, where we can see that all three microservices successfully registered themselves in Eureka. This in turn means that they will be able to communicate with each other without preconfiguring their exact URLs, but using application names to find them out from Eureka Server instead.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilr8rEISxRShmLdLDbYjxv2g438i83ovXSeSBMUOqP6FnTwvjaZfHeQC1ZrAqvAMlOSt8tKjm59DVeMJ-i1JawpPrezsmlAW2jSynVoQJfjT6s_gf2nUPct3AV6UWgF82pXD80D0uoy6n6/s1600/eureka-no-config.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="727" data-original-width="1600" height="290" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilr8rEISxRShmLdLDbYjxv2g438i83ovXSeSBMUOqP6FnTwvjaZfHeQC1ZrAqvAMlOSt8tKjm59DVeMJ-i1JawpPrezsmlAW2jSynVoQJfjT6s_gf2nUPct3AV6UWgF82pXD80D0uoy6n6/s640/eureka-no-config.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<h2>
<span style="font-size: x-large;">Spring Cloud Config</span></h2>
<br />
Having our example in place, and bearing in mind all configuration issues that we've discussed, let's get straight to the solution. Spring Cloud Config is a tool that provides both server and client-side support for managing configuration in distributed environment in a centralized manner.<br />
<br />
<h2>
EnvironmentRepository</h2>
<br />
Config server can be treated as a remote property source. It can be backed by numerous storage providers, like Git (which is the default setting), SVN, or distributed file system. You can even have more than one storage at the same time. With Git we can easily manage configuration files for any application and any environment. Moreover, we gain access control, which means we can decide who can modify particular files (for example restricting access to production properties). We also have full traceability - we know who changed what, and when, and we can easily revert those changes.<br />
<br />
The way we want to store our data is defined by <span style="font-family: "courier new" , "courier" , monospace;">EnvironmentRepository</span> interface:<br />
<pre class="brush:java;">public interface EnvironmentRepository {
Environment findOne(String application, String profile, String label);
}
</pre>
<br />
It tells us a lot about how things are organized on both config server and backing service. You can see that in order to get a particular environment, we need to locate it with following variables:<br />
<ul>
<li>application - application name</li>
<li>profile - application profile</li>
<li>label - additional parameter used by the backing service (branch name, tag, etc. in case of Git repository)</li>
</ul>
In order to get proper configuration clients can use following endpoints:<br />
<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">/{application}-{profiles}.[properties|yml|yaml|json]</span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">/{label}/{application}-{profiles}.[properties|yml|yaml|json]</span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">/{application}/{profile}[/{label}]</span></li>
</ul>
<br />
<h2>
Embedded Config Server</h2>
<br />
Benefiting from spring's convention over configuration approach, we can set up our <a href="https://github.com/bslota/cloud-config/tree/master/config-server" target="_blank">Config Server</a> in just a few steps. First of all, you need to declare following dependency:<br />
<pre class="brush:xml;"><dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-config-server</artifactid>
</dependency>
</pre>
<br />
and mark config class with
<span style="font-family: "courier new" , "courier" , monospace;">@EnableConfigServer</span> annotation:<br />
<pre class="brush:java;">@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}</pre>
<br />
We will also need to define some properties inside our <span style="font-family: "courier new" , "courier" , monospace;">application.yml</span> file, like below:<br />
<pre class="brush:text;">spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/bslota/config-repository.git
clone-on-start: true
search-paths: 'config/{application}'
server:
port: 8888
</pre>
<br />
You can see here that we set port number to 8888, which is a conventional and recommended setting. We also told our application to look for config files in a <a href="https://github.com/bslota/config-repository" target="_blank">github repository</a>, and clone it right after the startup. Cloning might take a while increasing the booting time, but as soon as the server is up it will be able to serve configuration quickly from the very first request. There is also a <span style="font-family: "courier new" , "courier" , monospace;">search-paths</span> property specified, which tells that config files for each application will be placed in proper folders under the <span style="font-family: "courier new" , "courier" , monospace;">config/</span> directory. While configuring Git as backing service, you can use {<span style="font-family: "courier new" , "courier" , monospace;">application</span>}<span style="font-family: inherit;">,</span> {<span style="font-family: "courier new" , "courier" , monospace;">profile}</span> and {<span style="font-family: "courier new" , "courier" , monospace;">label}</span> placeholders, so that it fits your needs. Here we have a very basic configuration, where properties for all applications are being held in one common repository, but you could easily apply <span style="font-family: "courier new" , "courier" , monospace;">one repo per profile</span> or <span style="font-family: "courier new" , "courier" , monospace;">one repo per application</span> strategy by using <span style="font-family: "courier new" , "courier" , monospace;">{profile}</span> and <span style="font-family: "courier new" , "courier" , monospace;">{application}</span> placeholders in <span style="font-family: "courier new" , "courier" , monospace;">spring.cloud.config.server.git.uri</span> property respectively. More details you will find in documentation.<br />
<br />
In order to keep the <span style="font-family: "courier new" , "courier" , monospace;">Config Server</span> consistent with our existing infrastructure, we will register it in <span style="font-family: "courier new" , "courier" , monospace;">Eureka Discovery Server</span>. Now our system looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhENybrGkKgYRsiq-QS_ha_-cTpoFfvz5Z0g7-OE9BA_jQFZF2LtCx_WEIGlZssVgc6KnH1TmsUlSdoO8vHQenKhJ7_q290Vo1CiRB3Is9NQGjMGgyvaKYgI1G32_LKfoLpcDUM_SiBnlnp/s1600/config-example-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="485" data-original-width="706" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhENybrGkKgYRsiq-QS_ha_-cTpoFfvz5Z0g7-OE9BA_jQFZF2LtCx_WEIGlZssVgc6KnH1TmsUlSdoO8vHQenKhJ7_q290Vo1CiRB3Is9NQGjMGgyvaKYgI1G32_LKfoLpcDUM_SiBnlnp/s640/config-example-3.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<br />
And here is the shot from Eureka Server dashboard:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBbxCMtiSheplw_IT4rEjHxcD9E461Z8yN_lGObtTbErCXQeIZNPYzAURK5ooIXk4FR1wR40LgmFDfg3TjNPONjyj_RlYq77jYv3cxePhsttChmLmgRWHb0aTFWOlXy16xVykGnlLjJMBQ/s1600/eureka-w-config.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="771" data-original-width="1600" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBbxCMtiSheplw_IT4rEjHxcD9E461Z8yN_lGObtTbErCXQeIZNPYzAURK5ooIXk4FR1wR40LgmFDfg3TjNPONjyj_RlYq77jYv3cxePhsttChmLmgRWHb0aTFWOlXy16xVykGnlLjJMBQ/s640/eureka-w-config.png" width="640" /></a></div>
<br />
Config Server is now the central part of our infrastructure that is supposed to both store and serve configuration for all other microservices. Thus, you should always scale it properly, so that your system stays resilient.<br />
<br />
<h2>
Spring Cloud Config Client</h2>
<br />
Okay, we have our Git repository in place, and we have our Config Server up and running. It's high time we start using it. Before I show you how to connect our applications with the server, I need to tell you a few words about so-called <span style="font-family: "courier new" , "courier" , monospace;">bootstrap context</span>. In a big short, a bootstrap context in Spring Cloud applications is a parent for main application context and it is used for the purpose of loading and decrypting (if needed) properties from external sources. It is defined in <span style="font-family: "courier new" , "courier" , monospace;">bootstrap.yml</span> file unless otherwise specified. What you should put in this file is information about how to locate config server, and properties that are necessary to properly identify environment there. Do you remember <span style="font-family: "courier new" , "courier" , monospace;">application</span>, <span style="font-family: "courier new" , "courier" , monospace;">profile</span>, and <span style="font-family: "courier new" , "courier" , monospace;">label</span> placeholders? This is exactly what we need to pass to the server, and we can do it with following properties:<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">spring.cloud.config.name</span> - by default it is equal to <span style="font-family: "courier new" , "courier" , monospace;">spring.application.name</span> property value</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">spring.cloud.config.profile</span> - by default equal to comma separated list of currently active profiles</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">spring.cloud.config.label</span> - its default value is valuated on the server side and is equal to <span style="font-family: "courier new" , "courier" , monospace;">master </span>if Git is used as backing service</li>
</ul>
Having such well assumed defaults, all we need to set in <span style="font-family: "courier new" , "courier" , monospace;">bootstrap.yml</span> is <span style="font-family: "courier new" , "courier" , monospace;">spring.application.name</span> property.<br />
<br />
In order to connect to the config server, we need to declare following dependency:<br />
<pre class="brush:xml;"><dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-config</artifactid>
</dependency>
</pre>
As soon as we have it, we need to choose one of two available bootstrap strategies. First one (the default one) is <span style="font-family: "courier new" , "courier" , monospace;">config first bootstrap</span>. It assumes that you define config server URI explicitly in <span style="font-family: "courier new" , "courier" , monospace;">bootstrap.yml</span> file with <span style="font-family: "courier new" , "courier" , monospace;">spring.cloud.config.uri</span> property. In this setup, <span style="font-family: "courier new" , "courier" , monospace;">bootstrap.yml</span> file will have following content:<br />
<pre class="brush:text;">spring:
application:
name: # microservice name
cloud:
config:
uri: http://localhost:8888
</pre>
<br />
The drawback of this strategy is that we cannot benefit from Config Server being registered in service discovery as we are defining its URI explicitly (this problem won't apply if we are using server-side service discovery). We can get rid of this problem by using <span style="font-family: "courier new" , "courier" , monospace;">discovery first bootstrap</span> strategy. In this approach, our application will resolve config server's URI by its name with the help of service discovery. Of course this option has its costs as well. In order to get the configuration we need an extra network roundtrip as we need to communicate with discovery server. Now our <span style="font-family: "courier new" , "courier" , monospace;">bootstrap.yml</span> file looks like this:<br />
<pre class="brush:text;">spring:
application:
name: # microservice name
cloud:
config:
discovery:
service-id: config-server
eureka:
client:
service-url:
default-zone: http://localhost:8761/eureka/
</pre>
<br />
Now we can easily move the configuration of our services to our <a href="https://github.com/bslota/config-repository" target="_blank">github repository</a>.<br />
<br />
<span style="font-size: large;"><b>Manual refresh</b></span><br />
<br />
Thanks to the actuator endpoints, we can easily trigger numerous actions on each of our applications. Sending <span style="font-family: "courier new" , "courier" , monospace;">POST<span style="font-family: inherit;"> </span></span>request to the <span style="font-family: "courier new" , "courier" , monospace;">/refresh</span> endpoint we can tell the service to reload the bootstrap context (updating the environment both from remote and local property sources), rebinding <span style="font-family: "courier new" , "courier" , monospace;">@ConfigurationProperties</span> and log levels, and refreshing all beans annotated with <span style="font-family: "courier new" , "courier" , monospace;">@RefreshScope</span> annotation.<br />
<br />
To give some concrete examples, let's take a look at <a href="https://github.com/bslota/cloud-config/tree/master/customer-manager" target="_blank">Customer Manager</a> service, that has the following property set in its <span style="font-family: "courier new" , "courier" , monospace;">application.yml</span> file in <a href="https://github.com/bslota/cloud-config/tree/master/customer-manager" target="_blank">remote property source</a>:<br />
<pre class="brush:text;">"premium-email-suffix": "yahoo.com"
</pre>
<br />
and a service class annotated with <span style="font-family: "courier new" , "courier" , monospace;">@RefreshScope</span> annotation, that depends on this property's value.<br />
<pre class="brush:java;">@Service
@RefreshScope
class CustomerService {
private final CustomerRepository customerRepository;
private final String premiumEmailSuffix;
CustomerService(CustomerRepository customerRepository,
@Value("${premium-email-suffix}") String premiumEmailSuffix) {
this.customerRepository = customerRepository;
this.premiumEmailSuffix = premiumEmailSuffix;
}
List<Customer> findAll() {
return customerRepository.findAll();
}
List<Customer> findAllPremium() {
return findAll()
.stream()
.filter(it -> it.getEmail().endsWith(premiumEmailSuffix)).collect(toList());
}
// ... other methods
}
</pre>
<br />
The service is used by <span style="font-family: "courier new" , "courier" , monospace;">CustomerController</span>, so we can easily check if our change, that we will apply in a minute, works as expected.<br />
<pre class="brush:java;">@RestController
@RequestMapping("/customers")
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping
public List<Customer> customers() {
return customerService.findAll();
}
@GetMapping(params = "premium")
public List<Customer> premiumCustomers() {
return customerService.findAllPremium();
}
// ... other methods
}
</pre>
<br />
Now if we send the following request:<br />
<pre class="brush:bash;">curl http://localhost:8085/customers?premium
</pre>
<br />
we get this response:<br />
<pre class="brush:js;">[
{
"id": 2,
"name": "Steve Harris",
"email": "steve@yahoo.com"
}
]
</pre>
<br />
Let's make an update to <span style="font-family: "courier new" , "courier" , monospace;">premium-email-suffix</span> property so that its value is now equal to <span style="font-family: "courier new" , "courier" , monospace;">gmail.com</span>, commit it, and push into <a href="https://github.com/bslota/config-repository/tree/master/config/customer-manager" target="_blank">remote repository</a>. As we had mentioned before, in order to make it visible by our application, we need to send the following request:<br />
<pre class="brush:bash;">curl -X POST http://localhost:8085/refresh
</pre>
<br />
And we can see the updated properties straight away in the response body<br />
<pre class="brush:js;">["config.client.version","premium-email-suffix"]</pre>
<br />
To be 100% sure that the manual update worked, let's try to get all premium customers again hoping that this time their emails will end with <span style="font-family: "courier new" , "courier" , monospace;">gmail.com</span>
<br />
<pre class="brush:js;">[
{
"id": 1,
"name": "Bruce Dickinson",
"email": "bruce.dickinson@gmail.com"
}
]
</pre>
<br />
Note that similar behaviour would be observed with <span style="font-family: "courier new" , "courier" , monospace;">@ConfigurationProperties</span> components.<br />
<br />
You see, it is easy, but if you have several services scaled up to a couple of instances it can make the manual refreshment a terrible experience. You need to find a proper service url and make sure that you performed the refresh to all instances. We can surely agree that it is not something that we would eagerly do. Fortunately, we can automate this process. Read on.<br />
<br />
<br />
<span style="font-size: large;"><b>Dynamic changes propagation</b></span><br />
<br />
The desired scenario would be that all services, whose properties get updated within a push into a remote repository, get notified and refreshed automatically. Thus, first of all, we need to find a way to propagate configuration changes to proper services. To solve this problem we will use <a href="https://cloud.spring.io/spring-cloud-bus/" target="_blank">Spring Cloud Bus</a>, which was built to propagate management instructions. It makes use of both actuator (by adding new management endpoints) and <a href="https://cloud.spring.io/spring-cloud-stream/" target="_blank">Spring Cloud Stream</a> (by enabling communitaction with AMQP message brokers). In our case, we will use <a href="https://kafka.apache.org/" target="_blank">Apache Kafka</a> as a message broker, and now the desired architecture would look like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_PuJZFv0ff83y1_SXBJgFx8Qfz73xtRfKt5JnNNdpR8ZjAPXLinkF0GYUdFiGkklOxQX24B7qO98O1VZsnF5jemkkjMFSHJNVVce4iiBVpfq-3imBx7qrD2rbupirDEo-zW0a4cmck41f/s1600/config-example-4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="485" data-original-width="707" height="438" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_PuJZFv0ff83y1_SXBJgFx8Qfz73xtRfKt5JnNNdpR8ZjAPXLinkF0GYUdFiGkklOxQX24B7qO98O1VZsnF5jemkkjMFSHJNVVce4iiBVpfq-3imBx7qrD2rbupirDEo-zW0a4cmck41f/s640/config-example-4.png" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
In order to enable <span style="font-family: "courier new" , "courier" , monospace;">Spring Cloud Bus</span> and connect to <span style="font-family: "courier new" , "courier" , monospace;">Kafka </span>broker, <span style="font-family: "courier new" , "courier" , monospace;">Gateway</span>, <span style="font-family: "courier new" , "courier" , monospace;">Customer Manager</span>, and <span style="font-family: "courier new" , "courier" , monospace;">Product Manager</span> services need to be altered with following dependency (don't worry, this one has transitive dependency on <span style="font-family: "courier new" , "courier" , monospace;">spring-cloud-bus</span>):<br />
<pre class="brush:xml;"><dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-bus-kafka</artifactid>
</dependency>
</pre>
<br />
and configure <span style="font-family: "courier new" , "courier" , monospace;">Zookeeper </span>nodes and <span style="font-family: "courier new" , "courier" , monospace;">Kafka </span>binders (unless you are fine with defaults)
<br />
<pre class="brush:text;">spring:
cloud:
stream:
kafka:
binder:
zkNodes: "localhost:2181"
brokers: "localhost:9092"
</pre>
<br />
Right after the startup, our services will connect to <span style="font-family: "courier new" , "courier" , monospace;">springCloudBus</span> topic.
<br />
<br />
Now our applications are ready to listen and react to refresh requests coming from message broker and determine if a particular event is dedicated to them or not.<br />
<br />
In order enable <span style="font-family: "courier new" , "courier" , monospace;">Config Server</span> to publish this kind of events (<span style="font-family: "courier new" , "courier" , monospace;">RefreshRemoteApplicationEvent </span>to be specific), we need to declare two dependencies:<br />
<pre class="brush:xml;"><dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-config-monitor</artifactid>
</dependency>
<dependency>
<groupid>org.springframework.cloud</groupid>
<artifactid>spring-cloud-starter-bus-kafka</artifactid>
</dependency>
</pre>
<br />
and configure <span style="font-family: "courier new" , "courier" , monospace;">Zookeeper </span>nodes and <span style="font-family: "courier new" , "courier" , monospace;">Kafka </span>binders in the same way as we did in the other services:
<br />
<pre class="brush:text;">spring:
cloud:
stream:
kafka:
binder:
zkNodes: "localhost:2181"
brokers: "localhost:9092"
</pre>
<br />
You already know what <span style="font-family: "courier new" , "courier" , monospace;">spring-cloud-starter-bus-kafka</span> is used for. The second dependency, though, <span style="font-family: "courier new" , "courier" , monospace;">spring-cloud-config-monitor</span> adds something more - the<span style="font-family: "courier new" , "courier" , monospace;"> /monitor</span> endpoint that accepts POST requests with information about what service needs to be refreshed. If this request gets to <span style="font-family: "courier new" , "courier" , monospace;">Config Server</span> it publishes
<span style="font-family: "courier new" , "courier" , monospace;">RefreshRemoteApplicationEvent </span>to a message broker. Then the target
application consumes it and performs refreshment. Yep, you guessed - we can create webhooks that call this endpoint whenever anything changes in Git! Now here we have a few options. The first one is a simple form based request:<br />
<br />
<pre class="brush:bash;">curl -X POST localhost:8888/monitor -d 'path=customer-manager'
</pre>
<br />
The remaining options are Git provider specific. In Github for exapmle, the request might be of following form:<br />
<pre class="brush: bash;">curl -X POST localhost:8888/monitor
| -H "X-Github-Event: push"
| -H "Content-Type: application/json"
| -d '{"commits": [{"modified": ["customer-manager.yml"] }]}'
</pre>
<br />
If you are interested in details about how to build Github Push Webhooks, please visit <a href="https://developer.github.com/v3/activity/events/types/#pushevent" target="_blank">this page</a>.<br />
<br />
<br />
<h2>
<span style="font-size: x-large;">Summary</span></h2>
<br />
In this article you could get an overview of how complex configuration issues may be. I gave you an explanation of why keeping configuration in external files is good, and when in might not be enough. You could see an evolving microservice system which we improved step by step by adding advanced configuration management with the use of <span style="font-family: "courier new" , "courier" , monospace;">spring-cloud-config</span> and Git as a backing service. You could also see, that a simple setup with manual refresh ability is fairly easy to provide, but in a much bigger architecture where your services are scaled up to a couple of nodes you simply won't be able to control it. Then, a good solution would be to use a message broker like <span style="font-family: "courier new" , "courier" , monospace;">Apache Kafka</span> and <span style="font-family: "courier new" , "courier" , monospace;">spring-cloud-bus</span> with a proper broker abstraction (<span style="font-family: "courier new" , "courier" , monospace;">spring-cloud-stream</span>) on the client side, and <span style="font-family: "courier new" , "courier" , monospace;">spring-cloud-config-monitor</span> on the server side. If you add a proper Webhook to your Git platform, everything will work automatically as a commit to a proper repository/branch gets pushed.<br />
<br />
<h2>
<span style="font-size: x-large;">Further considerations</span></h2>
<br />
When you read articles like this, you should always keep in mind that software development is about trade-off-s before you apply it in your infrastructure. You need to know that keeping configuration in a central place is helpful when it comes to maintenance, traceability, and all the stuff that we discussed at the very beginning, but it complicates the CI and CD processes as you have second place where you keep things connected with deployed application. Another thing is that you need to plan how to organize your Git repository and decide if you want to have a repository per application, or maybe one common repository with application-dependent folders and branches that will apply to profiles - there are lots of strategies and it is up to you to pick the one that will suit you best. If you need some more information about <span style="font-family: "courier new" , "courier" , monospace;">spring-cloud-config</span> I recommend visiting <a href="https://cloud.spring.io/spring-cloud-config/" target="_blank">this page</a>. Cheers!Bartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.com15tag:blogger.com,1999:blog-3619983083169551150.post-61618822429868525072017-09-25T11:26:00.001+02:002017-09-27T09:50:19.011+02:00Convenience Factory Methods for Collections in Java 9Java 9 doesn't bring as dramatic changes to the way of coding as its predecessor did but surely we will have some fancy features, one of which I would like to present to you in this article. When I started coding in Groovy about 5 years ago, I was amazed by the collections support there. Especially when it came to initialize an immutable list, I could do it in one simple line:<br />
<br />
<pre class="brush:groovy;">def band = ["Bruce", "Steve", "Adrian", "Dave", "Janic", "Nicko"].asImmutable()
</pre>
<br />
This year I also started coding in scala, and here we have some fancy tricks like:
<br />
<pre class="brush:scala;">val band = "Bruce" :: "Steve" :: "Adrian" :: "Dave" :: "Janick" :: "Nicko" :: Nil
</pre>
<br />
or simply
<br />
<br />
<pre class="brush:scala;">val band = List("Bruce", "Steve", "Adrian", "Dave", "Janick", "Nicko")
</pre>
<br />
At the same time Java seemed to be torturing me with an <span style="font-family: "courier new" , "courier" , monospace;">add</span> statement list:
<br />
<br />
<pre class="brush:java;">List<String> band = new ArrayList<>();
band.add("Bruce");
band.add("Steve");
band.add("Adrian");
band.add("Janick");
band.add("Nicko");
band = Collections.unmodifiableList(band);
</pre>
<br />
or so called "double-brace" initialization (which in fact isn't any special Java feature, but rather a workaround benefiting from anonymous classes and initialization blocks):
<br />
<br />
<pre class="brush:java;">List<String> band = Collections.unmodifiableList(new ArrayList<>() {{
add("Bruce");
add("Steve");
add("Adrian");
add("Janick");
add("Nicko");
}});</pre>
<br />
or using arrays API to convert array to an ArrayList<br />
<br />
<pre class="brush:java;">List<String> band = Collections
.unmodifiableList(Arrays.asList("Bruce","Steve","Adrian",
"Dave", "Janick","Nicko"));</pre>
<div>
<br /></div>
Lately I could also benefit from Stream API:
<br />
<br />
<pre class="brush:java;">List<String> band = Collections
.unmodifiableList(Stream.of("Bruce","Steve","Adrian", "Dave", "Janick","Nicko")
.collect(toList()));</pre>
<br />
<br />
Two last options are the cutest ones, but why do I need to first create an array or a stream in order to create a list, and why can't I just use <span style="font-family: "courier new" , "courier" , monospace;">Collections API </span>instead of <span style="font-family: "courier new" , "courier" , monospace;">Arrays API</span> or <span style="font-family: "courier new" , "courier" , monospace;">Stream API</span>? Well, I don't even want to recall the way we can create <span style="font-family: "courier new" , "courier" , monospace;">Set</span>s or <span style="font-family: "courier new" , "courier" , monospace;">Map</span>s in Java - thinking of it makes me wake up in sweat in the middle of the night.<br />
<br />
So far, the most concise and elegant way of creating immutable collections was provided by <span style="font-family: "courier new" , "courier" , monospace;">Guava</span> library and classes like <span style="font-family: "courier new" , "courier" , monospace;">ImmutableList</span>, <span style="font-family: "courier new" , "courier" , monospace;">ImmutableMap</span>, <span style="font-family: "courier new" , "courier" , monospace;">ImmutableSet</span>, etc. Below is an example of what was desired to be available in Java out of the box:<br />
<br />
<pre class="brush:java;">List<String> band = ImmutableList.of("Bruce", "Steve", "Dave",
"Adrian", "Janick", "Nicko");</pre>
<br />
Fortunately, authors of Java 9 implemented <span style="font-family: "courier new" , "courier" , monospace;">JEP 269: Convenience Factory Methods for Collections</span>, which simply provides a set of static factory methods supporting creation of immutable collection instances. Saviours! Read on to get the overview of this feature.
<br />
<br />
<h2>
<span style="font-size: x-large;">
Immutable collections</span></h2>
<br />
Before we dig into the topic you should know what immutable collections really are. So, they are collections that cannot be modified once they are created. What I mean by modified is that their state (references they hold, order in which those references are being kept, and the number of elements) will stay untouched. Please note that if an immutable collection holds mutable objects, their state won't be protected anyhow. Although immutable collections still implement <span style="font-family: "courier new" , "courier" , monospace;">List</span>, <span style="font-family: "courier new" , "courier" , monospace;">Set</span> or <span style="font-family: "courier new" , "courier" , monospace;">Map</span> interfaces, methods modifying their contents throw <span style="font-family: "courier new" , "courier" , monospace;">UnsupportedOperationException</span>. You will find sets of such methods in subsequent sections.
<br />
<br />
<h2>
<span style="font-size: x-large;">
Implementation</span></h2>
<br />
Implementation can be devided into two main parts. Firstly, <span style="font-family: "courier new" , "courier" , monospace;">java.util</span> package was enriched with package-private <span style="font-family: "courier new" , "courier" , monospace;">ImmutableCollections</span> class, that contains classes providing the immutability feature. Secondly, instances of those classes are being created with the help of static factory methods in already existing interfaces, i.e. <span style="font-family: "courier new" , "courier" , monospace;">List</span>, <span style="font-family: "courier new" , "courier" , monospace;">Set</span>, and <span style="font-family: "courier new" , "courier" , monospace;">Map</span>. In following sections you will find description of both sets of functionalities per each collection interface.
<br />
<br />
<h2>
<span style="font-size: large;">
List</span></h2>
<br />
An immutable list has an abstract base class <span style="font-family: "courier new" , "courier" , monospace;">AbstractImmutableList<E></span> and four implementations:<br />
<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">List0<E></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">List1<E></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">List2<E></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">ListN<E></span></li>
</ul>
<br />
Each of these types correspond to the number of elements that is used to their creation. In <span style="font-family: "courier new" , "courier" , monospace;">java.util.List</span> interface we have 12 static factory methods that use the above implementations to create immutable objects:<br />
<br />
<pre class="brush:java;">// creates empty immutable list
static <E> List<E> of()
// creates one-element immutable list
static <E> List<E> of(E e1)
// creates two-element immutable list
static <E> List<E> of(E e1, E e2)
...
// creates ten-element immutable list
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
// creates N-element immutable list
static <E> List<E> of(E... elements)
</pre>
<br />
Methods that throw <span style="font-family: "courier new" , "courier" , monospace;">UnsupportedOperationException</span>:<br />
<br />
<pre class="brush:java;">boolean add(E e);
boolean addAll(Collection<? extends E> c);
boolean addAll(int index, Collection<? extends E> c);
void clear();
boolean remove(Object o);
boolean removeAll(Collection<?> c);
boolean removeIf(Predicate<? super E> filter);
void replaceAll(UnaryOperator<E> operator);
boolean retainAll(Collection<?> c);
void sort(Comparator<? super E> c);
</pre>
<br />
Apart from protecting the content of our list, we also get a validation, that prevents us from initiating a list with a <span style="font-family: "courier new" , "courier" , monospace;">null</span> value. Trying to run the following piece of code, we will end up with <span style="font-family: "courier new" , "courier" , monospace;">NullPointerException</span>:<br />
<br />
<pre class="brush:java;">// throws NullPointerException
List<String> band = List.of("Bruce","Steve","Adrian", "Dave", "Janick", null);
</pre>
<br />
Now here is an example of how to properly create immutable list:<br />
<br />
<pre class="brush:java;">List<String> band = List.of("Bruce","Steve","Adrian", "Dave", "Janick","Nicko");
</pre>
<br />
<h2>
<span style="font-size: large;">
Set</span></h2>
<br />
An immutable set is implemented similarly to what we have seen with the <span style="font-family: "courier new" , "courier" , monospace;">List</span> interface. It has an abstract base class <span style="font-family: "courier new" , "courier" , monospace;">AbstractImmutableSet<E></span> and four implementations:<br />
<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">Set0<E></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">Set1<E></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">Set2<E></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">SetN<E></span></li>
</ul>
<br />
that again correspond to the number of elements that is used to their creation. In <span style="font-family: "courier new" , "courier" , monospace;">java.util.Set</span> interface we have 12 static factory methods:<br />
<br />
<pre class="brush:java;">// creates empty immutable set
static <E> Set<E> of()
// creates one-element immutable set
static <E> Set<E> of(E e1)
// creates two-element immutable set
static <E> Set<E> of(E e1, E e2)
...
// creates ten-element immutable set
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10)
// creates N-element immutable set
static <E> Set<E> of(E... elements)
</pre>
<br />
<br />
Methods that throw <span style="font-family: "courier new" , "courier" , monospace;">UnsupportedOperationException</span>:<br />
<br />
<pre class="brush:java;">boolean add(E e)
boolean addAll(Collection<? extends E> c)
void clear()
boolean remove(Object o)
boolean removeAll(Collection<?> c)
boolean removeIf(Predicate<? super E> filter)
boolean retainAll(Collection<?> c)
</pre>
<br />
<br />
Like with immutable lists, we cannot instantiate a Set with a <span style="font-family: "courier new" , "courier" , monospace;">null</span> value:
<br />
<br />
<pre class="brush:java;">// throws NullPointerException
Set<String> band = Set.of("Bruce","Steve","Adrian", "Dave", "Janick", null);
</pre>
<br />
<br />
You should also know, that sets differ from lists in a way, that they cannot have duplicate values. With newly provided factory methods, we won't be able to initialize an immutable <span style="font-family: "courier new" , "courier" , monospace;">Set</span> passing more than one object of the same value - we will get <span style="font-family: "courier new" , "courier" , monospace;">IllegalArgumentException</span>:
<br />
<br />
<pre class="brush:java;">// throws IllegalArgumentException
Set<String> guitarists = Set.of("Adrian", "Dave", "Janick", "Janick");
</pre>
<br />
Now here is an example of how to properly create immutable set:<br />
<br />
<pre class="brush:java;">Set<String> band = Set.of("Bruce","Steve","Adrian", "Dave", "Janick","Nicko");
</pre>
<br />
<h2>
<span style="font-size: large;">
Map</span></h2>
<br />
Before we describe immutable map technical details we should start with the concept of an entry (<span style="font-family: "courier new" , "courier" , monospace;">java.util.Map.Entry</span> interface) - an aggregate of key - value pair. From <span style="font-family: "courier new" , "courier" , monospace;">Java 9</span> we have yet another <span style="font-family: "courier new" , "courier" , monospace;">Entry</span>'s package private implementation - <span style="font-family: "courier new" , "courier" , monospace;">java.util.KeyValueHolder - </span> an immutable container, that prevents from instantiating an entry with key or value equal to null (throwing <span style="font-family: "courier new" , "courier" , monospace;">NullPointerException</span> if done so).<br />
<br />
In order to create an immutable entry, we can use following static factory method from <span style="font-family: "courier new" , "courier" , monospace;">java.util.Map </span>interface:<br />
<br />
<pre class="brush:java;">static <K, V> Entry<K, V> entry(K k, V v)</pre>
<br />
Immutable map has an abstract base class <span style="font-family: "courier new" , "courier" , monospace;">AbstractImmutableMap<K, V></span> with three implementations:<br />
<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">Map0<K, V></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">Map1<K, V></span></li>
<li><span style="font-family: "courier new" , "courier" , monospace;">MapN<K, V></span></li>
</ul>
<br />
Again we have the following set of factory methods inside <span style="font-family: "courier new" , "courier" , monospace;">java.util.Map</span> interface:<br />
<br />
<pre class="brush:java;">// creates an empty map
static <K, V> Map<K, V> of()
// creates one-element map
static <K, V> Map<K, V> of(K k1, V v1)
// creates two-element map
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2)
...
// creates ten-element map
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4,
K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8,
K k9, V v9, K k10, V v10)
// creates N-element map
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries)
</pre>
<br />
You can see that it differs from <span style="font-family: "courier new" , "courier" , monospace;">List</span> or <span style="font-family: "courier new" , "courier" , monospace;">Set</span> factory methods from previous chapters. Using one of the <span style="font-family: "courier new" , "courier" , monospace;">of</span> methods we can create immutable maps that contain up to 10 elements. If we want to have a bigger one, we need to use <span style="font-family: "courier new" , "courier" , monospace;">ofEntries</span> method, accepting <span style="font-family: "courier new" , "courier" , monospace;">varargs</span> of <span style="font-family: "courier new" , "courier" , monospace;">Entry</span>. It shouldn't be any surprise, as we can use <span style="font-family: "courier new" , "courier" , monospace;">varargs</span> for only one argument in a method, so we have no way of passing keys and values of different types this way.<br />
<br />
Like with lists and sets, we have some methods that throw <span style="font-family: "courier new" , "courier" , monospace;">UnsupportedOperationException</span>:<br />
<br />
<pre class="brush:java;">void clear()
V compute(K key, BiFunction<? super K,? super V,? extends V> rf)
V computeIfAbsent(K key, Function<? super K,? extends V> mf)
V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> rf)
V merge(K key, V value, BiFunction<? super V,? super V,? extends V> rf)
V put(K key, V value)
void putAll(Map<? extends K,? extends V> m)
V putIfAbsent(K key, V value)
V remove(Object key)
boolean remove(Object key, Object value)
V replace(K key, V value)
boolean replace(K key, V oldValue, V newValue)
void replaceAll(BiFunction<? super K,? super V,? extends V> f)
</pre>
<br />
Regardless the way of creating immutable map (<span style="font-family: "courier new" , "courier" , monospace;">of</span> or <span style="font-family: "courier new" , "courier" , monospace;">ofEntries</span> method) we won't be able to instantiate it with key, value or whole entry equal to null. Below are the examples of code that will throw <span style="font-family: "courier new" , "courier" , monospace;">NullPointerException</span>:<br />
<br />
<pre class="brush:java;">// throws NullPointerExcepton because of null key
Map<String, Long> age = Map.of(null, 59L, "Steve", 61L);</pre>
<br />
<pre class="brush:java;">// throws NullPointerExcepton because of null value
Map<String, Long> age = Map.of("Bruce", null, "Steve", 61L);</pre>
<br />
<pre class="brush:java;">// throws NullPointerExcepton because of null entry
Map<String, Long> age = Map.ofEntries(Map.entry("Bruce", 59L), null);</pre>
<br />
Similarily to immutable set, we cannot create a map with duplicate values. Trying to do so will end up with throwing <span style="font-family: "courier new" , "courier" , monospace;">IllegalArgumentException</span>:<br />
<br />
<pre class="brush:java;">Map<String, Long> age = Map.of("Bruce", 59L, "Bruce", 59L);</pre>
<br />
<pre class="brush:java;">Map<String, Long> age = Map.ofEntries(Map.entry("Bruce", 59L),
Map.entry("Bruce", 59L));</pre>
<br />
And here are some examples of how can we properly create immutable maps in <span style="font-family: "courier new" , "courier" , monospace;">Java 9</span>:<br />
<br />
<pre class="brush:java;">Map<String, Long> age = Map.of("Bruce", 59L, "Steve", 61L, "Dave", 60L,
"Adrian", 60L, "Janick", 60L, "Nicko", 65L);</pre>
<br />
<pre class="brush:java;">Map<String, Long> age = Map.ofEntries(Map.entry("Bruce", 59L),
Map.entry("Steve", 61L),
Map.entry("Dave", 60L),
Map.entry("Adrian", 60L),
Map.entry("Janick", 60L),
Map.entry("Nicko", 65L));
</pre>
<br />
<br />
<h2>
<span style="font-size: x-large;">
Conclusions</span></h2>
<br />
Since <span style="font-family: "courier new" , "courier" , monospace;">Java 9</span>, creating immutable collections is very convenient. We have a set of static factory methods for each interface, that, apart from creating immutable objects, prevent from inserting nulls or duplicates (in <span style="font-family: "courier new" , "courier" , monospace;">Set</span> and <span style="font-family: "courier new" , "courier" , monospace;">Map</span>). We are warned about any problems at creation time, and we are secured from getting <span style="font-family: "courier new" , "courier" , monospace;">NullPointerExceptions</span> while traversing collection elements. It is a tiny feature, but surely a useful one!<br />
<br />
<br />Bartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.com3tag:blogger.com,1999:blog-3619983083169551150.post-45135151260752353872017-09-18T09:06:00.000+02:002017-10-28T17:54:08.190+02:00Following OOP principles - hermetizationHave you ever looked at the code that you had written couple of months ago and asked yourself: “<i>who could leave such a mess here?</i>” Have you ever been so lazy that you didn’t think of what accessors/mutators you need, simply hitting “<i>Generate getters and setters</i>” for your entity in IDE? Or maybe you have used lombok’s <span style="font-family: "courier new" , "courier" , monospace;">@Getter/@Setter</span> annotations to get the same effect? Yep, just as I thought! Well, honestly, I did this way too many times, too. The problem is that it is not the only crime that we can commit in order to break some of the basic <span style="font-family: inherit;">OOP</span> principles. In this article we will focus on <span style="font-family: inherit;">hermetization</span> (information hiding) but other paradigms, like <span style="font-family: inherit;">abstraction</span> or <span style="font-family: inherit;">encapsulation</span> will be mentioned too, as they all are complementary to each other. In the following paragraphs I will give you an explanation of what is <span style="font-family: inherit;">hermetization</span> and how to provide one within Java. We will discuss common pitfalls and some good practices. You will also find here some philosophical considerations and my own judgements and opinions. I am very open for further discussions. I will walk you through an example of a very poorly written classes, which we will improve step by step, looking at hermetization from numerous perspectives. Enjoy!<br />
<br />
<h2>
<span style="font-size: x-large;">
Hermetization</span></h2>
<br />
<span style="font-family: inherit;">Hermetization</span> is about hiding information (implementation details) that shouldn’t be visible to clients of a class or a module. As long as we follow the encapsulation paradigm, we enclose information (state) and interface (behavior) in a class. Now an interface (API) is a declaration of how we can interact with a particular object. Should we care about how this interaction is implemented? Should we care about the data representation inside? Should we publish methods modifying internal state, that is supposed to be done automatically? Nope, not at all. We just want to send it a command, get the result, and forget. At the same time we want our internals to stay safe and untouched (intentionally or unintentionally) from the outside.<br />
<br />
The less information we expose to the outer world, the less coupled modules we get. Thus, we gain a better separation of classes, which it turn means that we can easily: <br />
<ul>
<li>manipulate the logic/internals inside a class not worrying that we will break our clients,</li>
<li>analyse, use, and test such classes, as we have a clear interface</li>
<li>reuse them, as independent classes might appear to be useful in some other contexts</li>
<li>keep object's state safe.</li>
</ul>
<br />
<h2>
<span style="font-size: x-large;">
Example overview</span></h2>
<br />
<div>
In this article we will focus on a simple business case. We need to provide following things:<br />
<br />
<ul>
<li>the ability to create both contact person and a customer,</li>
<li>each contact person can have an email address - we want to both present and modify this data,</li>
<li>a particular contact person might be assigned to more than one customer</li>
<li>each customer can have a name, and a list of contact people</li>
<li>we want to store a timestamp of the moment of customers' creation and activation</li>
<li>we also want to be able to easily activate a customer and verify if a customer is activated or not</li>
<li>we want to present customer's name, contact people, creation date and a flag of activation</li>
<li>name and contact person list can be modified in future, but creation date must be set only once during creation phase.</li>
</ul>
<br />
Here is a piece of extremely poorly written code:<br />
<br />
<pre class="brush:java;">public class ContactPerson {
public long id;
public String email;
}</pre>
<pre class="brush:java;">public class Customer {
public long id;
public String name;
public Date creationDate;
public Date activationDate;
public ArrayList<ContactPerson> contactPeople = new ArrayList<>();
}</pre>
<pre class="brush:java;">public class CustomerService {
public Customer createCustomer(String name,
ArrayList<ContactPerson> contactPeople) {
if(contactPeople == null) {
throw new IllegalArgumentException("Contact people list cannot be null");
}
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Name cannot be empty");
}
final Customer customer = new Customer();
customer.id = Sequence.nextValue();
customer.creationDate = new Date();
customer.name = name;
customer.contactPeople = contactPeople;
return customer;
}
public ContactPerson createContactPerson(String email) {
final ContactPerson contactPerson = new ContactPerson();
contactPerson.id = Sequence.nextValue();
contactPerson.email = email;
return contactPerson;
}
void activateCustomer(Customer customer) {
customer.activationDate = new Date();
}
boolean isCustomerActive(Customer customer) {
return customer.activationDate != null;
}
void addContactPerson(Customer customer, ContactPerson contactPerson) {
customer.contactPeople.add(contactPerson);
}
void removeContactPerson(Customer customer, ContactPerson contactPerson) {
customer.contactPeople.removeIf(it -> it.id == contactPerson.id);
}
}
</pre>
<br />
You can see that we have two model classes and a service fulfilling mentioned business requirements. Let's try to work on this example to make it a shiny one. You can find the final version of this example <a href="https://github.com/bslota/hermetization">here</a>.</div>
<br />
<i>Please note that we skip here all aspects of concurrency.</i><br />
<i><br /></i>
<br />
<h2>
<span style="font-size: x-large;">
Access control, accessors, mutators</span></h2>
<br />
The first facility for information hiding that Java gives us is access control mechanism. We have a few options to choose:<br />
<ul>
<li>Private</li>
<li>Package-private</li>
<li>Protected</li>
<li>Public</li>
</ul>
By default, we are granted a package-private scope which gives us a bit of hermetization out of the box. The language itself suggests that we should keep our modules (packages) independent, reusable - it should be our conscious decision to make a class, a method or a field a public one.<br />
<br />
The code from above does what it is supposed to do, but with this approach you face following problems:<br />
<ul>
<li>you cannot change the data representation without modifying client's code - the information about how you store data becomes a part of your API,</li>
<li>you cannot perform any extra actions (like validation) when field is being accessed/modified.</li>
</ul>
It means we have no hermetization at all. The easiest way of dealing with it is to restrict all instance members' visibility to private scope and define their accessors (getters) and mutators (setters) like below:<br />
<br />
<pre class="brush:java;">public class ContactPerson {
private long id;
private String email;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "ContactPerson{" +
"id=" + id +
", email='" + email + '\'' +
'}';
}
}</pre>
<br />
<pre class="brush:java;">public class Customer {
private long id;
private String name;
private Date creationDate;
private Date activationDate;
private ArrayList<ContactPerson> contactPeople = new ArrayList<>();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public Date getActivationDate() {
return activationDate;
}
public void setActivationDate(Date activationDate) {
this.activationDate = activationDate;
}
public ArrayList<ContactPerson> getContactPeople() {
return contactPeople;
}
public void setContactPeople(ArrayList<ContactPerson> contactPeople) {
this.contactPeople = contactPeople;
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", creationDate=" + creationDate +
", activationDate=" + activationDate +
", contactPeople=" + contactPeople +
'}';
}
}</pre>
And now our client's code need to be refactored, too:
<br />
<pre class="brush:java;">public class CustomerService {
public Customer createCustomer(String name,
ArrayList<ContactPerson> contactPeople) {
if(contactPeople == null) {
throw new IllegalArgumentException("Contact people list cannot be null");
}
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Name cannot be empty");
}
final Customer customer = new Customer();
customer.setId(Sequence.nextValue());
customer.setCreationDate(new Date());
customer.setName(name);
customer.setContactPeople(contactPeople);
return customer;
}
public ContactPerson createContactPerson(String email) {
final ContactPerson contactPerson = new ContactPerson();
contactPerson.setId(Sequence.nextValue());
contactPerson.setEmail(email);
return contactPerson;
}
public void activateCustomer(Customer customer) {
customer.setActivationDate(new Date());
}
public boolean isCustomerActive(Customer customer) {
return customer.getActivationDate() != null;
}
public void addContactPerson(Customer customer, ContactPerson contactPerson) {
customer.getContactPeople().add(contactPerson);
}
public void removeContactPerson(Customer customer, long contactPersonId) {
customer.getContactPeople().removeIf(it -> it.getId() == contactPersonId);
}
}
</pre>
<br />
You may think now that we are done - our fields are private, accessors and mutators cover implementation details, right? Well, it is a common mistake that we treat objects as data containers. We start with defining a set of fields, and afterwards we declare corresponding getters and setters to each and every field in a class. Then we put the whole logic into some service class making our entity a dumb data structure. As long as a class can manage the values of its fields (e.g. there is no need to call a repository or some external system) it should be done inside this class. In other words, every class should encapsulate both instance fields and business methods, which are nothing more than an abstraction of a real-life domain object, hermetizing implementation details as much as possible. You see - OOP is about composing all paradigms together. Now let's try to answer a few questions, bearing in mind previously defined example's business requirements:
<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">ContactPerson</span>:
<br />
<ol>
<li>Do I really need getters to all fields? Well, I suppose yes - we might want to present customers' contact people information. Okay then, let's leave the getters.</li>
<li>Is <span style="font-family: "courier new" , "courier" , monospace;">ID</span> something that I should set? Do I even need what value should I give it? No. It is something that shouldn't bother us. It should be generated automatically, e.g. by <span style="font-family: "courier new" , "courier" , monospace;">Hibernate</span>. It means that having a <span style="font-family: "courier new" , "courier" , monospace;">setId</span> method we break hermetization! Let's remove this mutator and put its logic to a constructor. For the simplicity of an example - we put a static sequence generator there.</li>
</ol>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">Customer</span>:</div>
<div>
<ol>
<li>Do I really need getters to all fields? Nope. Like we said in the example description, we just want to get information whether a customer is active or not. Exposing <span style="font-family: "courier new" , "courier" , monospace;">getActivationDate</span> method forces our clients to put some logic around <span style="font-family: "courier new" , "courier" , monospace;">activationDate</span> value. It smells badly to me. A customer is able to decide about its activation status using its own fields' values (one field actually). It suggests that we hermetize activation details inside an entity. We simply move <span style="font-family: "courier new" , "courier" , monospace;">isCustomerActive</span> method logic into <span style="font-family: "courier new" , "courier" , monospace;">isActive</span> method inside <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> class, like it is depicted below.</li>
<li>Is <span style="font-family: "courier new" , "courier" , monospace;">ID</span> something I should set? You should know the answer now - it is the same situation like with <span style="font-family: "courier new" , "courier" , monospace;">ContactPerson</span>.</li>
<li>Should I set <span style="font-family: "courier new" , "courier" , monospace;">creationDate</span> in client's code? Well, as the name implies it is a timestamp of object creation and shouldn't be modifiable at any other time. Thus, giving a setter we create a threat that someone will update this value in the future or set something really strange. It is up to entity to decide what time it should set. Let's move it to the constructor, then, and forget about this mutator.</li>
<li>Do I need to set <span style="font-family: "courier new" , "courier" , monospace;">activationDate</span> in client's code? Well, who told you (the client) that we store activation date? Ha! We don't care about data representation again, we just want to be able to activate a customer. What we should do is to remove <span style="font-family: "courier new" , "courier" , monospace;">setActivationDate</span> from the service and create <span style="font-family: "courier new" , "courier" , monospace;">activateCustomer</span> method inside an entity instead.</li>
<li>Do I really need methods that add or remove contact people from my customer in a service class? Well again, collection belongs to a <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> entity, and letting some third parties modify that collection is a crime. Let's move these methods to the entity, too.</li>
<li>Should I keep validations in service? In this case we can validate params without calling external services or resources, so the answer is <b>no</b>. Every condition that must be fulfilled while creating or setting a field should be hermetized inside the entity (in constructors and/or mutators), so that clients don't need to worry about performing such checks. Thus, we will have consistent conditions across all clients. Passing wrong parameters will simply cause an exception. </li>
</ol>
<div>
Uhh, finally... that was tough. Let's see how our code looks now:</div>
<br />
<pre class="brush:java;">public class ContactPerson {
private long id;
private String email;
public ContactPerson() {
this.id = Sequence.nextValue();
}
public long getId() {
return id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "ContactPerson{" +
"id=" + id +
", email='" + email + '\'' +
'}';
}
}
</pre>
<pre class="brush:java;">public class Customer {
private long id;
private String name;
private Date creationDate;
private Date activationDate;
private ArrayList<ContactPerson> contactPeople = new ArrayList<>();
public Customer() {
this.id = Sequence.nextValue();
this.creationDate = new Date();
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Name cannot be empty");
} else {
this.name = name;
}
}
public Date getCreationDate() {
return creationDate;
}
public ArrayList<ContactPerson> getContactPeople() {
return contactPeople;
}
public void setContactPeople(ArrayList<ContactPerson> contactPeople) {
if (contactPeople == null) {
throw new IllegalArgumentException("Contact people list cannot be null");
} else {
this.contactPeople = contactPeople;
}
}
public void activate() {
this.activationDate = new Date();
}
public boolean isActive() {
return this.activationDate != null;
}
public void addContactPerson(ContactPerson contactPerson) {
this.contactPeople.add(contactPerson);
}
public void removeContactPerson(long contactPersonId) {
this.contactPeople.removeIf(it -> it.getId() == contactPersonId);
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", creationDate=" + creationDate +
", activationDate=" + activationDate +
", contactPeople=" + contactPeople +
'}';
}
}</pre>
<pre class="brush:java;">public class CustomerService {
public Customer createCustomer(String name, ArrayList<ContactPerson> contactPeople) {
final Customer customer = new Customer();
customer.setName(name);
customer.setContactPeople(contactPeople);
return customer;
}
public ContactPerson createContactPerson(String email) {
final ContactPerson contactPerson = new ContactPerson();
contactPerson.setEmail(email);
return contactPerson;
}
}
</pre>
</div>
<br />
<br />
What we can see now, is that our entities are not just simple data stores. They have a real behavior. Implementation details are hidden behind constructors, and business methods. Those business methods are nothing more than an abstraction of a real-world behavior of customer and its contact people. You can see now that abstraction, encapsulation and hermetization are complementary to each other. As a result of our refactoring, the <span style="font-family: "courier new" , "courier" , monospace;">CustomerService</span> does nothing more than just creating objects, so we could even remove this class, and implement proper constructors or factory methods. Nice, huh?<br />
<br />
<h2>
<span style="font-size: x-large;">
Interface vs implementation</span></h2>
<br />
Let's have a look at the list of contact people. It is working, right? But don't we tell our client too much with <span style="font-family: "courier new" , "courier" , monospace;">getContactPeople</span> and <span style="font-family: "courier new" , "courier" , monospace;">setContactPeople</span> methods' signatures? I think we are, as we are using a concrete implementation of a <span style="font-family: "courier new" , "courier" , monospace;">java.util.</span><span style="font-family: "courier new" , "courier" , monospace;">List</span> interface to declare a type of contact people collection. We are sharing yet another implementation detail here. In such situations what we should do is to use an interface (if such interface exists of course) instead - <span style="font-family: "courier new" , "courier" , monospace;">java.util.List</span> in this case. The only place where we can refer to a specific class is object's construction. This way we both hide data representation and create a possibility to change the implementation from an <span style="font-family: "courier new" , "courier" , monospace;">ArrayList</span> to a <span style="font-family: "courier new" , "courier" , monospace;">LinkedList</span> if needed, without modifying our clients. Isn't it cool?<br />
<br />
Don't think that you must always follow this approach. It is completely correct to refer to objects via class when one of the following situations apply to your case. Firstly, when you hava a class that does not implement any interface - then you simply have no choice, and must use class as a type.Secondly, when a class belongs to some class hierarchy, then it is recommended to refer to an object via the base class (usually an abstract one). And finally, your class might implement an interface, but contain some additional methods, not existing in mentioned interface. If and only if your client's code need to call this extra methods - then you need to refer to object via this class instead of using its interface.
<br />
<br />
It is all about providing both hermetization and flexibility. Let's have a look at <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> class now:
<br />
<pre class="brush:java;">public class Customer {
private long id;
private String name;
private Date creationDate;
private Date activationDate;
private List<ContactPerson> contactPeople = new ArrayList<>();
public Customer() {
this.id = Sequence.nextValue();
this.creationDate = new Date();
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Name cannot be empty");
} else {
this.name = name;
}
}
public Date getCreationDate() {
return creationDate;
}
public List<ContactPerson> getContactPeople() {
return contactPeople;
}
public void setContactPeople(List<ContactPerson> contactPeople) {
if (contactPeople == null) {
throw new IllegalArgumentException("Contact people list cannot be null");
} else {
this.contactPeople = contactPeople;
}
}
public void activate() {
this.activationDate = new Date();
}
public boolean isActive() {
return this.activationDate != null;
}
public void addContactPerson(ContactPerson contactPerson) {
this.contactPeople.add(contactPerson);
}
public void removeContactPerson(long contactPersonId) {
this.contactPeople.removeIf(it -> it.getId() == contactPersonId);
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", creationDate=" + creationDate +
", activationDate=" + activationDate +
", contactPeople=" + contactPeople +
'}';
}
} </pre>
<br />
<h2>
<span style="font-size: x-large;">
toString()</span></h2>
<br />
It might look trivial to override default <span style="font-family: "courier new" , "courier" , monospace;">toString()</span> method, but my experience shows that the way you print your object details is very vital. First of all, there might be some crazy guy that will write an application reading your logs, parsing them and calculating something - yep, I saw that on production. Secondly, lots of people have access to our log files and may read some sensitive information. It means that <span style="font-family: "courier new" , "courier" , monospace;">toString()</span> method should be implemented with the same attention like an API. It should expose only those information, that are accessible programmatically. It is a common mistake that we just hit <i>"Generate toString()"</i> in our IDE, because it usually creates a method printing all your private fields and breaking hermetization by publishing all information about data representation. We have one violation of this rule in <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> class, then. Below you can see how our <span style="font-family: "courier new" , "courier" , monospace;">toString()</span> method should look like:<br />
<br />
<pre class="brush:java;">public class Customer {
...
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", creationDate=" + creationDate +
", active=" + isActive() + //activation date no longer here!
", contactPeople=" + contactPeople +
'}';
}
} </pre>
<br />
<br />
<h2>
<span style="font-size: x-large;">
equals() and hashCode()</span></h2>
<br />
Another couple of methods common for all objects are <span style="font-family: "courier new" , "courier" , monospace;">equals()</span> and <span style="font-family: "courier new" , "courier" , monospace;">hashCode()</span>. They are also strongly connected with OOP principles, as they are part of your API. Each time when objects of your class are considered to be compared or play the role of a key in some data structure, and their equality is based on some logical assumptions, then you should override Object's default <span style="font-family: "courier new" , "courier" , monospace;">equals()</span> method. It is said that if you can do something inside your class or a library - do it there - don't force your clients to implement it on their own, because you will spread the logic outside of the class and break the hermetization. This problem is similar to what we described in <span style="font-family: "courier new" , "courier" , monospace;">Access control, accessors, mutators</span> chapter, while moving <span style="font-family: "courier new" , "courier" , monospace;">activateCustomer()</span> and <span style="font-family: "courier new" , "courier" , monospace;">isCustomerActive()</span> methods from service to <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> class. Of course you should also remember that overriding <span style="font-family: "courier new" , "courier" , monospace;">equals()</span> implies necessity of implementing <span style="font-family: "courier new" , "courier" , monospace;">hashCode()</span>, too. As soon as you have both methods, your clients doesn't have to worry about deciding how they should compare objects, or wondering if they can use them in a hash map - you hide (hermetize) it inside your class. Below you will find out how <span style="font-family: "courier new" , "courier" , monospace;">equals()</span> and <span style="font-family: "courier new" , "courier" , monospace;">hashCode()</span> could look like in our example (let's assume that all instance fields define object's identity).<br />
<br />
<i>Please note that the description of rules which should be followed while implementing <span style="font-family: "courier new" , "courier" , monospace;">equals()</span> and <span style="font-family: "courier new" , "courier" , monospace;">hashCode()</span> are out of the scope of this article</i>.
<br />
<pre class="brush:java;">public class ContactPerson {
...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final ContactPerson that = (ContactPerson) o;
if (id != that.id) return false;
return email != null ? email.equals(that.email) : that.email == null;
}
@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (email != null ? email.hashCode() : 0);
return result;
}
}</pre>
<br />
<pre class="brush:java;">public class Customer {
...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Customer customer = (Customer) o;
if (id != customer.id) return false;
if (name != null ? !name.equals(customer.name) : customer.name != null) return false;
if (creationDate != null ? !creationDate.equals(customer.creationDate) : customer.creationDate != null) return false;
if (activationDate != null ? !activationDate.equals(customer.activationDate) : customer.activationDate != null) return false;
return contactPeople != null ? contactPeople.equals(customer.contactPeople) : customer.contactPeople == null;
}
@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (creationDate != null ? creationDate.hashCode() : 0);
result = 31 * result + (activationDate != null ? activationDate.hashCode() : 0);
result = 31 * result + (contactPeople != null ? contactPeople.hashCode() : 0);
return result;
}
}
</pre>
<br />
<h2>
<span style="font-size: x-large;">
Object references</span></h2>
<br />
When we operate on objects, we pass their references back and forth, especially when we pass an object as a method parameter or return it as a method's call result. Having a reference to a mutable object we can easily update its state. It means that if it is a reference to an instance field of some other object - we may break its hermetization. Let's have a look at our example. Imagine a situation, when our client calls <span style="font-family: "courier new" , "courier" , monospace;">getCreationDate()</span> method like below:<br />
<pre class="brush:java;">Date creationDate = customer.getCreationDate();
creationDate.setTime(1504259400000L);
</pre>
<br />
Did we just find a way of changing the state of our <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> object not even calling any of its mutators? Exactly. One of the possibilities to defend ourselves from this kind of threats is using immutable objects (check-out next chapter). Here we will focus on another option, then, that is <span style="font-family: "courier new" , "courier" , monospace;">defensive copying</span>. <span style="font-family: "courier new" , "courier" , monospace;">Defensive copying</span> is about returning copies (references to copies - to be precise) of our mutable instance fields and working on copies of objects passed as constructor or mutator parameters.
<br />
<br />
Well, in order to secure our <span style="font-family: "courier new" , "courier" , monospace;">creationDate</span> field we will produce a copy. Here are two possible solutions:
<br />
<br />
<ol>
<li>Cloning - it is a para-Java mechanism of creating objects without using constructors. There are lots of dangerous things around it, that won't be covered in detail here. It is considered as not-safe and we should avoid it but I also think that we should be aware of what can be possibly done via this technique. In a big short, it is about calling object's protected <span style="font-family: "courier new" , "courier" , monospace;">clone()</span> method. In most cases, classes that enable cloning provide a public equivalent of <span style="font-family: "courier new" , "courier" , monospace;">clone()</span>. What you need to know is that you should use it for defensive copying only if the class is declared <span style="font-family: "courier new" , "courier" , monospace;">final</span> (nobody can extend it). Why is that? It is because there is a real threat that a subclass overrides <span style="font-family: "courier new" , "courier" , monospace;">clone()</span> method which does both cloning and registering reference to original object somewhere, and we will lose hermetization (more about inheritance in furhter chapter) You must be also aware that <span style="font-family: "courier new" , "courier" , monospace;">clone()</span> does just a shallow copy based on an assignment, which means that all instance fields will be initialized with <span style="font-family: "courier new" , "courier" , monospace;">=</span> operator. Thus, if the object you are copying has an instance field which is a reference to some other object, this reference will be copied one to one (instance field of the object's clone will point to the same place in memory - any change within this object may corrupt all clones, unless you implement a deep cloning!). Now, please take a look at a sample cloning (don't use it with <span style="font-family: "courier new" , "courier" , monospace;">Date</span> in a real life, as <span style="font-family: "courier new" , "courier" , monospace;">Date</span> is not a <span style="font-family: "courier new" , "courier" , monospace;">final</span> class):
<br />
<pre class="brush:java;">public Date getCreationDate() {
return (Date) creationDate.clone();
}
</pre>
<br />
</li>
<li>Copying via constructor or factory method (which may be called a copy constructor) - this is a quick and safe method, free from threats carried by <span style="font-family: "courier new" , "courier" , monospace;">clone()</span>, where you can fully control creation process yourself.
<br />
<pre class="brush:java;">public Date getCreationDate() {
return new Date(creationDate.getTime());
}
</pre>
</li>
</ol>
<br />
The same problem refers to the <span style="font-family: "courier new" , "courier" , monospace;">contactPeople</span> collection. Whatever mutable collection you expose to the outter world, anyone can modify it freely without any notice. It means that we should neither return reference to the collection nor save such reference to our instance field within a setter. There are plenty of methods to perform the shallow copy of a collection (shallow in this case means that we will create a completely different collection object, but containing the same references to content elements!). Defensive copying for accessor method is rather straightforward. We could simply use <span style="font-family: "courier new" , "courier" , monospace;">Collections API</span> like below:
<br />
<pre class="brush:java;">public List<ContactPerson> getContactPeople() {
return Collections.unmodifiableList(contactPeople);
}
</pre>
<br />
Regarding mutator, we could either remove it and force our clients to use add/remove methods (<span style="font-family: "courier new" , "courier" , monospace;">addContactPerson</span>/<span style="font-family: "courier new" , "courier" , monospace;">removeContactPerson</span>) or make a shallow copy manually:
<br />
<pre class="brush:java;">public void setContactPeople(List<ContactPerson> contactPeople) {
if (contactPeople == null) {
throw new IllegalArgumentException("Contact people list cannot be null");
} else {
this.contactPeople = new ArrayList<>(contactPeople);
}
}
</pre>
<br />
You should see now that the problem we face here is that (despite defensive copying of collection) we keep references to all elements and enable our clients to modify them. We could discuss now whether shallow copy gives a real hermetization or not, and... it depends. If we have references to immutable objects (please refer to further chapter) - we don't need to worry about hermetiaztion violations during copying. Well, immutables don't even need to be copied at all! If an object is mutable, though, then changing its state means changing indirectly the state of all objects containing its reference. Sometimes when we need to store a reference to a mutable object, we simply cannot copy all its fields. We have a perfect example of that in our code - is there a way of copying <span style="font-family: "courier new" , "courier" , monospace;">id</span> field without using reflection? There is none, as we have <span style="font-family: "courier new" , "courier" , monospace;">id</span> field generated automatically inside the constructor and there is no setter available. Now it is the moment where you should ask: okay, so why don't we restore <span style="font-family: "courier new" , "courier" , monospace;">setId</span> methods? Personally, I consider it as a bad idea, because cloning is a very low level procedure, and it shouldn't influence our abstraction and hermetization. Thus, to workaround this problem we could e.g. create a private constructor that accepts all fields as parameters and provide our own <span style="font-family: "courier new" , "courier" , monospace;">copy()</span> method that would call it and return a proper copy (you see, no reflection needed, no hermetization violations). Take a look:
<br />
<pre class="brush:java;">public class ContactPerson {
private long id;
private String email;
private ContactPerson(long id, String email) {
this.id = id;
this.email = email;
}
...</pre>
<pre class="brush:java;"> public ContactPerson copy() {
return new ContactPerson(this.id, this.email);
}
}
</pre>
<br />
As soon as we have the ability to make a copy of the elements from our collection we can easily make deep copies inside getter and setter:
<br />
<pre class="brush:java;">public List<ContactPerson> getContactPeople() {
return this.contactPeople.stream().map(ContactPerson::copy).collect(toList());
}
public void setContactPeople(List<ContactPerson> contactPeople) {
if (contactPeople == null) {
throw new IllegalArgumentException("Contact people list cannot be null");
} else {
this.contactPeople = contactPeople.stream()
.map(ContactPerson::copy).collect(toList());
}
}
</pre>
<br />
If we have a collection of objects of type that we have no authority to modify (e.g. as it comes from some external library), we should just perform a shallow copy and advise other programmers with a proper comment not to mutate the state of these objects.<br />
<br />
<h2>
<span style="font-size: x-large;">
Inheritance</span></h2>
<br />
Inheritance breaks hermetization! Every subclass is based on the logic encapsulated in its superclass, right? In order to work properly, a subclass needs to call its parent's super methods, which means it depends on implementation details of the predecessor. Now a superclass may change, and those changes influence all its subclasses. As a consequence, every alteration might require changes in children classes. Let me show you an example. Let's imagine, that we want to store a number of contact people in an instance variable inside a subclass of a <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> (yes, I know it is just a <span style="font-family: "courier new" , "courier" , monospace;">size()</span> of our collection, but I want to visualise the problem) - let's call it a <span style="font-family: "courier new" , "courier" , monospace;">SpecialCustomer</span>.
<br />
<pre class="brush:java;">public class SpecialCustomer extends Customer {
private int numberOfContactPeople = 0;
@Override
public void setContactPeople(List<ContactPerson> contactPeople) {
numberOfContactPeople = contactPeople.size();
super.setContactPeople(contactPeople);
}
@Override
public void addContactPerson(ContactPerson contactPerson) {
super.addContactPerson(contactPerson);
numberOfContactPeople++;
}
public int getNumberOfContactPeople() {
return numberOfContactPeople;
}
}
</pre>
<br />
And here we have a simple test, where we create <span style="font-family: "courier new" , "courier" , monospace;">SpecialCustomer</span> setting one-element <span style="font-family: "courier new" , "courier" , monospace;">ContactPerson</span> list:
<br />
<pre class="brush:java;">@Test
public void specialCustomerShouldHaveContactPeopleCounterEqualToOne() {
//given
final ContactPerson contactPerson =
new ContactPerson("Steve", "Harris", "steve@gmail.com");
final List<ContactPerson> contactPeople = new ArrayList<>();
contactPeople.add(contactPerson);
//when
final SpecialCustomer specialCustomer = new SpecialCustomer();
specialCustomer.setContactPeople(contactPeople);
//then
assertEquals(1, specialCustomer.getNumberOfContactPeople());
}
</pre>
<br />
And what we get after running this test is:
<br />
<pre class="brush:plain;">java.lang.AssertionError:
Expected :1
Actual :2
</pre>
<br />
The reason is that we didn't know, that <span style="font-family: "courier new" , "courier" , monospace;">setContactPeople</span> method from <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> class calls <span style="font-family: "courier new" , "courier" , monospace;">addContactPerson</span> inside, so our counter gets incremented twice. Hermetization of our subclass is broken by the dependency to its parent, and it is a clear example of a strong and dangerous coupling that inheritance bears. Ok, so how to deal with it?<br />
<br />
Well, we could of course override every public method and put a desired logic in subclass without calling <span style="font-family: "courier new" , "courier" , monospace;">super</span> methods, but this clearly isn't something that inheritance is for, and of course, we might not be aware e.g. about validations that are implemented in our super class. Another idea might be to use inheritance only when we want to add new methods, not overriding existing ones. Great, but if a method of the same signature is added to the base class, then the problem is back. What if a parent class has some errors? Then we populate all this errors to its children. Okay, I won't keep you in suspense anymore - you should prefer composition over inheritance. We won't discuss this pattern further, but as you know the threats connected with inheritance I would rather like to point out, that if we see a possibility of breaking hermetization, and we don't think our class should be extendable, we should declare it <span style="font-family: "courier new" , "courier" , monospace;">final</span> (and we will do so with our example). If it is not the case, then we should declare as many methods <span style="font-family: "courier new" , "courier" , monospace;">final</span> as possible and document exactly how each method should be overriden properly and hope that other programmers will stick to that rules.<br />
<br />
<h2>
<span style="font-size: x-large;">
Immutables</span></h2>
<br />
We had said it many times before that when we have immutable objects, we don't have to worry about hermetization issues. Sounds great, huh? What are those immutables, then? As the name implies, these are objects that cannot be modified once they are created. It means that they have one, consistent state throughout their lifecycle, and thus they may be safely shared among numerous threads. In terms of hermetization it is an essence of hiding and securing internals. Here are the features that immutable class must provide:
<br />
<br />
<ul>
<li>All instance fields are private</li>
<li>No mutators (setters) - there shouldn't be any possibility of changing the state of existing object</li>
<li>Any method that is supposed to change a state creates the object's copy with a properly updated fields</li>
<li>No method can be overriden - it is about dealing with threats carried with inheritance</li>
<li>All instance fields should be declared <span style="font-family: "courier new" , "courier" , monospace;">final</span>, and thus, should be initialized inside constructor</li>
<li>Access to all mutable instance fields must be secured with defensive copying mechanism</li>
</ul>
<div>
As you can see, all those features reflect our previous discussion. Unless there is a strong reason of creating modifiable classes, we should do our best to provide immutable ones. What a wonderful world would it be if we could have our projects built upon immutables only... Basically, yes, it would be, but as everything in this world it has its drawbacks, too, and we should be aware of them. Now if an object is immutable, operations that require returning a new instance might be costly in terms of memory. Imagine copying arrays of thousand of elements each time we call <span style="font-family: "courier new" , "courier" , monospace;">addToYourArray</span> method! Another side-effect is that the "old" instance will be alive as long as something holds its reference (or GC cleans it). Sometimes making immutables is even impossible. You may e.g. use <span style="font-family: "courier new" , "courier" , monospace;">JPA</span> that requires no-arg constructor and you simply cannot declare your fields final and instantiate them at creation time. If we cannot make our classes immutable we should declare as many fields <span style="font-family: "courier new" , "courier" , monospace;">final</span> as possible to keep the hermetization and security at the highest possible level.</div>
<div>
<br />
When talking about immutables, it is also worth mentioning that immutable objects are desired to be used with so called <span style="font-family: "courier new" , "courier" , monospace;">Value Objects</span>. Not digging deep into the topic, these are the objects that don't have any conceptual identity, and we specify them only by the state of their properties (fields). Keeping <span style="font-family: "courier new" , "courier" , monospace;">value objects</span> immutable ones combines very good abstraction and encapsulation (by converting a logical value into an object) with hermetization, therefore securing their state (value) from any manipulations from the outside.<br />
<br /></div>
<div>
There are lots of good examples of immutables in core Java libraries: <span style="font-family: "courier new" , "courier" , monospace;">java.lang.String</span>, <span style="font-family: "courier new" , "courier" , monospace;">java.math.BigInteger</span>, <span style="font-family: "courier new" , "courier" , monospace;">java.time.ZonedDateTime</span>. You should now know why didn't we do any defensive copy for <span style="font-family: "courier new" , "courier" , monospace;">String</span> fields. Remember, if you only have an option - use immutables! Yes, we will do so too, we will throw <span style="font-family: "courier new" , "courier" , monospace;">Date</span> away in favour of <span style="font-family: "courier new" , "courier" , monospace;">ZonedDateTime</span>.<br />
<br /></div>
How do you think, can we make our classes pure immutable ones? Let's try it with a <span style="font-family: "courier new" , "courier" , monospace;">ContactPerson</span>:<br />
<pre class="brush:java;">public final class ContactPerson {
private final long id;
private final String email;
private ContactPerson(long id, String email) {
this.id = id;
this.email = email;
}
public long getId() {
return id;
}
public String getEmail() {
return email;
}
@Override
public String toString() {
return "ContactPerson{" +
"email='" + email + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final ContactPerson that = (ContactPerson) o;
if (id != that.id) return false;
return email != null ? email.equals(that.email) : that.email == null;
}
@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (email != null ? email.hashCode() : 0);
return result;
}
public ContactPerson copy() {
return new ContactPerson(this.id, his.email);
}
public static ContactPerson valueOf(String email) {
return new ContactPerson(Sequence.nextValue(), email);
}
}
</pre>
<br />
<ul>
<li>All instance fields private - <i>checked</i></li>
<li>No mutators (setters) - <i>checked</i></li>
<li>Any method that is supposed to change a state must create a copy with a properly updated fields - <i>no such methods</i></li>
<li>No method can be overriden - <i>checked</i></li>
<li>All instance fields final - <i>checked</i></li>
<li>Mutable instance fields must be secured with defensive copying - <i>checked</i></li>
</ul>
<div>
Success! We made <span style="font-family: "courier new" , "courier" , monospace;">ContactPerson</span> an immutable class. You can see here that we added a static <span style="font-family: "courier new" , "courier" , monospace;">valueOf</span> factory method instead of a public constructor, which gives a convenient way of creating objects (no more <span style="font-family: "courier new" , "courier" , monospace;">new</span> operator) and gives another level of hermetization - client does not need to know what constructors are used inside.</div>
<div>
<br /></div>
<div>
Now can we do the same to a <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> class? Yes, but with a few regards. Firstly, if we declare <span style="font-family: "courier new" , "courier" , monospace;">activationDate</span> final, we won't be able to activate the same object - we will need to create its copy. Similarily, we will need to clone whole customer while adding or removing any contact person. If we are okay with that, let's see how it works:</div>
<br />
<pre class="brush:java;">public class Customer {
private final long id;
private final String name;
private final ZonedDateTime creationDate;
private final ZonedDateTime activationDate;
private final List<ContactPerson> contactPeople;
private Customer(long id, String name, ZonedDateTime creationDate,
ZonedDateTime activationDate, List<ContactPerson> contactPeople) {
if (contactPeople == null) {
throw new IllegalArgumentException("Contact people list cannot be null");
}
if (StringUtils.isEmpty(name)) {
throw new IllegalArgumentException("Name cannot be empty");
}
this.id = id;
this.name = name;
this.creationDate = creationDate;
this.activationDate = activationDate;
this.contactPeople = new ArrayList<>(contactPeople);
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public ZonedDateTime getCreationDate() {
return creationDate;
}
public List<ContactPerson> getContactPeople() {
return Collections.unmodifiableList(contactPeople);
}
public Customer activate() {
return new Customer(this.id, this.name, this.creationDate,
ZonedDateTime.now(), new ArrayList<>(this.contactPeople));
}
public boolean isActive() {
return this.activationDate != null;
}
public Customer addContactPerson(ContactPerson contactPerson) {
final List<ContactPerson> newContactPersonList =
new ArrayList<>(this.contactPeople);
newContactPersonList.add(contactPerson);
return new Customer(this.id, this.name, this.creationDate,
this.activationDate, newContactPersonList);
}
public Customer removeContactPerson(long contactPersonId) {
final List<ContactPerson> newContactPersonList =
new ArrayList<>(this.contactPeople);
newContactPersonList.removeIf(it -> it.getId() == contactPersonId);
return new Customer(this.id, this.name, this.creationDate,
this.activationDate, newContactPersonList);
}
@Override
public String toString() {
return "Customer{" +
"id=" + id +
", name='" + name + '\'' +
", creationDate=" + creationDate +
", activationDate=" + activationDate +
", contactPeople=" + contactPeople +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Customer customer = (Customer) o;
if (id != customer.id) return false;
if (name != null ? !name.equals(customer.name) : customer.name != null) return false;
if (creationDate != null ? !creationDate.equals(customer.creationDate) : customer.creationDate != null) return false;
if (activationDate != null ? !activationDate.equals(customer.activationDate) : customer.activationDate != null) return false;
return contactPeople != null ? contactPeople.equals(customer.contactPeople) : customer.contactPeople == null;
}
@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (creationDate != null ? creationDate.hashCode() : 0);
result = 31 * result + (activationDate != null ? activationDate.hashCode() : 0);
result = 31 * result + (contactPeople != null ? contactPeople.hashCode() : 0);
return result;
}
public static Customer valueOf(String name, List<ContactPerson> contactPeople) {
return new Customer(Sequence.nextValue(), name, ZonedDateTime.now(),
null, contactPeople);
}
}</pre>
<br />
<ul>
<li>All instance fields private - <i>checked</i></li>
<li>No mutators (setters) - <i>checked</i></li>
<li>Any method that is supposed to change a state must create a copy with a properly updated fields - <i>checked</i></li>
<li>No method can be overriden - <i>checked</i></li>
<li>All instance fields final - <i>checked</i></li>
<li>Mutable instance fields must be secured with defensive copying - <i>checked</i></li>
</ul>
Please note that in <span style="font-family: "courier new" , "courier" , monospace;">getContactPeople</span> method we got back to a shallow copy solution. This is because <span style="font-family: "courier new" , "courier" , monospace;">ContactPerson</span> is an immutable class so we don't need to copy its objects any more. All right, we have our classes hermetized!<br />
<br />
<h2>
<span style="font-size: x-large;">
Serialization </span></h2>
<div>
<br />
It is a common thing that we send our objects throughout the network or persist them somehow (in a queue, event store, etc.). In order to convert object to some unified binary form we often use Java <span style="font-family: "courier new" , "courier" , monospace;">serialization</span> mechanism. We are not going to describe how serialization works but rather point out its connection with hermetization.<br />
<br />
Well, what my experience shows, there is something about serialization that makes people think that the only thing they should do is to implement <span style="font-family: "courier new" , "courier" , monospace;">Serializable</span> interface. Unfortunately it might be illusive. Let me explain.<br />
<br />
Deserialization restores the private state of an object. It means that we can treat <span style="font-family: "courier new" , "courier" , monospace;">readObject</span> method as another public constructor. Thus, we cannot trust the external byte stream (like we don't trust our clients) that it will always contain proper data. If there are any validations implemented in our constructors or setters, they should be applied within <span style="font-family: "courier new" , "courier" , monospace;">readObject</span> method, too. It will prevent us from initializing corrupted object.<br />
<br />
Another threat that we are exposed to is that the serialized byte stream might contain so called <span style="font-family: "courier new" , "courier" , monospace;">back references</span> to objects that are already inside the stream. If these objects are mutable, then we face the same problem like we described in <span style="font-family: "courier new" , "courier" , monospace;">Object references</span> chapter. You should know by now, that what we should do inside <span style="font-family: "courier new" , "courier" , monospace;">readObject</span> method is a defensive copy of all mutable objects.<br />
<br />
In case of <span style="font-family: "courier new" , "courier" , monospace;">ContactPerson</span> class, default serialized form of an object corresponds to its logical content, and we don't have any references to mutable objects nor validations there. As a result it is enough to simply impement <span style="font-family: "courier new" , "courier" , monospace;">Serializable</span> interface, like below:<br />
<br />
<pre class="brush:java;">public final class ContactPerson implements Serializable {
private static final long serialVersionUID = 1L;
...
}</pre>
<br />
In <span style="font-family: "courier new" , "courier" , monospace;">Customer</span> class, apart from implementing <span style="font-family: "courier new" , "courier" , monospace;">Serializable</span> interface, we need to override <span style="font-family: "courier new" , "courier" , monospace;">readObject</span> method and both put appropriate validations and make defensive copies of all instance fields that are mutable.<br />
<br />
<pre class="brush:java;">public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
private final long id;
private final String name;
private final ZonedDateTime creationDate;
private final ZonedDateTime activationDate;
private List<ContactPerson> contactPeople;
...
private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
s.defaultReadObject();
if (contactPeople == null) {
throw new NotSerializableException("Contact people list cannot be null");
}
if (StringUtils.isEmpty(name)) {
throw new NotSerializableException("Name cannot be empty");
}
contactPeople = new ArrayList<>(contactPeople);
}
}</pre>
<br />
One thing that we needed to do was removing the <span style="font-family: "courier new" , "courier" , monospace;">final</span> keyword from <span style="font-family: "courier new" , "courier" , monospace;">contactPeople</span> field. It is because we are doing defensive copying (shallow one) after the object is constructed - <span style="font-family: "courier new" , "courier" , monospace;">readObject</span> works like constructor but it isn't one. Here we partially break one of the rules from immutable object definition, but having defensive copy mechanism for this field, we will still have effectively immutable object and safe deserialization, too.
<br />
<br /></div>
<div>
<h2>
<span style="font-size: x-large;">
Conclusions</span></h2>
</div>
<br />
As you could see in this long article, there is a lot of philosophy around OOP concepts, which is not that simple as it might sometimes seem to be. You had a chance to see that all OOP concepts are complementary, and overlap each other. We cannot talk about hermetization, not mentioning encapsulation, abstraction or inheritance. Here are some rules that you should follow to have hermetization in your code:<br />
<br />
<ul>
<li>Create immutables when possible.</li>
<li>Keep access to instance members as restricted as possible.</li>
<li>Give your class a public access modifier only when you are sure that you want to expose it outside the package.</li>
<li>Declare accessors only to fields you want to expose to the outter world.</li>
<li>Declare modifiers only to fields that really might be changed in the future and that are not to be set automatically.</li>
<li>Give your class a behavior, so that methods reflect the abstraction, hiding data representation and other implementation details.</li>
<li>If you have instance fields that are references to mutable objects, provide defensive copying in getters, setters and constructors.</li>
<li>Try to keep your class <span style="font-family: "courier new" , "courier" , monospace;">final</span>. If you want your class to be extended, declare as many methods <span style="font-family: "courier new" , "courier" , monospace;">final</span> as possible, and document the class clearly.</li>
<li>Always prefer interfaces (or base classes from class hierarchy) rather than their implementations as types of fields/params/method return values.</li>
<li>Override <span style="font-family: "courier new" , "courier" , monospace;">toString()</span> method so that it prints information accessible programmatically from the outside of a class - it is like your API.</li>
<li>If your objects are supposed to be compared to each other or used as keys in data structure, provide your own <span style="font-family: "courier new" , "courier" , monospace;">equals()</span> and <span style="font-family: "courier new" , "courier" , monospace;">hashCode()</span> methods.</li>
<li>Prefer composition over inheritance.</li>
<li>Put proper validations and defensive copying (if needed) inside <span style="font-family: "courier new" , "courier" , monospace;">readObject</span> method while implementing <span style="font-family: "courier new" , "courier" , monospace;">Serializable</span> interface.</li>
</ul>
Bartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.com42tag:blogger.com,1999:blog-3619983083169551150.post-76353423191064867242017-07-05T14:02:00.001+02:002017-09-18T16:04:53.511+02:00Transaction synchronization and Spring application events - understanding @TransactionalEventListenerThe aim of this article is to explain how <span style="font-family: "courier new" , "courier" , monospace;">@TransactionalEventListener</span> works, how it differs from a simple <span style="font-family: "courier new" , "courier" , monospace;">@EventListener</span>, and finally - what are the threats that we should take into account before using it. Giving a real-life example, I will mainly focus on transaction synchronization issues not paying too much attention neither to consistency nor application event reliability. A complete SpringBoot project with described examples you will find <a href="https://github.com/bslota/transactional-event-listener">here</a>.<br />
<br />
<h2>
<span style="font-size: x-large;">
Example overview </span></h2>
<br />
Imagine we have a microservice which manages customers' basic information and triggers activation token generation after a customer is created. From the business perspective token generation is not an integral part of user creation and should be a separate process (this is very important assumption, which I will refer to later). To keep things simple, let's assume that a customer looks like this:
<br />
<pre class="brush:java;">@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String token;
public Customer() {}
public Customer(String name, String email) {
this.name = name;
this.email = email;
}
public void activatedWith(String token) {
this.token = token;
}
public boolean hasToken() {
return !StringUtils.isEmpty(token);
}
...
//getters
//equals and hashcode
}</pre>
<br />
We have a simple spring-data-jpa repository:
<br />
<pre class="brush:java;">public interface CustomerRepository extends JpaRepository<Customer, Long> {}
</pre>
<br />
And below you can see an essence of the business problem - creating new customer (persisting it in DB) and returning it.<br />
<br />
<pre class="brush:java;">@Service
public class CustomerService {
private final CustomerRepository customerRepository;
private final ApplicationEventPublisher applicationEventPublisher;
public CustomerService(CustomerRepository customerRepository, ApplicationEventPublisher applicationEventPublisher) {
this.customerRepository = customerRepository;
this.applicationEventPublisher = applicationEventPublisher;
}
@Transactional
public Customer createCustomer(String name, String email) {
final Customer newCustomer = customerRepository.save(new Customer(name, email));
final CustomerCreatedEvent event = new CustomerCreatedEvent(newCustomer);
applicationEventPublisher.publishEvent(event);
return newCustomer;
}
}
</pre>
<br />
As you can see, <span style="font-family: "courier new" , "courier" , monospace;">CustomerService</span> depends on two beans:<br />
<ol>
<li><span style="font-family: "courier new" , "courier" , monospace;">CustomerRepository</span> - interface for the purpose of saving customer</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">ApplicationEventPublisher</span> - Spring's super-interface for <span style="font-family: "courier new" , "courier" , monospace;">ApplicationContext</span>, which declares the way of event publishing inside Spring application</li>
</ol>
<i>Please note the constructor injection. If you are not familiar with this technique or not aware of its benefits relative to field injection, please read <a href="http://pillopl.github.io/constructor-injection/">this article</a>. </i><br />
<br />
Remember to give <span style="font-family: "courier new" , "courier" , monospace;">-1</span> during the code review if there is no test included! But wait, take it easy, mine is here:<br />
<br />
<pre class="brush:java;">@SpringBootTest
@RunWith(SpringRunner.class)
public class CustomerServiceTest {
@Autowired
private CustomerService customerService;
@Autowired
private CustomerRepository customerRepository;
@Test
public void shouldPersistCustomer() throws Exception {
//when
final Customer returnedCustomer = customerService.createCustomer("Matt", "matt@gmail.com");
//then
final Customer persistedCustomer = customerRepository.findOne(returnedCustomer.getId());
assertEquals("matt@gmail.com", returnedCustomer.getEmail());
assertEquals("Matt", returnedCustomer.getName());
assertEquals(returnedCustomer, persistedCustomer);
}
</pre>
<br />
The test does one simple thing - checks whether <span style="font-family: "courier new" , "courier" , monospace;">createCustomer</span> method creates a proper customer. One could say that in this kind of tests I shouldn't pay attention to implementation details (persisting entity through the repository, etc.) and rather put it in some unit test, and I would agree, but let's just leave it to keep the example clearer.<br />
<br />
You may ask now, where is the token generation. Well, due to the business case that we are discussing, <span style="font-family: "courier new" , "courier" , monospace;">createCustomer</span> method does not seem to be a good place to put any logic apart from simple creation of user (method name should always reflect its responsibility). In that kind of cases it might be a good idea to use the observer pattern to inform interested parties that a particular event took place. Following this considerations, you can see that we are calling <span style="font-family: "courier new" , "courier" , monospace;">publishEvent</span> method on <span style="font-family: "courier new" , "courier" , monospace;">applicationEventPublisher</span>. We are propagating an event of the following type:<br />
<br />
<pre class="brush:java;">public class CustomerCreatedEvent {
private final Customer customer;
public CustomerCreatedEvent(Customer customer) {
this.customer = customer;
}
public Customer getCustomer() {
return customer;
}
...
//equals and hashCode
}
</pre>
<br />
Note that it is just a <span style="font-family: "courier new" , "courier" , monospace;">POJO</span>. Since <span style="font-family: "courier new" , "courier" , monospace;">Spring 4.2</span> we are no longer obliged to extend <span style="font-family: "courier new" , "courier" , monospace;">ApplicationEvent</span> and can publish any object we like instead. Spring wraps it in <span style="font-family: "courier new" , "courier" , monospace;">PayloadApplicationEvent</span> itself.
<br />
<br />
We do also have an event listener component, like this:
<br />
<pre class="brush:java;">@Component
public class CustomerCreatedEventListener {
private static final Logger LOGGER = LoggerFactory.getLogger(CustomerCreatedEventListener.class);
private final TokenGenerator tokenGenerator;
public CustomerCreatedEventListener(TokenGenerator tokenGenerator) {
this.tokenGenerator = tokenGenerator;
}
@EventListener
public void processCustomerCreatedEvent(CustomerCreatedEvent event) {
LOGGER.info("Event received: " + event);
tokenGenerator.generateToken(event.getCustomer());
}
}
</pre>
<br />
Before we discuss this listener, let's briefly look at <span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;">TokenGenerator<span style="font-family: inherit;"></span></span></span> interface:<br />
<pre class="brush:java;">public interface TokenGenerator {
void generateToken(Customer customer);
}
</pre>
<br />
<br />
and its implementation:<br />
<pre class="brush:java;">@Service
public class DefaultTokenGenerator implements TokenGenerator {
private final CustomerRepository customerRepository;
public DefaultTokenGenerator(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@Override
public void generateToken(Customer customer) {
final String token = String.valueOf(customer.hashCode());
customer.activatedWith(token);
customerRepository.save(customer);
}
}
</pre>
<br />
<br />
We are simply generating a token, setting it as customer's property and updating the entity in database. Good, let's update our test class now, so that it checks not only the customer creation but also token generation.
<br />
<pre class="brush:java;">@SpringBootTest
@RunWith(SpringRunner.class)
public class CustomerServiceTest {
@Autowired
private CustomerService customerService;
@Autowired
private CustomerRepository customerRepository;
@Test
public void shouldPersistCustomerWithToken() throws Exception {
//when
final Customer returnedCustomer = customerService.createCustomer("Matt", "matt@gmail.com");
//then
final Customer persistedCustomer = customerRepository.findOne(returnedCustomer.getId());
assertEquals("matt@gmail.com", returnedCustomer.getEmail());
assertEquals("Matt", returnedCustomer.getName());
assertTrue(returnedCustomer.hasToken());
assertEquals(returnedCustomer, persistedCustomer);
}
}
</pre>
<br />
<h2>
<span style="font-size: x-large;">
@EventListener </span></h2>
<br />
As you can see, we have moved token generation logic into a separate component which is good (note the assumption at the beginning of the previous chapter), but do we have a real separation of concerns? Nope. <span style="font-family: "courier new" , "courier" , monospace;">@EventListener </span>registers the <span style="font-family: "courier new" , "courier" , monospace;">processCustomerCreatedEvent</span> as the listener of <span style="font-family: "courier new" , "courier" , monospace;">CustomerCreatedEvent</span> but it is called synchronously within the bounds of the same transaction as <span style="font-family: "courier new" , "courier" , monospace;">CustomerService</span>. It means, that if something goes wrong with token generation - customer won't be created. Is this the way it should really work? Surely not. Before we generate and set token, we would rather have a customer already created and saved in database (committed). Now this is the time to introduce <span style="font-family: "courier new" , "courier" , monospace;">@TransactionalEventListener</span> annotation.<br />
<br />
<h2>
<span style="font-size: x-large;">
@TransactionalEventListener - transaction synchronization</span></h2>
<h4>
</h4>
<h4>
</h4>
<span style="font-family: "courier new" , "courier" , monospace;">@TransactionalEventListener</span> is an <span style="font-family: "courier new" , "courier" , monospace;">@EventListener</span> enhanced with the ability to collaborate with surrounding transaction's phase. We call this a transaction synchronization - in other words it is a way of registering callback methods to be invoked when transaction is being completed. Synchronization is possible w<span style="font-family: inherit;">ithin following transaction phases (<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;">phase</span></span> attribute):</span><br />
<ul>
<li><span style="font-family: inherit;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;">AFTER_COMMIT</span> </span>(default setting) - specialization of <span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;">AFTER_COMPLETION</span></span>, used when transaction has successfully committed</span></li>
<li><span style="font-family: inherit;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;">AFTER_ROLLBACK</span> - specialization of <span style="font-family: "courier new" , "courier" , monospace;">AFTER_COMPLETION</span>, used when transaction has rolled back</span></span></li>
<li><span style="font-family: inherit;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;">AFTER_COMPLETION</span> - used when transaction has completed (regardless the success)</span></span></li>
<li><span style="font-family: inherit;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-family: "courier new" , "courier" , monospace;">BEFORE_COMMIT</span> - used before transaction commit </span></span></li>
</ul>
<span style="font-family: inherit;">When there is no transaction running th</span>en the method annotated with <span style="font-family: "courier new" , "courier" , monospace;">@TransactionalEventListener</span> won't be executed unless there is a parameter <span style="font-family: "courier new" , "courier" , monospace;">fallbackExecution</span> set to <span style="font-family: "courier new" , "courier" , monospace;">true</span>.<br />
<br />
Good, looks like this is something that we are looking for! Let's change <span style="font-family: "courier new" , "courier" , monospace;">@EventListener</span> annotation with <span style="font-family: "courier new" , "courier" , monospace;">@TransactionalEventListener</span> in <span style="font-family: "courier new" , "courier" , monospace;">CustomerCreatedEventListener</span>, then:<br />
<pre class="brush:java;">@TransactionalEventListener
public void processCustomerCreatedEvent(CustomerCreatedEvent event) {
LOGGER.info("Event received: " + event);
tokenGenerator.generateToken(event.getCustomer());
}
</pre>
<br />
We need to check now if everything works as we expect - let's run our test:<br />
<pre class="brush:text;">
java.lang.AssertionError:
Expected :Customer{id=1, name='Matt', email='matt@gmail.com', token='1575323438'}
Actual :Customer{id=1, name='Matt', email='matt@gmail.com', token='null'}
</pre>
Why is that? What have we missed? I tell you what: we spent too little time on analysing how transaction synchronization works. Now the crucial thing is that we have synchronized token generation with the transaction after it has been committed - so we shouldn't even expect that anything will be committed again! Javadoc for <span style="font-family: "courier new" , "courier" , monospace;">afterCommit</span> method of <span style="font-family: "courier new" , "courier" , monospace;">TransactionSynchronization</span> interface says it clearly:<br />
<br />
<i>The transaction will have been committed already, but the transactional resources might still be active and accessible. As a consequence, any data access code triggered at this point will still "participate" in the original transaction, allowing to perform some cleanup (with no commit following anymore!), unless it explicitly declares that it needs to run in a separate transaction. Hence: <b>Use {@code PROPAGATION_REQUIRES_NEW} for any transactional operation that is called from here.</b></i><br />
<br />
As we have already stated, we need to have a strong separation of concerns between a service call and an event listener logic. This means that we can use the advice given by Spring authors. Let's try annotating a method inside <span style="font-family: "courier new" , "courier" , monospace;">Defa<span style="font-family: "courier new" , "courier" , monospace;">ult</span>TokenGenerator</span>:<br />
<pre class="brush:java;">@Transactional(propagation = Propagation.REQUIRES_NEW)
public void generateToken(Customer customer) {
final String token = String.valueOf(customer.hashCode());
customer.activatedWith(token);
customerRepository.save(customer);
}
</pre>
<br />
If we run our test now, it passes!<br />
<br />
<i>Caveat: We are discussing interacting with AFTER_COMMIT phase only, but all these considerations apply to all AFTER_COMPLETION phases. In case of BEFORE_COMMIT phase none of the above problems should worry you, although you need to make a conscious decision whether your listener's code should </i><i><i>really </i>be executed in the same transaction.</i><br />
<br />
<h2>
<span style="font-size: x-large;">
Asynchronous execution</span></h2>
<br />
What if a token generation is a long lasting process? If it is not an essential part of creating a customer, then we could make one step forward and make our <span style="font-family: "courier new" , "courier" , monospace;">@TransactionalEventListener</span>-annotated method asynchronous one (via anotating it with <span style="font-family: "courier new" , "courier" , monospace;">@Async</span>). Asynchronous call means that we will execute listener's <span style="font-family: "courier new" , "courier" , monospace;">processCustomerCreatedEvent</span> in a separate thread. Bearing in mind that a single transaction in Spring framework is by default thread-bounded, we won't need <complete id="goog_2083673426">autonomous transaction in <span style="font-family: "courier new" , "courier" , monospace;">DefaultTokenGenerator</span> anymore.</complete><br />
<br />
Good, let's write a test for this case:<br />
<pre class="brush:java;">@SpringBootTest
@RunWith(SpringRunner.class)
@ActiveProfiles("async")
public class CustomerServiceAsyncTest {
@Autowired
private CustomerService customerService;
@Autowired
private CustomerRepository customerRepository;
@Test
public void shouldPersistCustomerWithToken() throws Exception {
//when
final Customer returnedCustomer = customerService.createCustomer("Matt", "matt@gmail.com");
//then
assertEquals("matt@gmail.com", returnedCustomer.getEmail());
assertEquals("Matt", returnedCustomer.getName());
//and
await().atMost(5, SECONDS)
.until(() -> customerTokenIsPersisted(returnedCustomer.getId()));
}
private boolean customerTokenIsPersisted(Long id) {
final Customer persistedCustomer = customerRepository.findOne(id);
return persistedCustomer.hasToken();
}
}
</pre>
<br />
The only thing that differentiates this test from the previous one is that we are using Awaitility library (a great and powerful tool) in order to await for the async task to complete. We also wrote a simple customerTokenIsPersisted helper method to check if token was properly set. And surely test passes brilliantly!<br />
<br />
<i>Caveat: I don't recommend performing any async tasks in BEFORE_COMMIT phase as you won't have any guarantee that they will complete before producer's transaction is committed.</i><br />
<br />
<h2>
<span style="font-size: x-large;">
Conclusions</span></h2>
<h4>
</h4>
<span style="font-family: "courier new" , "courier" , monospace;">@TransactionalEventListener</span> is a great alternative to <span style="font-family: "courier new" , "courier" , monospace;">@EventListener</span> in situations where you need to synchronize with one of transaction phases. You can declare listeners as synchronous or asynchronous. You need to keep in mind that with synchronous call you are by default working within the same transaction as the event producer. In case you synchronize to <span style="font-family: "courier new" , "courier" , monospace;">AFTER_COMPLETION</span> phase (or one of its specializations) you won't be able to persist anything in the database as there won't be commit procedure executed anymore. If you need to commit some changes anyway, you can declare an autonomous transaction on event listener code. <span style="font-family: "courier new" , "courier" , monospace;">BEFORE_COMMIT</span> phase is much simplier, because commit will be performed after calling event listeners. With asynchronous calls you don't have to worry about declaring autonomous transactions, as Spring's transactions are by default thread-bounded (you will get a new transaction anyway). It is a good idea if you have some long running task to be performed. I suggest using asynchronous tasks only when synchronizing to <span style="font-family: "courier new" , "courier" , monospace;">AFTER_COMPLETION</span> phase or one of its specializations. As long as you don't need to have your event listener's method transactional - described problems shouldn't bother you at all.<br />
<br />
<h2>
<span style="font-size: x-large;">
Further considerations</span></h2>
<br />
In a real-life scenarios numerous other requirements might occur. For example you might need to both persist customer and send an invitation email like it is depicted below:<br />
<pre class="brush:java;">@Component
public class CustomerCreatedEventListener {
private final MailingFacade mailingFacade;
private final CustomerRepository customerRepository;
public CustomerCreatedEventListener(MailingFacade mailingFacade, CustomerRepository customerRepository) {
this.mailingFacade = mailingFacade;
this.customerRepository = customerRepository;
}
@EventListener
public void processCustomerCreatedEvent(CustomerCreatedEvent event) {
final Customer customer = event.getCustomer();
// sending invitation email
mailingFacade.sendInvitation(customer.getEmail());
}
}
</pre>
<br />
Imagine a situation when an email is sent successfully, but right after it, our database goes down and it is impossible to commit the transaction (persist customer) - thus, we lose consistency! If such situation is acceptable within your business use case, then it is completely fine to leave it as it is, but if not then you have a much more complex problem to solve. I intentionally haven't covered consistency end event reliability issues here. If you want to have a broader picture of how you could possibly deal with such situations, I recommend reading <a href="http://pillopl.github.io/reliable-domain-events/">this article</a>.<br />
<br />
<br />
<br />
<br />
<br />
<br />Bartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.com13tag:blogger.com,1999:blog-3619983083169551150.post-83516759307345566382017-04-09T23:27:00.000+02:002017-06-06T00:08:33.219+02:00Example of multiple login pages with Spring Security and Spring BootI just finished preparing a Spring Security configuration for a Zuul proxy in my company when a new requirement in this area came in from the business. We needed to have different login pages for different URLs being accessed within the same application. I'm not a front-end guy, so my first thought was to enhance my existing security config. I found this topic interesting enough to investigate broader possibilities of defining separate security constraints for different URL path patterns. In this article I will describe an example on how to achieve this and how to test your configuration using Spring Boot and Thymeleaf as a templating engine. A complete project you will find <a href="https://github.com/bslota/multi-login">here</a>.
I will mainly focus on form-based login, but at the end you will also see how to benefit from these examples in order to provide various http security types within a single application. Enjoy!<br />
<br />
<br />
Imagine we have two home pages, that should be accessible under following paths: <span style="font-family: "courier new" , "courier" , monospace;">/regular/home</span> and <span style="font-family: "courier new" , "courier" , monospace;">/special/home</span>. We would like to have them secured with corresponding login forms: <span style="font-family: "courier new" , "courier" , monospace;">/regular/login</span>, and <span style="font-family: "courier new" , "courier" , monospace;">/special/login</span>. By deafault, Thymeleaf templates are supposed to be located in <span style="font-family: "courier new" , "courier" , monospace;">/templates</span> directory:
<br />
<pre class="brush:bash;">├───src
│ ├───main
│ │ ├───java
│ │ │ └───com
│ │ │ └───bslota
│ │ │ │ MultiLoginApplication.java
│ │ │ │
│ │ │ └───config
│ │ │ MvcConfig.java
│ │ │ SecurityConfig.java
│ │ │
│ │ └───resources
│ │ │ application.yml
│ │ │
│ │ ├───static
│ │ │ └───css
│ │ │ styles.css
│ │ │
│ │ └───templates
│ │ ├───regular
│ │ │ home.html
│ │ │ login.html
│ │ │
│ │ └───special
│ │ home.html
│ │ login.html
│ │
│ └───test
│ └───java
│ └───com
│ └───bslota
│ WebSecurityTest.java
│
│ .gitignore
│ mvnw
│ mvnw.cmd
│ pom.xml
</pre>
Now, apart from html templates we need to configure our application, so that it resolves all views properly. To keep it simple, this should be enough for our example:
<br />
<pre class="brush:java;">@Configuration
public class MvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("regular/home");
registry.addViewController("/regular/home").setViewName("regular/home");
registry.addViewController("/special/home").setViewName("special/home");
registry.addViewController("/regular/login").setViewName("regular/login");
registry.addViewController("/special/login").setViewName("special/login");
}
}</pre>
In order to introduce security into the application, we need to declare a following dependency:
<br />
<pre class="brush:xml;"><dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-security</artifactid>
</dependency>
</pre>
Hey, hold on, we are not going to do anything without testing (I hope you already have a habit of writing tests, don't you?). In order to test our security configuration, we need this library:
<br />
<pre class="brush:xml;"><dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-test</artifactid>
<scope>test</scope>
</dependency>
</pre>
Right now, what we have out of the box due to having <span style="font-family: "courier new" , "courier" , monospace;">spring-boot-starter-security</span> dependency on classpath are:<br />
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">HTTP-Basic</span> security setup for all endpoints,</li>
<li>randomly generated password logged in console during startup for a user named <span style="font-family: "courier new" , "courier" , monospace;">user</span>.</li>
</ul>
As we mentioned at the beginning, we want to have a form-based login. Let's define our requirements in a couple of simple tests, then:<br />
<br />
<pre class="brush:java;">@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
@AutoConfigureMockMvc
public class WebSecurityTest {
@Autowired
private MockMvc mockMvc;
@Test
public void testIfRegularHomePageIsSecured() throws Exception {
final ResultActions resultActions = mockMvc.perform(get("/regular/home"));
resultActions
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/regular/login"));
}
@Test
@WithMockUser
public void testIfLoggedUserHasAccessToRegularHomePage() throws Exception {
final ResultActions resultActions = mockMvc.perform(get("/regular/home"));
resultActions
.andExpect(status().isOk())
.andExpect(view().name("regular/home"));
}
@Test
@WithMockUser
public void testIfLoggedUserHasAccessToSpecialHomePage() throws Exception {
final ResultActions resultActions = mockMvc.perform(get("/special/home"));
resultActions
.andExpect(status().isOk())
.andExpect(view().name("special/home"));
}
}
</pre>
<br />
What you should know from this code is that we are creating a mock servlet environment (<span style="font-family: "courier new" , "courier" , monospace;">webEnvironment = SpringBootTest.WebEnvironment.MOCK</span>) and auto-configuring <span style="font-family: "courier new" , "courier" , monospace;">MockMvc</span> (<span style="font-family: "courier new" , "courier" , monospace;">@AutoConfigureMockMvc</span>) - a neat and powerful tool for web controller testing. With this setup you don't need to build and configure <span style="font-family: "courier new" , "courier" , monospace;">MockMvc</span> on your own - you can simply inject it as a regular bean dependency. Spring Boot never stops fascinating me.<br />
We have three tests written here. The first one says:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>given</b>:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> anonymous user</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>when</b>:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> trying to access /regular/home URL</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>then</b>:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> I get 302 HTTP response</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>and</b>:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> I'm redirected to /regular/login page</span><br />
<br />
And the second one:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>given</b>:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> a principal with username "user" and password "password"</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>when</b>:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> trying to access /regular/home URL</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>then</b>:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> I get 200 HTTP response</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b>and</b>:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> I access regular/home view</span><br />
<br />
The third one is almost the same as the second (the only difference is the url that is being accessed with <span style="font-family: "courier new" , "courier" , monospace;">MockMvc</span>). As long as <span style="font-family: "courier new" , "courier" , monospace;">when-then</span> parts should be rather clear, the <span style="font-family: "courier new" , "courier" , monospace;">given</span> part might be a bit confusing. In the first test we have not defined any security constraints, so the <span style="font-family: "courier new" , "courier" , monospace;">MockMvc</span> call will be be considered as one from anonymous user. In the second test, though, we are using <complete id="goog_1122233915"><span style="font-family: "courier new" , "courier" , monospace;">@WithMockUser</span> annotation which emulates a call as if it is performed by authenticated user. The <span style="font-family: "courier new" , "courier" , monospace;">SecurityContext </span>within so-annotated test will contain an implementation of <span style="font-family: "courier new" , "courier" , monospace;">Authentication </span>interface of type <span style="font-family: "courier new" , "courier" , monospace;">UsernamePasswordAuthenticationToken</span>. With this annotation, you can adjust username, roles/authorities and password as well. By default, we will have a principal with following details:</complete><br />
<ul>
<li><complete id="goog_1122233915">username: <span style="font-family: "courier new" , "courier" , monospace;">user</span></complete></li>
<li><complete id="goog_1122233915">password: <span style="font-family: "courier new" , "courier" , monospace;">password</span></complete></li>
<li><complete id="goog_1122233915">roles: <span style="font-family: "courier new" , "courier" , monospace;">USER</span> </complete></li>
</ul>
It would be sufficient to stick to defaults here. Okay, we have some tests, but they fail. Sure they do! Here is what we need to do now:<br />
<ul>
<li>Define <span style="font-family: "courier new" , "courier" , monospace;">AuthenticationManager</span> (in-memory one will be enough for this example) and create appropriate user,</li>
<li>Configure <span style="font-family: "courier new" , "courier" , monospace;">HttpSecurity</span> so that all resources are secured with form-based login under <span style="font-family: "courier new" , "courier" , monospace;">/regular/login.</span></li>
</ul>
<br />
<pre class="brush:java;"> @Configuration
public class SecurityConfig {
@Configuration
public static class RegularSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//@formatter:off
http
.authorizeRequests()
.antMatchers("/css/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/regular/login")
.defaultSuccessUrl("/regular/home")
.permitAll()
.and()
.logout()
.logoutUrl("/regular/logout")
.permitAll();
//@formatter:on
}
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER");
}
}
</pre>
Good, now within <span style="font-family: "courier new" , "courier" , monospace;">configureGlobal</span> method we configured an in-memory <span style="font-family: "courier new" , "courier" , monospace;">AuthenticationManager</span> and created a user, as desired. We also declared a <span style="font-family: "courier new" , "courier" , monospace;">RegularSecurityConfig</span> class that extends <span style="font-family: "courier new" , "courier" , monospace;">WebSecurityConfigurerAdapter</span> and overrides <span style="font-family: "courier new" , "courier" , monospace;">configure(HttpSecurity)</span> method - this gives us the ability to change default pre-configured security behaviour. Within the <span style="font-family: "courier new" , "courier" , monospace;">configure(HttpSecurity)</span> method, we:<br />
<ul>
<li>decided to authenticate any request (apart from accessing css files - nevermind that part),</li>
<li>set login page URL to <span style="font-family: "courier new" , "courier" , monospace;">/regular/login,</span></li>
<li>set default success login URL to <span style="font-family: "courier new" , "courier" , monospace;">/regular/home</span> - the place where users will be directed after authenticating, not having visited a secured page,</li>
<li>set logout URL to <span style="font-family: "courier new" , "courier" , monospace;">/regular/logout.</span></li>
</ul>
<span style="font-family: "courier new" , "courier" , monospace;"></span>Of course we don't need logout or default success URL details being defined to complete this example but you will appreciate it when you download and run the whole app, I hope. All right, now all tests are passed. What's next? Tests again:<br />
<pre class="brush:java;"> @Test
public void testIfSpecialHomePageIsSecured() throws Exception {
final ResultActions resultActions = mockMvc.perform(get("/special/home"));
resultActions
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/special/login"));
}
</pre>
This tests is very similar to the previously written one. We are checking whether anonymous user trying to access <span style="font-family: "courier new" , "courier" , monospace;">/special/home</span> page gets redirected to <span style="font-family: "courier new" , "courier" , monospace;">/special/login</span>. Surely this test won't pass. The remedy is to add a following code into <span style="font-family: "courier new" , "courier" , monospace;">SecurityConfig</span> class:
<br />
<pre class="brush:java;"> @Configuration
@Order(1)
public static class SpecialSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//@formatter:off
http
.antMatcher("/special/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/special/login")
.defaultSuccessUrl("/special/home")
.permitAll()
.and()
.logout()
.logoutUrl("/special/logout")
.permitAll();
//@formatter:on
}
}
</pre>
<br />
We just created yet another <span style="font-family: "courier new" , "courier" , monospace;">WebSecurityConfigurerAdapter</span> extension. When you look at the body of configure method, then you will see that it is pretty similar to the one that we had defined previously. The difference is that we have an <span style="font-family: "courier new" , "courier" , monospace;">antMatcher</span>, that enables us to filter and apply this settings only for URLs that begin with <span style="font-family: "courier new" , "courier" , monospace;">/special/</span> prefix. And how does Spring know which configure method (from which <span style="font-family: "courier new" , "courier" , monospace;">WebSecurityConfigurerAdapter</span> extension) should be invoked first? It is because the <span style="font-family: "courier new" , "courier" , monospace;">@Order(1)</span> annotation.<br />
Yep, we got it! We have implemented and tested our Spring MVC configuration with two separate login pages for different URLs being accessed. This example should show you how many possibilitis Spring Security gives you. Do not think that this kind of configuration is limited to form-based login - you could declare <span style="font-family: "courier new" , "courier" , monospace;">HTTP-Basic</span> security for all requests that concerns<span style="font-family: "courier new" , "courier" , monospace;"> /special/**</span> URLs as well or set any security constraints you like for whatever path templates.
Bartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.com9tag:blogger.com,1999:blog-3619983083169551150.post-39797383015862130602017-02-28T23:06:00.002+01:002017-09-18T16:06:00.408+02:00Defining bean dependencies with Java Config in Spring Framework<div style="text-align: left;">
I found it hard to choose a topic to describe in my first blog post. I wanted it not to be too trivial and too complicated neither. It turned out that there are many basic concepts in Spring Framework that can be confusing. Java-based configuration is one of them. I hear my colleagues asking from time to time about it, and I see numerous questions regarding it on StackOverflow. Nevermind the motivation, below you will find a compact description of how to declare beans with Java Config.</div>
Please note that this post won't cover bean dependencies of different scopes nor discussion on annotations like <span style="font-family: "courier new" , "courier" , monospace;">@Component</span>, <span style="font-family: "courier new" , "courier" , monospace;">@Service</span>, <span style="font-family: "courier new" , "courier" , monospace;">@Repository</span>, etc., that are often a good alternative to described approach. Java Config might seem to be an overkill in many situations but I hope you will find that post useful anyway. Let's go!<i><br /></i><br />
<h2>
<span style="font-size: x-large;">Inter-bean reference</span></h2>
<br />
Imagine we have a following repository:
<br />
<pre class="brush:java;">public class MyRepository {
public String findString() {
return "some-string";
}
}
</pre>
and a service, that depends on repository of that type:
<br />
<pre class="brush:java;">public class MyService {
private final MyRepository myRepository;
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
public String generateSomeString() {
return myRepository.findString() + "-from-MyService";
}
}
</pre>
First solution is pretty straightforward and it's called <span style="font-family: "courier new" , "courier" , monospace;">inter-bean<span style="font-family: "courier new" , "courier" , monospace;"> </span>reference</span>. <span style="font-family: "courier new" , "courier" , monospace;">MyService</span> bean depends on <span style="font-family: "courier new" , "courier" , monospace;">MyRepository</span>. In order to fulfill this dependency, we pass <span style="font-family: "courier new" , "courier" , monospace;">myRepository()</span> method as a constructor parameter (constructor injection).
<br />
<pre class="brush:java;">@Configuration
class MyConfiguration {
@Bean
public MyService myService() {
return new MyService(myRepository());
}
@Bean
public MyRepository myRepository() {
return new MyRepository();
}
}</pre>
Easy, right? Good, let's complicate it a bit.
Imagine we have a following repository, that has a few dependencies - to make it clearer, I will use String fields:
<br />
<pre class="brush:java;">public class MyRepository {
private final String prefix;
private final String suffix;
public MyRepository (String prefix, String suffix) {
this.prefix = prefix;
this.suffix = suffix;
}
public String findString() {
return prefix + "-some-string-" + suffix;
}
}
</pre>
<span style="font-family: "courier new" , "courier" , monospace;">MyService</span> stays the same. Now we want to create a singleton bean of type <span style="font-family: "courier new" , "courier" , monospace;">MyRepository</span>, where prefix and suffix are values from external properties file. In order to inject those properties, we will use <span style="font-family: "courier new" , "courier" , monospace;">@Value</span> annotation.
<br />
<pre class="brush:java;">@Configuration
class MyConfiguration {
@Bean
public MyService myService() {
return new MyService(myRepository(null, null));
}
@Bean
public MyRepository myRepository(@Value("${repo.prefix}") String prefix,
@Value("${repo.suffix}") String suffix) {
return new MyRepository(prefix, suffix);
}
}</pre>
Wait, what did I just do? I did a constructor injection with a method having both params equal to <span style="font-family: "courier new" , "courier" , monospace;">null</span>. Here is how it all works: <span style="font-family: "courier new" , "courier" , monospace;">@Configuration</span> annotation tells Spring that so-annotated class will have one or more bean defined inside. <span style="font-family: "courier new" , "courier" , monospace;">@Bean</span> annotation is a way of telling Spring container to manage the bean returned by so-annotated method. Like in examples above, <span style="font-family: "courier new" , "courier" , monospace;">@Bean </span>methods are generally used inside configuration classes, that are proxied by <span style="font-family: "courier new" , "courier" , monospace;">CGLIB </span>-
the result of bean defining method is registered as a Spring bean and
each call of this method will return the same bean (as long as it is a
singleton of course). Thus, thanks to <span style="font-family: "courier new" , "courier" , monospace;">CGLIB</span>, whatever params (like <span style="font-family: "courier new" , "courier" , monospace;">null</span>s in the example above) you use while calling such methods you will get the proper bean. Remember also that according to <span style="font-family: "courier new" , "courier" , monospace;">CGLIB</span> usage configuration <span style="font-family: "courier new" , "courier" , monospace;"></span> classes and bean-defining methods must not be private or final.<br />
<br />
There is a caveat, though. <span style="font-family: "courier new" , "courier" , monospace;">@Bean</span> annotation might be used not only in <span style="font-family: "courier new" , "courier" , monospace;">@Configuration</span> classes - it can be used in <span style="font-family: "courier new" , "courier" , monospace;">@Component</span> for example. Then we are talking about a so called <span style="font-family: "courier new" , "courier" , monospace;">Lite mode</span>.
In this case there are no proxies created, so method invocations are not
intercepted and thus interpreted as a typical Java method invocation.<br />
<br />
I think that inter-bean reference is a very nice way of defining bean dependencies inside <span style="font-family: "courier new" , "courier" , monospace;">@Configuration </span>class as long as bean-defining method has no parameters. Otherwise, I choose the below one - read on!<br />
<br />
<h2>
<span style="font-size: x-large;">Dependency as @Bean method parameter</span></h2>
<br />
Okay, and what if you don't like passing methods as arguments? Or you have <span style="font-family: "courier new" , "courier" , monospace;">MyRepository</span> bean defined with <span style="font-family: "courier new" , "courier" , monospace;">@Component</span> annotation or in some other <span style="font-family: "courier new" , "courier" , monospace;">@Configuration</span> class (but of course in the same context)? It is enough to put your dependency as a method parameter (<span style="font-family: "courier new" , "courier" , monospace;">@Autowired</span> is not needed!):<br />
<pre class="brush:java;">@Configuration
class MyConfiguration {
@Bean
public MyService myService(MyRepository myRepository) {
return new MyService(myRepository);
}
}</pre>
But, hold on - what if I have several <span style="font-family: "courier new" , "courier" , monospace;">MyRepository</span> beans? Aha! Spring firstly looks at the type of parameter. If it finds more than one bean of this type - it tries to inject by name (yes, the name of the parameter must match the bean name):<br />
<pre class="brush:java;">@Configuration
class MyConfiguration {
@Bean
public MyRepository myFirstRepository() {
return new MyRepository("first", "repository");
}
//a bean that will be injected by name into myService
@Bean
public MyRepository mySecondRepository() {
return new MyRepository("second", "repository");
}
@Bean
public MyService myService(MyRepository mySecondRepository) {
return new MyService(myRepository);
}
}</pre>
If you don't want to base on parameter name, you can use <span style="font-family: "courier new" , "courier" , monospace;">@Qualifier</span> annotation as well, and it will take precedence over the parameter name:<br />
<pre class="brush:java;">@Configuration
class MyConfiguration {
//a bean that will be injected by name into myService
@Bean
public MyRepository myFirstRepository() {
return new MyRepository("first", "repository");
}
@Bean
public MyRepository mySecondRepository() {
return new MyRepository("second", "repository");
}
@Bean
public MyService myService(@Qualifier("myFirstRepository") MyRepository someRepository) {
return new MyService(someRepository);
}
}</pre>
<br />
<h2>
<span style="font-size: x-large;">@Configuration composition</span></h2>
<br />
You may now wonder what to do when you have configuration spread over numerous <span style="font-family: "courier new" , "courier" , monospace;">@Configuration</span> classes and you want to set dependencies among them. Let's consider following classes:<br />
<pre class="brush:java;">@Configuration
class FirstConfiguration {
@Bean
public FirstService firstService() {
return new FirstService();
}
}</pre>
<pre class="brush:java;">@Configuration
class SecondConfiguration {
@Bean
public SecondService secondService() {
return new SecondService();
}
}</pre>
Now imagine that <span style="font-family: "courier new" , "courier" , monospace;">SecondService</span> becomes dependent on <span style="font-family: "courier new" , "courier" , monospace;">FirstService</span>. If both configurations are settled in common application context (this is important here!), you can inject the bean like in one of previous examples:<br />
<pre class="brush:java;">@Configuration
class SecondConfiguration {
@Bean
public SecondService secondService(FirstService firstService) {
return new SecondService(firstService);
}
}</pre>
<span style="font-family: "courier new" , "courier" , monospace;">@Configuration</span> is meta-annotated with <span style="font-family: "courier new" , "courier" , monospace;">@Component</span>, which means that the class will be component scanned, and you can benefit from DI concepts brought in by Spring. It means you can also autowire your bean this way:<br />
<pre class="brush:java;">@Configuration
class SecondConfiguration {
@Autowired
private FirstService firstService;
@Bean
public SecondService secondService() {
return new SecondService(firstService);
}
}</pre>
As I mentioned before, <span style="font-family: "courier new" , "courier" , monospace;">@Configuration</span> is a <span style="font-family: "courier new" , "courier" , monospace;">@Component</span>. Thus, you can inject it as if it is a regular bean, and call its methods in order to retrieve beans (you will inject a <span style="font-family: "courier new" , "courier" , monospace;">CGLIB </span>proxy!).<br />
<pre class="brush:java;">@Configuration
class SecondConfiguration {
@Autowired
private FirstConfiguration firstConfiguration;
@Bean
public SecondService secondService() {
return new SecondService(firstConfiguration.firstService());
}
}</pre>
It's not all. There is yet another Spring mechanism hidden under the <span style="font-family: "courier new" , "courier" , monospace;">@Import</span> annotation:<br />
<pre class="brush:java;">@Configuration
@Import({FirstConfiguration.class})
class SecondConfiguration {
...
}</pre>
This looks nice, gives you the ability to relate different configurations not necessarily under the same context scope. In this setup you can use autowiring of beans and the configuration class as well (see two previous code snippets).<br />
<br />
<h2>
<span style="font-size: x-large;">Conclusions</span></h2>
<br />
Defining bean dependencies is a very basic concept of Spring framework, but as you could see here, there are lots of possibilities to do it, and there are enough approaches to get confused. Which to choose, which is the best, which looks nice, and which is ugly - it depends on the situation and personal (or team) preferences. How do I do it?<br />
<ul>
<li>When I have bean definitions inside one configuration classes, and bean-definig methods have no parameters - I use inter-bean reference, otherwise - I choose passing bean as method parameter. IDE easy navigation is not as vital as good looking code.</li>
<li>When I have two <span style="font-family: "courier new" , "courier" , monospace;">@Configuration</span> classes inside a common context - I pass beans as method paremeters or autowire them.</li>
<li>When I have two <span style="font-family: "courier new" , "courier" , monospace;">@Configuration</span> classes in separate contexts - I use <span style="font-family: "courier new" , "courier" , monospace;">@Import</span> annotation and I pass beans as method paremeters or autowire them. </li>
</ul>
<ul>
</ul>
Bartłomiej Słotahttp://www.blogger.com/profile/03700079226605716625noreply@blogger.com6