<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Spring - bdabek.pl</title>
	<atom:link href="https://www.bdabek.pl/tag/spring/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bdabek.pl/tag/spring/</link>
	<description>Bartosz Dąbek</description>
	<lastBuildDate>Tue, 31 Dec 2024 06:31:16 +0000</lastBuildDate>
	<language>pl-PL</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.bdabek.pl/wp-content/uploads/2020/10/cropped-5986134a-46ba-41ac-9c82-bb4ffb3a7bf3_200x200-1-150x150.png</url>
	<title>Spring - bdabek.pl</title>
	<link>https://www.bdabek.pl/tag/spring/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Aspekty i Spring 👈</title>
		<link>https://www.bdabek.pl/spring-aop/</link>
					<comments>https://www.bdabek.pl/spring-aop/#comments</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Thu, 10 Feb 2022 21:26:01 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Spring]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=2973</guid>

					<description><![CDATA[<p>Spring AOP to nic trudnego jeżeli mamy kawałek fundamentalej wiedzy. Rozbierając na czynniki pierwsze Aspekty i Springa jesteśmy lepiej w stanie pojąć i zrozumieć o co tam chodzi. W dzisiejszym artykule: Aspekty i Spring Koncept Aspektów Rodzaje Advice w AOP Mechanizm Proxy Przykład użycia Programowanie aspektowe (AOP) uzupełnia programowanie obiektowe (OOP), dostarczając innego sposobu myślenia&#8230;&#160;<a href="https://www.bdabek.pl/spring-aop/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">Aspekty i Spring 👈</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/spring-aop/">Aspekty i Spring 👈</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Spring AOP to nic trudnego jeżeli mamy kawałek fundamentalej wiedzy. Rozbierając na czynniki pierwsze Aspekty i Springa jesteśmy lepiej w stanie pojąć i zrozumieć o co tam chodzi.</p>
<p>W dzisiejszym artykule:</p>
<ul>
<li><a href="#Aspekty i Spring"><strong>Aspekty i Spring</strong></a></li>
<li><a href="#Koncept Aspektów"><strong>Koncept Aspektów</strong></a></li>
<li><a href="#Rodzaje Advice w AOP"><strong>Rodzaje Advice w AOP</strong></a></li>
<li><a href="#Mechanizm Proxy"><strong>Mechanizm Proxy</strong></a></li>
<li><a href="#Przykład użycia"><strong>Przykład użycia</strong></a></li>
</ul>
<hr />
<h2><h2 id="Aspekty i Spring"> <a href="#Aspekty i Spring"><span class="dashicons dashicons-admin-links"></span></a>Aspekty i Spring</h2></h2>
<p>Programowanie aspektowe (AOP) uzupełnia programowanie obiektowe (OOP), dostarczając innego sposobu myślenia o strukturze programu. Kluczową jednostką modularności programowania obiektowego jest klasa, podczas gdy w AOP <strong>jednostką modularności jest aspekt</strong>. Aspekty umożliwiają modularyzację zagadnień (takich jak zarządzanie transakcjami), które dotyczą wielu typów i obiektów.</p>
<p>AOP jest paradygmatem programowania, który ma na celu zwiększenie modularności. Czyni to poprzez dodawanie dodatkowych zachowań do istniejącego kodu bez modyfikowania samego kodu. Zamiast tego, możemy zadeklarować nowy kod i nowe zachowanie osobno.</p>
<p><a href="https://www.bdabek.pl/spring-aop/aspekty-01/" rel="attachment wp-att-2988"><img fetchpriority="high" decoding="async" class="aligncenter size-full wp-image-2988" src="https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-01.webp" alt="" width="1224" height="816" srcset="https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-01.webp 1224w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-01-300x200.webp 300w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-01-1024x683.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-01-768x512.webp 768w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-01-930x620.webp 930w" sizes="(max-width: 1224px) 100vw, 1224px" /></a></p>
<p>Jednym z <strong>kluczowych komponentów Springa jest framework AOP</strong>. Podczas gdy kontener Spring IoC nie zależy od AOP (co oznacza, że nie musisz używać AOP, jeśli nie chcesz), AOP uzupełnia Spring IoC, aby zapewnić wydajne rozwiązania. AOP w Springu jest używant m.in. do:</p>
<ul>
<li>Dostarczania deklaratywnych usług &#8211; najważniejszą taką usługą jest <a href="https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/" target="_blank" rel="noopener">zarządzanie transakcjami</a>.</li>
<li>Pozwala użytkownikom implementować niestandardowe aspekty, uzupełniając ich użycie OOP o AOP.</li>
</ul>
<hr />
<h2><h2 id="Koncept Aspektów"> <a href="#Koncept Aspektów"><span class="dashicons dashicons-admin-links"></span></a>Koncept Aspektów</h2></h2>
<p>Aby lepiej zrozumieć działanie i odsłonić magię aspektów, trzeba się zapoznać z tym jak ten mechanizm działa. Spójrz na obrazek i przejdź do opisu definicji, aby lepiej poznać konept aspektów.</p>
<p><a href="https://www.bdabek.pl/spring-aop/aspekty-02/" rel="attachment wp-att-2990"><img decoding="async" class="aligncenter size-full wp-image-2990" src="https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-02.webp" alt="" width="1183" height="845" srcset="https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-02.webp 1183w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-02-300x214.webp 300w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-02-1024x731.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-02-768x549.webp 768w" sizes="(max-width: 1183px) 100vw, 1183px" /></a></p>
<h3><h3 id="JoinPoint"> <a href="#JoinPoint"><span class="dashicons dashicons-admin-links"></span></a>JoinPoint</h3></h3>
<p>Joinpoint jest punktem podczas wykonywania programu, takim jak wykonanie metody lub obsługa wyjątku. <strong>W Spring AOP, JoinPoint zawsze reprezentuje wykonanie metody.</strong></p>
<h3><h3 id="Pointcut"> <a href="#Pointcut"><span class="dashicons dashicons-admin-links"></span></a>Pointcut</h3></h3>
<p>Poincut jest predykatem, który pomaga dopasować poradę (Advice), która ma być zastosowana przez Aspekt w konkretnym JoinPoincie. Często kojarzymy Advice z Pointcutem i jest ona uruchamiana w dowolnym JoinPoincie dopasowanym przez ten Poincut.</p>
<h3><h3 id="Advice"> <a href="#Advice"><span class="dashicons dashicons-admin-links"></span></a>Advice</h3></h3>
<p>Advice jest akcją podejmowaną przez aspekt w konkretnym JoinPoincie. Są różne typy porad, o czym w <a href="#Rodzaje Advice w AOP">kolejnym punkcie</a>. W Springu, Advice jest modelowany jako interceptor, utrzymujący łańcuch interceptorów wokół Joinpoint.</p>
<hr />
<h2><h2 id="Rodzaje Advice w AOP"> <a href="#Rodzaje Advice w AOP"><span class="dashicons dashicons-admin-links"></span></a>Rodzaje Advice w AOP</h2></h2>
<p><a href="https://www.bdabek.pl/spring-aop/aspekty-03/" rel="attachment wp-att-2999"><img decoding="async" class="aligncenter size-full wp-image-2999" src="https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-03.webp" alt="" width="602" height="217" srcset="https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-03.webp 602w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-03-300x108.webp 300w" sizes="(max-width: 602px) 100vw, 602px" /></a></p>
<p>Spring AOP zawiera następujące rodzaje porad:</p>
<ul>
<li><strong>Before advice</strong> &#8211; porada, która działa przed JoinPointem, ale która nie ma możliwości zatrzymania wykonania programu (chyba, że rzuci wyjątek).</li>
<li><strong>After returning advice </strong>&#8211; porada, którą należy uruchomić po normalnym zakończeniu JoinPointu (na przykład, jeśli metoda powróci bez rzucenia wyjątku).</li>
<li><strong>After throwing advice </strong>&#8211; porada, którą należy uruchomić, jeśli metoda zakończy działanie rzucając wyjątek.</li>
<li><strong>After (finally) advice </strong>&#8211; porada, którą należy uruchomić niezależnie od sposobu, w jaki JoinPoint wychodzi z wykonania (normalny lub zakończony wyjątkiem).</li>
<li><strong>Around advice </strong>&#8211; porada, która otacza JoinPoint, taki jak wywołanie metody. Jest to najpotężniejszy rodzaj porady. Wokół porady może wykonywać niestandardowe zachowanie przed i po wywołaniu metody. Jest ona również odpowiedzialna za wybór, czy kontynuować wykonanie do punktu złączenia (JoinPointu), czy też skrócić wykonanie zalecanej metody poprzez zwrócenie własnej wartości lub rzucenie wyjątku.</li>
</ul>
<hr />
<h2><h2 id="Mechanizm Proxy"> <a href="#Mechanizm Proxy"><span class="dashicons dashicons-admin-links"></span></a>Mechanizm Proxy</h2></h2>
<p>Spring AOP do utworzenia proxy dla danego obiektu docelowego używa albo:</p>
<ul>
<li>dynamicznych proxy JDK</li>
<li>albo CGLIB</li>
</ul>
<p>Dynamiczne proxy JDK są wbudowane w JDK, podczas gdy CGLIB jest powszechną biblioteką definicji klas o otwartym kodzie źródłowym (przepakowaną do spring-core).</p>
<p>Jeśli obiekt docelowy, który ma być <em>proxowany</em>, implementuje przynajmniej jeden interfejs, używane jest dynamiczne proxy JDK.  Natomiast jeżeli obiekt docelowy nie implementuje żadnych interfejsów, tworzone jest proxy przez CGLIB.</p>
<p><a href="https://www.bdabek.pl/spring-aop/aspekty-04/" rel="attachment wp-att-3002"><img decoding="async" class="aligncenter size-full wp-image-3002" src="https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-04.webp" alt="" width="1279" height="630" srcset="https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-04.webp 1279w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-04-300x148.webp 300w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-04-1024x504.webp 1024w, https://www.bdabek.pl/wp-content/uploads/2022/05/aspekty-04-768x378.webp 768w" sizes="(max-width: 1279px) 100vw, 1279px" /></a></p>
<p>&nbsp;</p>
<hr />
<h2><h2 id="Przykład użycia"> <a href="#Przykład użycia"><span class="dashicons dashicons-admin-links"></span></a>Przykład użycia</h2></h2>
<p>Zaczynamy od napisania Join Pointu &#8211; czyli <strong>w</strong> <strong>przypadku springa będzie to jakaś metoda</strong>.</p><pre class="crayon-plain-tag">@Component
public class BusinessClass{
    public void validateTransaction() {
        System.out.println("...validating");
    }
}</pre><p>Definijuemy Aspect, Pointcuty oraz Advice&#8217;y. Pointcuty można definiować oddzielnie a później wykorzystywać jako <em>&#8217;metodę&#8217; </em>w Advice.</p><pre class="crayon-plain-tag">@Aspect
@Component
public class LoggingAspect {

    @Pointcut("execution(* BusinessClass.validateTransaction(..))")
    public void logAfter() {
        //pointcut
    }

    @Before("execution(* BusinessClass.validateTransaction())")     //point-cut expression
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("BusinessClass.logBefore() : " + joinPoint.getSignature().getName());
    }

    @AfterReturning(pointcut = "logAfter()")
    public void logujWyjscieZUslugi(JoinPoint joinPoint) {
        System.out.println("BusinessClass.afterRetuning() : " + joinPoint.getSignature().getName());
    }
}</pre><p>Po wywołaniu metody, na którą Aspekt był założony wynik naszego programu jest następujący:</p><pre class="crayon-plain-tag">BusinessClass.logBefore() : validateTransaction
...validating
BusinessClass.afterRetuning() : validateTransaction</pre><p></p>
<hr />
<h2>Podsumowanie</h2>
<p><a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/lightbulb/" rel="attachment wp-att-976" data-slb-active="1" data-slb-asset="1379905354" data-slb-internal="976"><img decoding="async" class="aligncenter wp-image-976 size-thumbnail lazyloaded" src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" alt="" width="150" height="150" data-src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" /></a></p>
<p>Mechanizm AOP z pewnością jest jednym z bardziej zaawansowanych technik programowania, która w pewnym momencie kariery staje się niezbędna. Aspekty pozwalają nam na wszechstronność pisania kodu. Za ich pomocą możemy bezinwazyjnie m.in. dodać logi audytu, lub transakcyjność. Jednak z doświadczeniem przychodzi pewna pokora i chciałbym ustrzec wszystkich podjaranych, że <strong>czytelność i utrzymanie kodu jest ważniejsze</strong> niż kod napisany <em>fajnie</em>. Z tego powodu raczej odradzam dodawanie biznes case&#8217;ów w postaci aspektów. Pamiętaj, ten kod ktoś musi później utrzymać.</p>
<p>Źródła:</p>
<ul>
<li><a href="https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop">https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop</a></li>
<li><a href="https://howtodoinjava.com/spring-aop-tutorial/">https://howtodoinjava.com/spring-aop-tutorial/</a></li>
<li><a href="https://www.baeldung.com/spring-aop">https://www.baeldung.com/spring-aop</a></li>
<li><a href="https://blog.allegro.tech/2014/12/aspects-in-spring.html">https://blog.allegro.tech/2014/12/aspects-in-spring.html</a></li>
</ul>
<p>Artykuł <a href="https://www.bdabek.pl/spring-aop/">Aspekty i Spring 👈</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/spring-aop/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>🆒 Spring &#8211; Zrozumieć Adnotacje Wstrzykiwania Zależności 👌</title>
		<link>https://www.bdabek.pl/%f0%9f%86%92-spring-zrozumiec-adnotacje-wstrzykiwania-zaleznosci-%f0%9f%91%8c/</link>
					<comments>https://www.bdabek.pl/%f0%9f%86%92-spring-zrozumiec-adnotacje-wstrzykiwania-zaleznosci-%f0%9f%91%8c/#comments</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Sat, 26 Dec 2020 11:00:55 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Spring]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=2406</guid>

					<description><![CDATA[<p>Spring pozwala na manualną oraz automatyczną rejestrację beanów. Do manualnej rejestracji zależności tworzymy własne configi (jak tutaj). Natomiast w celu automatycznej rejestracji, Spring udostępnia nam adnotacje zwane stereotypami. Cześć  Dziś zajmiemy się omówieniem poszczególnych stereotypów. Kiedyś na rozmowie rekrutacyjnej dostałem również pytanie o stereotypy i kiedy ich używać, więc o tym też wspomnę. W dzisiejszym&#8230;&#160;<a href="https://www.bdabek.pl/%f0%9f%86%92-spring-zrozumiec-adnotacje-wstrzykiwania-zaleznosci-%f0%9f%91%8c/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">🆒 Spring &#8211; Zrozumieć Adnotacje Wstrzykiwania Zależności 👌</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/%f0%9f%86%92-spring-zrozumiec-adnotacje-wstrzykiwania-zaleznosci-%f0%9f%91%8c/">🆒 Spring &#8211; Zrozumieć Adnotacje Wstrzykiwania Zależności 👌</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Spring pozwala na manualną oraz automatyczną rejestrację beanów. Do manualnej rejestracji zależności tworzymy własne configi (<a href="https://www.bdabek.pl/spring-framework-jak-bronic-sie-przed-oddaniem-kontroli-frameworkowi/">jak tutaj</a>). Natomiast w celu automatycznej rejestracji, Spring udostępnia nam adnotacje zwane stereotypami.</p>
<hr />
<h3>Cześć <img decoding="async" class="emoji" role="img" draggable="false" src="https://s.w.org/images/core/emoji/12.0.0-1/svg/1f642.svg" alt="&#x1f642;" /></h3>
<p>Dziś zajmiemy się omówieniem poszczególnych stereotypów. Kiedyś na rozmowie rekrutacyjnej dostałem również pytanie o stereotypy i kiedy ich używać, więc o tym też wspomnę.</p>
<p>W dzisiejszym artykule:</p>
<ul>
<li><a href="#Mechanizm wstrzykiwania zależności"><strong>Mechanizm wstrzykiwania zależności</strong></a></li>
<li><a href="#Stereotypy"><strong>Stereotypy</strong></a></li>
<li><a href="#Różnice pomiędzy poszczególnymi adnotacjami"><strong>Różnice pomiędzy poszczególnymi adnotacjami</strong></a></li>
</ul>
<hr id="Mechanizm wstrzykiwania zależności" />
<h2 id="Mechanizm wstrzykiwania zależności"> <a href="#Mechanizm wstrzykiwania zależności"><span class="dashicons dashicons-admin-links"></span></a>Mechanizm wstrzykiwania zależności</h2>
<p>Podczas pierwszych wydań Springa, wszystkie używane beany były deklarowane w plikach XML. Dla większych projektów, szybko stało się to trudnym zadaniem. Na szczęście ludzie od Springa dość szybko rozpoznali problem. W późniejszych wersjach, dostarczone zostało wstrzykiwanie zależności przy pomocy andotacji i/lub konfiguracji opartej na Javie. Oznacza to, że zamiast deklarowania beanów używając plików XML, możemy wstrzykiwać zależności poprzez adnotacje, które przy odpowiedniej konfiguracji zostaną automatycznie zaczytane przez Springa.</p>
<p>Aby włączyć automatyczną rejestrację beanów w przypadku czystego Springa, na klasie konfiguracyjnej należy dołączyć adnotację <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/ComponentScan.html">@ComponentScan</a>. W przypadku projektu spring bootowego nie musimy niczego dodawać. Pakiety a zarazem klasy, znajdujące się pod klasą, która uruchamia naszą aplikację zostaną automatycznie zeskanowane. Jest to oczywiście zasługa adnotacji <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html">@SpringBootApplication</a>, która pod spodem posiada @ComponentScan.</p>
<hr id="Stereotypy" />
<h2 id="Stereotypy"> <a href="#Stereotypy"><span class="dashicons dashicons-admin-links"></span></a>Stereotypy</h2>
<p>Wiedząc już, że Spring umożliwia nam wstrzykiwanie zależności za pomocą adnotacji, jakich adnotacji należy używać? Adnotacje jakich możemy użyć nazywa się stereotypami, dlatego że zostały one umieszczone w pakiecie <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/package-summary.html">stereotype</a>. Adnotacje te pozwolą Springowi na zarejestrowanie nowego beana, ale trzeba uważać!</p>
<p><a href="https://www.bdabek.pl/?attachment_id=2670" rel="attachment wp-att-2670"><img decoding="async" class="aligncenter size-full wp-image-2670" src="https://www.bdabek.pl/wp-content/uploads/2020/12/stereotypes.png" alt="" width="640" height="369" srcset="https://www.bdabek.pl/wp-content/uploads/2020/12/stereotypes.png 640w, https://www.bdabek.pl/wp-content/uploads/2020/12/stereotypes-300x173.png 300w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>
<p>Uwaga uwaga &#8211; tak naprawdę jedyną adnotacją, która jest automatycznie wykrywana przez Springa jest adnotacja <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html">@Component</a>! W praktyce jednak wygląda to tak, że każda z adnotacji <em>&#8217;potomnych&#8217;</em> (@Controller, @Service, @Repository) dodaje adnotację @Component w swojej deklaracji. Wynikiem tego jest oczywiście to, że nasze klasy są rejestrowane jak należy.</p>
<hr id="Różnice pomiędzy poszczególnymi adnotacjami" />
<h2 id="Różnice pomiędzy poszczególnymi adnotacjami"> <a href="#Różnice pomiędzy poszczególnymi adnotacjami"><span class="dashicons dashicons-admin-links"></span></a>Różnice pomiędzy poszczególnymi adnotacjami</h2>
<p>W tym podrozdziale omówimy każdą z wcześniej wspomnianych adnotacji.</p>
<ul>
<li><strong>@Component</strong> &#8211; to ogólny stereotyp dowolnego komponentu zarządzanego przez Springa. Jeżeli bean, który chcesz oznaczyć nie pasuje do żadnej innej kategorii to ta adnotacja będzie odpowiednia.</li>
<li><strong>@Repository</strong> &#8211; stereotyp dla warstw persystencji. Jedną z zalet korzystania z tej adnotacji jest to, że ma ona włączone automatyczne tłumaczenie wyjątków. Wyjątki zgłaszane w klasach z adnotacją @Repository zostaną automatycznie przetłumaczone na podklasy DataAccessExeption Springa.</li>
<li><strong>@Service </strong>&#8211; stereotyp dla warstw usług. W klasach z tą adnotacją zawarta jest zazwyczaj logika biznesowa aplikacji.</li>
<li><strong>@Controller</strong> &#8211; stereotyp dla warstw prezentacji (Spring MVC). DispatcherServlet będzie szukał adnotacji @RequestMapping w klasach, które są opatrzone adnotacjami za pomocą @Controller, ale nie za pomocą @Component. Często spotkasz się też zapewne z bardzo podobną adnotacją <strong>@RestController</strong>, która jest właściwie tym samym ale dodatkowo dokłada adnotacje @ResponseBody oraz automatycznie konwertuje odpowiedzi do formatu JSON/XML.</li>
</ul>
<hr />
<h2>Podsumowanie</h2>
<p><a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/lightbulb/" rel="attachment wp-att-976" data-slb-active="1" data-slb-asset="1379905354" data-slb-internal="976"><img decoding="async" class="aligncenter wp-image-976 size-thumbnail lazyloaded" src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" alt="" width="150" height="150" data-src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" /></a></p>
<p>To wszystko jeżeli chodzi o adnotacje do wstrzykiwania zależności w Springu. Wszystkie z nich są używane do automatycznego wykrywania beanów Springowych i zasadniczo zapewniają tę samą funkcjonalność. Różnice pomiędzy poszczególnymi adnotacjami są minimalne ale istotne, np. @Controller czy @Repository. Jednak w przypadku adnotacji @Service oraz @Component, różnica polega tylko na semantyce.</p>
<p>Źródła:</p>
<ul>
<li><a href="https://javarevisited.blogspot.com/2017/11/difference-between-component-service.html#ixzz6P8aSoQeX"><strong>Difference between @Component, @Service, @Controller, and @Repository in Spring</strong></a></li>
<li><strong><a href="https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-stereotype-annotations">@Component and Further Stereotype Annotations</a></strong></li>
<li><strong><a href="https://stackoverflow.com/questions/6827752/whats-the-difference-between-component-repository-service-annotations-in">What&#8217;s the difference between @Component, @Repository &amp; @Service annotations in Spring?</a></strong></li>
</ul>
<hr />
<h3>Za tydzień</h3>
<p>Nowy rok :). A co za tym idzie pierwszy post w miesiącu, a więc <strong>krótkie podsumowanie miesiąca</strong>. Myślę, że zmieni się również format wypuszczania nowych artykułów w nowym roku, ale to już więcej opiszę za tydzień.</p>
<div id="wpd-post-rating" class="wpd-not-rated">
<div class="wpd-rating-wrap"></div>
</div>
<p>Artykuł <a href="https://www.bdabek.pl/%f0%9f%86%92-spring-zrozumiec-adnotacje-wstrzykiwania-zaleznosci-%f0%9f%91%8c/">🆒 Spring &#8211; Zrozumieć Adnotacje Wstrzykiwania Zależności 👌</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/%f0%9f%86%92-spring-zrozumiec-adnotacje-wstrzykiwania-zaleznosci-%f0%9f%91%8c/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>✔️ Spring Framework &#8211; Jak Bronić Się Przed Oddaniem Kontroli Frameworkowi? ⛔️⛔️</title>
		<link>https://www.bdabek.pl/spring-framework-jak-bronic-sie-przed-oddaniem-kontroli-frameworkowi/</link>
					<comments>https://www.bdabek.pl/spring-framework-jak-bronic-sie-przed-oddaniem-kontroli-frameworkowi/#respond</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Sat, 28 Nov 2020 11:00:46 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Spring]]></category>
		<category><![CDATA[Wzorce Projektowe]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=2032</guid>

					<description><![CDATA[<p>Spring Framework powstał jako alternatywa dla programowania aplikacji z użyciem Javy EE w 2002 roku. Dziś jest kompleksowym rozwiązaniem dla wielu innych problemów a jego znajomość wśród developerów Javy jest już standardem. Cześć  Spring sprawia, że programowanie w Javie jest szybsze, łatwiejsze i bezpieczniejsze dla każdego. Spring skupia się na szybkości, prostocie i produktywności, dzięki&#8230;&#160;<a href="https://www.bdabek.pl/spring-framework-jak-bronic-sie-przed-oddaniem-kontroli-frameworkowi/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">✔️ Spring Framework &#8211; Jak Bronić Się Przed Oddaniem Kontroli Frameworkowi? ⛔️⛔️</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/spring-framework-jak-bronic-sie-przed-oddaniem-kontroli-frameworkowi/">✔️ Spring Framework &#8211; Jak Bronić Się Przed Oddaniem Kontroli Frameworkowi? ⛔️⛔️</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><strong>Spring Framework</strong> powstał jako alternatywa dla programowania aplikacji z użyciem Javy EE w 2002 roku. Dziś jest kompleksowym rozwiązaniem dla wielu innych problemów a <strong>jego znajomość wśród developerów Javy jest już standardem</strong>.</p>
<hr />
<h3>Cześć <img decoding="async" class="emoji" role="img" draggable="false" src="https://s.w.org/images/core/emoji/12.0.0-1/svg/1f642.svg" alt="&#x1f642;" /></h3>
<blockquote><p>Spring sprawia, że programowanie w Javie jest szybsze, łatwiejsze i bezpieczniejsze dla każdego. Spring skupia się na szybkości, prostocie i produktywności, dzięki czemu stał się najpopularniejszym na świecie frameworkiem Java.<br />
<cite>spring.io</cite></p></blockquote>
<p>Cytat powyżej doskonale opisuje znaczenie Springa w dzisiejszym świecie (2020). Spring jest wszędzie &#8211; niezależnie od tego, czy chodzi o <a href="https://netflixtechblog.com/netflix-oss-and-spring-boot-coming-full-circle-4855947713a0" target="_blank" rel="noopener noreferrer">streaming telewizji</a>, <a href="https://tanzu.vmware.com/big-data/press-release/mercedes-benz-teams-with-pivotal-to-bring-connected-car-app-to-life" target="_blank" rel="noopener noreferrer">samochody z dostępem do internetu</a>, <a href="https://tech.target.com/2018/12/18/spring-feign.html" target="_blank" rel="noopener noreferrer">zakupy online</a>, czy też niezliczone inne innowacyjne rozwiązania. Dzięki swojej elastyczności, ilości projektów jakie rozwija (w sposób zadowalający programistów na całym świecie) oraz społeczeństwa (<em>community</em>) jakie zostało wokół niego stworzone, z pewnością można stwierdzić, że <strong>Spring Framework jest częścią obecnego świata</strong>.</p>
<p>Należy jednak pamiętać, że nadal <strong>jest to tylko framework a rynek bywa nieprzewidywalny</strong>. Co w przyadku, kiedy okaże się, że Spring jest już przeżytkiem? <strong>Czy będziesz musiał przepisać całą aplikację od zera tylko dlatego, że pozwoliłeś się mu uwięzić</strong>?</p>
<p>W dzisiejszym artykule:</p>
<ul>
<li><a href="#Elastyczność a kontrola"><strong>Elastyczność a kontrola</strong></a></li>
<li><a href="#Gdzie leży granica?"><strong>Gdzie leży granica?</strong></a></li>
<li><a href="#Technika obrony przed oddaniem władzy w ręce Springa"><strong>Technika obrony przed oddaniem władzy w ręce Springa</strong></a></li>
</ul>
<hr id="Elastyczność a kontrola" />
<h2><strong>Elastyczność a kontrola</strong></h2>
<p>Spring Boot, czyli jeden z podprojektów springa, który drastycznie poprawia produktywność. Pozwala na postawinie aplikacji od zera za pomocą dosłownie kilku kliknięć przy pomocy <a href="https://start.spring.io/" target="_blank" rel="noopener noreferrer">Spring Initializr</a>. W dobie, kiedy duży nacisk jako IT kładziemy na architekturę, gdzie każdy moduł ma konkretną odpowiedzialność (mikroserwisy), Spring Boot jest świetnym wyborem bo dostarcza nam przygotowany projekt, który musimy tylko odpowiednio zakodować.</p>
<p>Skupiam się szczególnie na projekcie Spring Boot&#8217;owym, ale <strong>sprawa zabetonowania kodu frameworkiem</strong> równomiernie dotyczy każdego innego projektu. Generalnie chodzi o komponenty, gdzie w dużej mierze polegamy na sercu Springa &#8211; IoC, AOP. Zyskujemy dzięki temu dużą elastyczność bo możemy szybko dostarczać funkcjonalności, które chce biznes, ale jednocześnie płacimy za to tym, że polegamy na mechanizmach frameworka.</p>
<p>Czy jest z tym jakiś problem? Dopóki wszystko działa to nie. Problem pojawia się gdy coś przestaje działać. Wtedy okazuje się, że z 10-osobowego zespołu, jedna&#8230; może dwie osoby, mniej lub więcej wiedzą co dzieje się pod spodem (dobrze jeżeli chociaż tyle osób się znajdzie) i umieją rozwiązać problem. <strong>To nie znaczy, że mamy wywalić wszystkie frameworki z naszego kodu i napisać je samemu</strong>. Efekt końcowy będzie taki sam. Osoby, które napiszą daną rzecz za jakiś czas są nieobecne &#8211; inny projekt / zmiana pracy / emerytura.</p>
<hr id="Gdzie leży granica?" />
<h2><strong>Gdzie leży granica?</strong></h2>
<p><strong>Niezaprzeczalnym faktem jest, że w znacznej większości przyapadków nie będziesz przepisywać funkcjonalności, które dostarczają Ci zewnętrzni dostawcy</strong> (biblioteki / frameworki). Dobrze byłoby wiedzieć co dzieje się pod spodem danego komponentu, jakie są kompromisy jego użycią &#8211; co zyskujemy a co tracimy. Niestety, znajomość, co dzieje się pod spodem, często nie jest adekwatna. Żeby nie teoryzować już za wiele i przejść do konkretów, to moim zdaniem <strong>granice wyznacza czas</strong>.</p>
<p>Załóżmy, że na projekcie używasz Spring Boota i działasz w branży księgowości. Dostałeś zadanie aby dodać nową funkcjonalność obsługi subskrypcji (użytkownicy co miesiąc płacą za usługę księgowości). Dla uproszczenia przyjmimy, że taka subskrypcja może być utworzona (użytkownik dołącza do planu księgowości), wyszukiwana (np. przez adminów systemu), przedłużana oraz może nastąpić rezygnacja przez użytkownika.</p>
<p>Na pierwszy rzut oka, typowy CRUD, ale tak nie jest. Nie będziemy wchodzić w domenę bo to nie jest temat tego artykułu, ale pozwól, że przedstawię Ci kilka argumentów utrudniających domenę:</p>
<ul>
<li>co z użytkownikami, którzy są stałymi klientami (zniżki / rabaty)</li>
<li>użytkownicy, którzy wykupuja plan na kilka lat z góry (zniżki / rabaty)</li>
<li>różne plany subskrypcji (np. najdroższy plan posiada support dostępny 24/7)</li>
<li>subskrypcje w wersji trial (14/30 dni)</li>
</ul>
<p>Znalazłoby się jeszcze kilka(naście) innych utrudnień, ale nie do tego zmierzamy. <strong>Jak byś to zaczął opędzlowywać w springu?</strong> @RestController, @Service, @Component nad każdą z klas, później dla metod, w których może wystąpić rollback @Transactional i jazda? Po miesiącu kodowania okazuje się, że Twój kod jest i działa. Tylko problem, że jest on w 100% zależny od Springa i jego mechanizmów.</p>
<p>Czy jest złoty środek, który pomoże w walce o niezależność kodu?</p>
<hr id="Technika obrony przed oddaniem władzy w ręce Springa" />
<h2><strong>Technika obrony przed oddaniem władzy w ręce Springa</strong></h2>
<p>Skoro znamy już problem i wiemy, że Spring Framework daje nam dużo benefitów ale jednocześnie częściowo uniezależnia nas od siebie jako dostawcy, to jak możemy się tego ustrzec? Mam zarówno dobrą jak i złą wiadomość. Zacznijmy od złej &#8211; <strong>nie da się tego ustrzec.</strong> Dobra natomaist jest taka, że możemy to załagodzić.</p>
<p>Dlaczego nie możemy się ustrzec? Używając Springa w naszych aplikacjach zapewne będziemy chcieli skorzystać z jego głównych zalet &#8211; kontenera IoC czy też mechanizmu AOP (<em>Aspect Oriented Programming</em>). Mechanizmy wokół kontenera IoC są odpowiedzialne za inicjalizację, konfigurowanie i składanie obiektów (beanów), a sam kontener zarządza ich cyklem życia co znacznie ułatwia programowanie. Natomiast, jeżeli chodzi o AOP &#8211; jest to mechanizm wykorzystywany chociażby przy <a href="https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/" target="_blank" rel="noopener noreferrer">transakcjach</a>, logowaniu, obsłudze wyjątków czy też kwestiach bezpieczeństwa (<em>security</em>).</p>
<h4>To jak załagodzić standardowe flow?</h4>
<p>Do tego celu przyda nam się:</p>
<ul>
<li>umiejętność tworzenia konfiguracji i beanów samodzielnie,</li>
<li>wiedza jak działa wzorzec projektowy fasada.</li>
</ul>
<p>I tyle. Te dwie rzeczy pomogą nam częściowo uwolnić się od zależności frameworka. <strong>Lecimy z przykładem wcześniej wspomnianych subskrypcji</strong>.</p>
<p>Na samym początku trzeba zdefiniować fasadę, która przykrywa wszystkie istotne akcje biznesowe (utworzenie, wyszukanie, przedłużenie, rezygnację):</p><pre class="crayon-plain-tag">public class CompanySubscriptionFacade {

	private final CreateNewCompanySubscriptionService createNewCompanySubscriptionService;
	private final UnsubscriptionService unsubscribeFromSubscriptionService;
	private final CompanySubscriptionRepository companySubscriptionRepository;

	CompanySubscriptionFacade(CreateNewCompanySubscriptionService createNewCompanySubscriptionService,
							  UnsubscriptionService unsubscribeFromSubscriptionService,
							  CompanySubscriptionRepository companySubscriptionRepository) {
		this.createNewCompanySubscriptionService = createNewCompanySubscriptionService;
		this.unsubscribeFromSubscriptionService = unsubscribeFromSubscriptionService;
		this.companySubscriptionRepository = companySubscriptionRepository;
	}

	public Result createCompanySubscription(UUID subscriberId) {
		return createNewCompanySubscriptionService.create(subscriberId);
	}

	public CompanySubscription update(CompanySubscription sub) {
		return companySubscriptionRepository.save(sub);
	}

	public Result unsubscribe(SubscriberId subscriber, SubscriptionId subscription) {
		return unsubscribeFromSubscriptionService.unsub(subscriber, subscription);
	}

	public Optional&lt;CompanySubscription&gt; findSubscription(SubscriptionId subscriberId) {
		return companySubscriptionRepository.findBy(subscriberId);
	}
}</pre><p>Jest to czysta klasa Javowa, podobnie zresztą jak CreateNewCompanySubscriptionService oraz UnsubscriptionService (z perspektywy kodu Javowego przed konfiguracją, która za chwilę nastąpi). Teraz czas na samodzielną konfigurację:</p><pre class="crayon-plain-tag">@Configuration
public class CompanySubscriptionConfiguration {

	/**
	 * wykorzystywane w testach
	 */
	public CompanySubscriptionFacade companySubscriptionFacade() {
		InMemoryCompanySubscriptionRepository companySubscriptionRepository = new InMemoryCompanySubscriptionRepository();

		return companySubscriptionFacade(
				createNewCompanySubscriptionService(companySubscriptionRepository),
				enrollToCompanySubscription(companySubscriptionRepository, new NoOpDomainEventPublisher()),
				companySubscriptionRepository);
	}

	@Bean
	CompanySubscriptionFacade companySubscriptionFacade(CreateNewCompanySubscriptionService createNewCompanySubscriptionService,
														UnsubscriptionService unsubscriptionService,
														CompanySubscriptionRepository companySubscriptionRepository) {
		return new CompanySubscriptionFacade(createNewCompanySubscriptionService, unsubscriptionService, companySubscriptionRepository);
	}

	@Bean
	CompanySubscriptionRepository companySubscriptionRepository() {
		return new InMemoryCompanySubscriptionRepository();
	}

	@Bean
	UnsubscriptionService unsubscriptionService(CompanySubscriptionRepository companySubscriptionRepository,
													  DomainEventPublisher domainEventPublisher) {
		return new UnsubscriptionService(companySubscriptionRepository, domainEventPublisher);
	}

	@Bean
	CreateNewCompanySubscriptionService createNewCompanySubscriptionService(CompanySubscriptionRepository companySubscriptionRepository) {
		return new CreateNewCompanySubscriptionService(companySubscriptionRepository);
	}
}</pre><p>Klasa konfiguracyjna natomiast jest właśnie tą klasą, która odpowiada za utworzenie beanów. Sama posiada adnotację @Configuration oraz <strong>jest odpowiedzialna za prawidłowe powiązanie zależności</strong>.</p>
<p>Jeżeli chcesz dodać wsparcie dla transakcji / aspektów, które wykorzystują mechanizmy Springa to nie ma z tym najmniejszego problemu. Wystarczy że dodasz nowy @Aspect dla nowego aspektu, a w przypadku transakcji @Transactional na odpowiednim beanie lub jednej z metod. Posiadasz nadal pełne wsparcie mechanizmów Springa a jednocześnie nie betonujesz kodu na wymianę na inny framework. Będzie się to wiązało z przepisaniem konfiguracji (i oczywiście wsparcia dla ewentualnie napisanych aspektów / transakcji przez owy framework).</p>
<hr />
<h2>Podsumowanie</h2>
<p><a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/lightbulb/" rel="attachment wp-att-976" data-slb-active="1" data-slb-asset="1379905354" data-slb-internal="976"><img decoding="async" class="aligncenter wp-image-976 size-thumbnail lazyloaded" src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" alt="" width="150" height="150" data-src="https://cdn.shortpixel.ai/client/to_webp,q_glossy,ret_img,w_150,h_150/https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-150x150.jpg" /></a></p>
<p>Koncept, który tu przedstawiłem jest poniekąd inspirowany podejściem jakie może być spotkane w <a href="https://www.bdabek.pl/architektura-hexagonalna/" target="_blank" rel="noopener noreferrer">architekturze hexagonalnej</a>. Jeżeli chciałbyś dowiedzieć się więcej na ten temat to w źródłach zostawiam <a href="https://youtu.be/ILBX9fa9aJo" target="_blank" rel="noopener noreferrer">link</a> do świetnej prezentacji Jakuba Nabrdalika z warszawskiego JUGA oraz dodatkowo takie podejście jest przedstawione w bardzo dobrym kursie <a href="https://droganowoczesnegoarchitekta.pl/" target="_blank" rel="noopener noreferrer">DNA</a> (tylko drogim).</p>
<p>Co do samego podejścia. Plusy? Sami kontrolujemy tworzenie beanów, więc doskonale wiemy, co jest tworzone i jakie są zależności. Przy klasach z większą ilością zależności <strong>szybciej dostrzegamy problemy z kodem </strong>bo sami musimy zarządzać zależnościami. <strong>Minusem natomiast jest to, że musimy wykonać więcej pracy.</strong> Jeżeli wszystkie klasy w naszym projekcie są bean&#8217;ami (najczęściej występuje to przy wykorzystaniu <a href="https://www.bdabek.pl/architektura-warstwowa-zlo-czy-dobro/" target="_blank" rel="noopener noreferrer">architektury warstwowej</a>), to prawdopodobnie lepiej już oddać władze w ręce Springa i niech się dzieje co się ma dziać.</p>
<p>Źródła:</p>
<ul>
<li><strong><a href="https://spring.io/" target="_blank" rel="noopener noreferrer">Spring</a></strong></li>
<li><strong><a href="https://youtu.be/ILBX9fa9aJo" target="_blank" rel="noopener noreferrer">WJUG #211 &#8211; [PL] Modularity and hexagonal architecture in real life: Jakub Nabrdalik</a></strong></li>
</ul>
<div id="wpd-post-rating" class="wpd-not-rated">
<div class="wpd-rating-wrap"></div>
</div>
<p>Artykuł <a href="https://www.bdabek.pl/spring-framework-jak-bronic-sie-przed-oddaniem-kontroli-frameworkowi/">✔️ Spring Framework &#8211; Jak Bronić Się Przed Oddaniem Kontroli Frameworkowi? ⛔️⛔️</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/spring-framework-jak-bronic-sie-przed-oddaniem-kontroli-frameworkowi/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Jak działa adnotacja @Transactional w Springu</title>
		<link>https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/</link>
					<comments>https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/#comments</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Sat, 20 Jun 2020 10:00:21 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Spring]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=1029</guid>

					<description><![CDATA[<p>Użycie adnotacji @Transactional stało się na tyle powszechne, że często nie wiemy, po co to robimy. Transakcje w Springu są dostarczone domyślnie i jako użytkownicy frameworka nie martwimy się jak działają pod spodem. Zdarza się jednak, że niewiedza działa na naszą niekorzyść i nie inaczej jest w tym przypadku. Transakcje są czymś niewidocznym. Niby wiemy&#8230;&#160;<a href="https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">Jak działa adnotacja @Transactional w Springu</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/">Jak działa adnotacja @Transactional w Springu</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Użycie adnotacji @Transactional stało się na tyle powszechne, że często nie wiemy, po co to robimy. Transakcje w Springu są dostarczone domyślnie i jako użytkownicy frameworka nie martwimy się jak działają pod spodem. Zdarza się jednak, że niewiedza działa na naszą niekorzyść i nie inaczej jest w tym przypadku. Transakcje są <span style="color: #ff6600;"><strong>czymś niewidocznym</strong></span>. Niby wiemy jak to działa, lub powinno działać, ale mimo wszystko gdzieś tam pod spodem dzieje się coś nieznanego. W tym artykule przybliżymy i odkryjemy to nieznane.</p>
<div id="comment668" class="partial-collapse collapse" aria-expanded="false">
<div class="collapse-content">
<p>W dzisiejszym artykule:</p>
<ul>
<li><strong><a href="#@Transactional w Springu">@Transactional w Springu</a></strong></li>
<li><strong><a href="#Wyjątki w transakcjach">Wyjątki w transakcjach</a></strong></li>
<li><strong><a href="#Propagacja transakcji">Propagacja transakcji</a></strong></li>
</ul>
<hr id="@Transactional w Springu" />
<h2><span style="color: #ff6600;">1. @Transactional w Springu</span></h2>
<p>Transakcje w springu można uruchomić używając adnotacji <span style="color: #ff6600;"><strong>@Transactional </strong></span>na metodzie lub klasie. Kiedy metoda oznaczona jako transakcyjna zostaje wywołana, Spring przechwytuje wywołanie i na naszą metodę <span style="color: #ff6600;"><strong>nakłada proxy</strong></span> (*lub manipuluje naszym kodem bajtowym, jeżeli zmieniliśmy domyślny proxy mode dla springa). Proxy uruchamia <span style="color: #ff6600;"><strong>TransactionInterceptor</strong></span>, który zarządza transakcją. a następnie w klasie <span style="color: #ff6600;"><strong>TransactionAspectSupport</strong> </span>(klasa rodzic dla <em>TransactionInterceptor</em>), wywoływana jest docelowa metoda biznesowa. Żeby lepiej to zobrazować posłużę się obrazkiem z <strong><a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#tx-decl-explained" target="_blank" rel="noopener noreferrer">dokumentacji springa</a></strong>.</p>
<p><a href="https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/tx/" rel="attachment wp-att-1190"><img decoding="async" class="aligncenter size-full wp-image-1190" src="https://www.bdabek.pl/wp-content/uploads/2020/06/tx.png" alt="" width="600" height="362" srcset="https://www.bdabek.pl/wp-content/uploads/2020/06/tx.png 600w, https://www.bdabek.pl/wp-content/uploads/2020/06/tx-300x181.png 300w" sizes="(max-width: 600px) 100vw, 600px" /></a></p>
<p>Warto wiedzieć, że samo nałożenie adnotacji <em>@Transactional</em> na metodę nie jest wystarczające. Oprócz tego należy spełnić jeszcze 2 warunki:</p>
<ul>
<li>klasa, w której znajduje się metoda musi być <span style="color: #ff6600;"><strong>bean&#8217;em springowym</strong></span>,</li>
<li>metoda, na której znajduje się adnotacja <strong><span style="color: #ff6600;">musi być publiczna</span> </strong>(przy założeniu, że używasz domyślnego proxy mode),</li>
<li>metoda oznaczona jako @Transactional <span style="color: #ff6600;"><strong>musi być wołana z innego beana springowego</strong></span>.</li>
</ul>
<hr id="Wyjątki w transakcjach" />
<h2><span style="color: #ff6600;">2. Wyjątki w transakcjach</span></h2>
<p>Wyobraź sobie taki scenariusz. Masz jakiś serwis, w którym zapisujesz zadanie do bazy danych. Twój serwis potrafi jednak wyrzucić jakiś <em>checked exception</em>. Zapisze zadanie do bazy czy nie?</p><pre class="crayon-plain-tag">@Override
@Transactional
public void create(Task task) throws Exception {
    em.persist(task);
    // logika biznesowa która rzuca wyjątek
    throw new Exception();
}</pre><p>Z jednej strony widać że poleciał błąd i naturalnym by się wydawało że powinien był wykonać się <em>rollback</em>. Jednak, jak możesz domyślać się z kontekstu &#8211; rollback nie został wykonany. Zamiast tego akcja została zacommitowana do bazy i pozwól, że wyjaśnię co się stało i czy da radę temu jakoś zaradzić. Na początku zacytuję <strong><a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-attransactional-settings" target="_blank" rel="noopener noreferrer">dokumentację</a></strong>:</p>
<p><em>Any <code>RuntimeException</code> triggers rollback, and any checked <code>Exception</code> does not. </em></p>
<p>Dlaczego architekci Springa podjęli właśnie taką decyzję? Oczywiście jest to decyzja projektowa &#8211; cytuję dalej dokumentację z innego miejsca:</p>
<p><em>While the Spring default behavior for <code>declarative transaction management follows EJB convention</code>(roll back is automatic only on unchecked exceptions), it is often useful to customize this behavior.</em></p>
<p>Jeżeli zajrzymy w kod aspektu transakcji znajdujący się w TransactionAspectSupport, który odpowiedzialny jest za przechwytywanie wyjątków, dojdziemy do metody <span style="color: #ff6600;"><strong>completeTransactionAfterThrowing</strong></span>. Metoda ta ma w sobie sprawdzenie txInfo.transactionAttribute.rollbackOn(ex).</p><pre class="crayon-plain-tag">if (txInfo.transactionAttribute != null &amp;&amp; txInfo.transactionAttribute.rollbackOn(ex)) {
    try {
        txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
    }
    ...
}</pre><p>Doprowadza nas to do klasy <span style="color: #ff6600;"><strong>RuleBasedTransactionAttribute </strong></span>i jej metody <span style="color: #ff6600;"><strong>rollbackOn</strong></span>. Nie będę przeklejał tutaj całej metody, ale skupię się na fragmencie, który pomoże nam zrozumieć w jaki sposób możemy rozszerzyć <em>@Transactional</em> o rollbackowanie wyjątków sprawdzanych. Zauważ, że jest tu robiona iteracja na <span style="color: #ff6600;"><strong>this.rollbackRules</strong></span>. I to jest właśnie klucz.</p><pre class="crayon-plain-tag">```
if (this.rollbackRules != null) {
    for (RollbackRuleAttribute rule : this.rollbackRules) {
        int depth = rule.getDepth(ex);
        if (depth &gt;= 0 &amp;&amp; depth &lt; deepest) {
            deepest = depth;
            winner = rule;
        }
    }
}
```</pre><p>Używając adnotacji <em>@Transactional</em> możemy do niej przekazać różne parametry, między innymi parametr <span style="color: #ff6600;"><strong>rollbackFor</strong></span>, w którym definijemy klasy dziedziczące po Throwable, jakie mają być brane pod uwagę przy rollbackowaniu. Oczywiście dotyczy się to wyjątków przechwytywanych (<em>checked exceptions</em>). Więcej info w dokumentacji &#8211; <strong><a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-attransactional-settings" target="_blank" rel="noopener noreferrer">@Transactional Settings</a></strong>.</p>
<hr id="Propagacja transakcji" />
<h2><span style="color: #ff6600;">3. Propagacja transakcji</span></h2>
<p>Jest ważne aby wiedzieć, jak będą zachowywały się transakcje w naszym systemie, gdy mamy kilka wywołań metod a na każdej z nich adnotację <em>@Transactional</em>. Dodatkowo, dosyć często, pytanie o to, co się dzieje z transakcją jest zadawane na <a href="https://www.bdabek.pl/tag/rekrutacja/" target="_blank" rel="noopener"><span style="color: #ff6600;"><strong>rozmowach rekrutacyjnych</strong></span></a>.</p>
<p>No to spójrzmy jakie <strong><a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Propagation.html" target="_blank" rel="noopener noreferrer">typy propagacji są dostępne</a></strong> na adnotacji <em>@Transactional</em></p><pre class="crayon-plain-tag">public enum Propagation {
    REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
    SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
    MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
    REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
    NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
    NEVER(TransactionDefinition.PROPAGATION_NEVER),
    NESTED(TransactionDefinition.PROPAGATION_NESTED);
    ...
}</pre><p></p>
<h3><span style="color: #ff6600;">3.1. <span style="text-decoration: underline;">REQUIRED</span></span></h3>
<p>Jest do domyślny poziom propagacji. Spring wchodząc do metody oznaczonej adnotacją <em>@Transactional</em> sprawdza czy istnieje aktywna transakcja i jeżeli nie, to tworzy nową. W przypadku, gdy transakcja już istniała, logika metody jest aplikowana do istniejącej transakcji.</p>
<p><a href="https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/tx_prop_required/" rel="attachment wp-att-1202"><img decoding="async" class="aligncenter size-full wp-image-1202" src="https://www.bdabek.pl/wp-content/uploads/2020/06/tx_prop_required.png" alt="" width="800" height="341" srcset="https://www.bdabek.pl/wp-content/uploads/2020/06/tx_prop_required.png 800w, https://www.bdabek.pl/wp-content/uploads/2020/06/tx_prop_required-300x128.png 300w, https://www.bdabek.pl/wp-content/uploads/2020/06/tx_prop_required-768x327.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></a></p><pre class="crayon-plain-tag">// nie stosuj w taki sposób
@Transactional(propagation = Propagation.REQUIRED)
public void requiredExample(String user) { 
    // ... 
}

// preferowane użycie - Propagation.REQUIRED jest ustawiany domyślnie
@Transactional
public void requiredExample(String user) { 
    // ... 
}</pre><p>Pseudokod logiki aplikującej REQUIRED</p><pre class="crayon-plain-tag">if (isExistingTransaction()) {
    if (isValidateExistingTransaction()) {
        validateExisitingAndThrowExceptionIfNotValid();
    }
    return existing;
}
return createNewTransaction();</pre><p></p>
<h3><span style="color: #ff6600;">3.2. <span style="text-decoration: underline;">SUPPORTS</span></span></h3>
<p>Ten typ propagacji sprawdza czy istnieje transakcja i jeżeli tak, to jej używa. W przeciwnym razie metoda jest wykonywana bez użycia transakcji.</p><pre class="crayon-plain-tag">@Transactional(propagation = Propagation.SUPPORTS)
public void supportsExample(String user) { 
    // ... 
}</pre><p>Pseudokod:</p><pre class="crayon-plain-tag">if (isExistingTransaction()) {
    if (isValidateExistingTransaction()) {
        validateExisitingAndThrowExceptionIfNotValid();
    }
    return existing;
}
return emptyTransaction;</pre><p></p>
<h3><span style="color: #ff6600;">3.3. <span style="text-decoration: underline;">MANDATORY</span></span></h3>
<p>Szuka istniejącej transakcji i jej używa. W przypadku, gdy nie może znaleźć istniejącej transakcji wyrzuca wyjątek.</p><pre class="crayon-plain-tag">@Transactional(propagation = Propagation.MANDATORY)
public void mandatoryExample(String user) { 
    // ... 
}</pre><p>Pseudokod:</p><pre class="crayon-plain-tag">if (isExistingTransaction()) {
    if (isValidateExistingTransaction()) {
        validateExisitingAndThrowExceptionIfNotValid();
    }
    return existing;
}
throw IllegalTransactionStateException;</pre><p></p>
<h3><span style="color: #ff6600;">3.4. <span style="text-decoration: underline;">REQUIRES_NEW</span></span></h3>
<p>Zawsze powstaje nowa transakcja. W przypadku, gdy wcześniej jakaś transakcja była już otwarta, zostaje ona wstrzymana.</p><pre class="crayon-plain-tag">@Transactional(propagation = Propagation.REQUIRES_NEW)
public void requiresNewExample(String user) { 
    // ... 
}</pre><p>Pseudokod:</p><pre class="crayon-plain-tag">if (isExistingTransaction()) {
    suspend(existing);
    try {
        return createNewTransaction();
    } catch (exception) {
        resumeAfterBeginException();
        throw exception;
    }
}
return createNewTransaction();</pre><p>W taki sposób możesz to sobie zilustrować.<a href="https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/tx_prop_requires_new/" rel="attachment wp-att-1205"><br />
<img decoding="async" class="aligncenter size-full wp-image-1205" src="https://www.bdabek.pl/wp-content/uploads/2020/06/tx_prop_requires_new.png" alt="" width="800" height="276" srcset="https://www.bdabek.pl/wp-content/uploads/2020/06/tx_prop_requires_new.png 800w, https://www.bdabek.pl/wp-content/uploads/2020/06/tx_prop_requires_new-300x104.png 300w, https://www.bdabek.pl/wp-content/uploads/2020/06/tx_prop_requires_new-768x265.png 768w" sizes="(max-width: 800px) 100vw, 800px" /></a></p>
<h3><span style="color: #ff6600;">3.5. <span style="text-decoration: underline;">NOT_SUPPORTED</span></span></h3>
<p>Sprawdza, czy istnieje transakcja i jeżeli znajduje istniejącą, to ją wstrzymuje. Logika biznesowa dalej wykonywana jest już bez użycia transakcji.</p><pre class="crayon-plain-tag">@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void notSupportedExample(String user) { 
    // ... 
}</pre><p>Pseudokod:</p><pre class="crayon-plain-tag">if (isExistingTransaction()) {
    suspend(existing);
}
return continueWithBusinessLogic();</pre><p></p>
<h3><span style="color: #ff6600;">3.6. <span style="text-decoration: underline;">NEVER</span></span></h3>
<p>Wykonuje metodę bez użycia transakcji. W przypadku gdy transakcja istniała, wyrzcany jest wyjątek.</p><pre class="crayon-plain-tag">@Transactional(propagation = Propagation.NEVER)
public void neverExample(String user) { 
    // ... 
}</pre><p>Pseudokod:</p><pre class="crayon-plain-tag">if (isExistingTransaction()) {
    throw IllegalTransactionStateException;
}
return emptyTransaction;</pre><p></p>
<h3><span style="color: #ff6600;">3.7. <span style="text-decoration: underline;">NESTED</span></span></h3>
<p>Sprawdzane jest czy istnieje transakcja &#8211; jeżeli tak, to oznacza ją jako savepoint. Tzn. jeżeli logika biznesowa wyrzuci wyjątek to rollback przywróci nas do tego savepointa. Jeżeli transakcja nie istniała, to propagacja zachowuje się tak samo jak w przypadku <em>REQUIRED</em>.</p><pre class="crayon-plain-tag">@Transactional(propagation = Propagation.NESTED)
public void nestedExample(String user) { 
    // ... 
}</pre><p>Stety, niestety &#8211; opcja ta wymaga wsparcia savepointów i <span style="color: #ff6600;"><strong>działa tylko dla połączeń JDBC</strong></span>. Zatem, jeżeli używasz hibernate&#8217;a to przy próbie wykorzystania tego poziomu propagacji dostaniesz wyjątek:</p><pre class="crayon-plain-tag">org.springframework.transaction.NestedTransactionNotSupportedException: JpaDialect does not support savepoints - check your JPA provider's capabilities</pre><p></p>
<hr />
<h2><span style="color: #ff6600;">Podsumowanie</span></h2>
<p>Moim zdaniem każdy świadomy programista powinien przyswoić wiedzę o tym, jak działają transakcje. Developerzy nie znający podstaw będą kombinowali jak koń pod górkę robiąc dziwne obejścia, a wystarczyłoby <span style="color: #ff6600;"><strong>odpowiednio użyć poziomów transakcji</strong></span>. Mam nadzieję, że ten artykuł pomógł Ci w zrozumieniu jak działa adnotacja @Transactional w Springu oraz jak działają transakcje same w sobie.</p>
<p>Zostawiam Ci 2 źródła z których sam korzystałem pisząc ten artkuł, jeżeli chcesz wejść jeszcze głębiej w temat transakcji:</p>
<ul>
<li><strong><a href="https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction" target="_blank" rel="noopener noreferrer">Transaction Management</a></strong></li>
<li><strong><a href="https://www.baeldung.com/spring-transactional-propagation-isolation" target="_blank" rel="noopener noreferrer">Transaction Propagation and Isolation in Spring @Transactional</a></strong></li>
</ul>
</div>
</div>
<p>Artykuł <a href="https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/">Jak działa adnotacja @Transactional w Springu</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/jak-dziala-adnotacja-transactional-w-springu/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Co się dzieje gdy nie ma osoby odpowiedzialnej? Historia Z Projektu</title>
		<link>https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/</link>
					<comments>https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/#respond</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Sat, 09 May 2020 10:00:34 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Spring]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=949</guid>

					<description><![CDATA[<p>Logi dla dewelopera są źródłem informacji o tym co dzieje się w systemie podczas jego działania. Nieodpowiednie ich ustawienie może powodować w najlepszym przypadku lekką nieczytelność, w najgorszym natomiast &#8211; ukryte błędy które wychodzą dopiero na produkcji. Cześć! 🙂 W dzisiejszym artykule: Opowiem Ci historię o tym jak brak osoby odpowiedzialnej zabija odpowiedzialność zespołu Konfiguracja&#8230;&#160;<a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">Co się dzieje gdy nie ma osoby odpowiedzialnej? Historia Z Projektu</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/">Co się dzieje gdy nie ma osoby odpowiedzialnej? Historia Z Projektu</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Logi dla dewelopera są źródłem informacji o tym co dzieje się w systemie podczas jego działania. Nieodpowiednie ich ustawienie może powodować w najlepszym przypadku lekką <em>nieczytelność</em>, w najgorszym natomiast &#8211; ukryte błędy które wychodzą dopiero na produkcji.</p>
<hr />
<h2>Cześć! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></h2>
<p>W dzisiejszym artykule:</p>
<ul>
<li><strong><a href="#historia">Opowiem Ci historię o tym jak brak osoby odpowiedzialnej zabija odpowiedzialność zespołu</a></strong></li>
<li><strong><a href="#konfiguracja">Konfiguracja logback&#8217;a w spring boocie &#8211; na co zwrócić uwagę</a></strong></li>
<li><a href="#tipy"><strong>Kilka tipów odnośnie logów</strong></a></li>
</ul>
<hr id="historia" />
<h2>Historia z projektu&#8230;</h2>
<p><a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/historia-projektu/" rel="attachment wp-att-974"><img decoding="async" class="aligncenter size-full wp-image-974" src="https://www.bdabek.pl/wp-content/uploads/2020/05/historia-projektu.jpg" alt="historia projektu" width="1024" height="768" srcset="https://www.bdabek.pl/wp-content/uploads/2020/05/historia-projektu.jpg 1024w, https://www.bdabek.pl/wp-content/uploads/2020/05/historia-projektu-300x225.jpg 300w, https://www.bdabek.pl/wp-content/uploads/2020/05/historia-projektu-768x576.jpg 768w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></p>
<p>Ruszył mnie mail od przełożonego, który poprosił o wysłanie konfiguracji logbacka jaka miała być używany na produkcji. Mail był wysłany pod alias całego zespołu. Ja na projekcie jestem najkrócej więc uznałem, że nie będę dobrą osobą żeby na niego odpowiadać &#8211; <strong>błąd</strong>. Zachowałem go sobie i po kilku dniach do niego wróciłem.</p>
<p>Nigdy nie konfigurowałem logów na &#8211; nazwijmy to &#8211; większą skale i nie miałem w tym żadnego doświadczenia. Odpaliłem plik konfiguracyjny <em>logback.xml</em> i czytam. Czytam ustawienia (nie było ich dużo), czytam dokumentację logbacka + jakiś szybki tutorial o ustawieniach spring boot&#8217;a + logbacka.</p>
<p>Po zgłębieniu wiedzy teoretycznej (na ten moment wiedziałem czego powinienem się spodziewać po logach), zajrzałem do logów serwera. Logi na które patrzyłem nie raz (przecież na co dzień pracuję z tym systemem). Wywołuję akcję, która uruchamia jakiś log i widzę zduplikowany log. Niby jeden do drugiego podobny &#8211; wiadomość ta sama, stacktrace się zgadza. W jednym składnia jest kolorowana, wygląda to schludnie. W drugim natomiast odwołanie do konkretnej klasy i metody gdzie wywołany jest log, brak kolorowanej składni (nie jestem jakimś fanem tego żeby wszystko się świeciło, ale w ten sposób o wiele przyjemniej czyta się logi) + kilka innych drobnych różnic.</p>
<p>I może nie robiłbym z tego żadnego dramatu i nie pisał o tym na blogu. Ale taka konfiguracja utrzymywała się przez około półtorej roku!! Żeby nie było, konfiguracja nie dotyczyła środowiska produkcyjnego, ale wszystkich innych środowisk z których na co dzień korzystamy (+ nasze lokalne).</p>
<p>Nachodzi mnie pytanie &#8211; <strong>dlaczego tak się stało</strong>? I znajduję dwie odpowiedzi:</p>
<ol>
<li><strong>Brak osoby odpowiedzialnej za logi w aplikacji</strong></li>
<li><strong>Brak kompetencji w zespole</strong></li>
</ol>
<p><strong>Numer 1</strong>. Skoro nikt nie jest odpowiedzialny to dlaczego ja mam być? Po co mam poprawiać coś co jako tako działa? Takie podejście <strong>nie jest dobre</strong>! Jeżeli widzimy (a chyba przez ten cały czas ktoś musiał to zauważyć) to dlaczego nie chcemy wziąć za to odpowiedzialności? Kieruje nami <strong>strach</strong> (że nie umiemy) czy <strong>lenistwo</strong>?</p>
<p><strong>Numer 2</strong>. Tutaj mój wniosek postawiłem na zasadzie &#8211; gdyby ktoś miał kompetencje i znał temat, to by to naprawił. I też <strong>nie chcę nikogo winić</strong>, że tego nie zrobił &#8211; nie umieć, rzecz ludzka. Natomiast jeżeli chcemy aby projekt(y) nad którymi pracujemy nie zmieniały się w słynne projekty <em>legacy</em>, to o nie dbajmy! Użyję nawet takiego ogrodowego slangu, pielęgnujmy je.</p>
<p>W moim przypadku są to tylko jakieś <del>głupie</del> logi, ale od tego się zaczyna. Dziś logi, jutro testy, które ktoś gwarantuje, że dopisze później, a za rok szukamy nowego miejsca pracy bo projekt w jakim pracujemy to bajzel! Spuentuje to tak: <strong>jak sobie pościelisz tak się wyśpisz</strong> <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><em style="font-size: 12px;">Ps. jeżeli czyta to ktoś z mojego projektu, to nie bierzcie tego interpersonalnie. Chciałem podkreślić, że we wszystkim co robimy &#8211; starajmy się <strong>być solidni i dbajmy o to co rozwijamy</strong>.</em></p>
<hr id="konfiguracja" />
<h2>Konfiguracja logback&#8217;a w spring boocie</h2>
<p><a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/spring-boot-logback-logo/" rel="attachment wp-att-975"><img decoding="async" class="aligncenter size-full wp-image-975" src="https://www.bdabek.pl/wp-content/uploads/2020/05/spring-boot-logback-logo.png" alt="" width="500" height="193" srcset="https://www.bdabek.pl/wp-content/uploads/2020/05/spring-boot-logback-logo.png 500w, https://www.bdabek.pl/wp-content/uploads/2020/05/spring-boot-logback-logo-300x116.png 300w" sizes="(max-width: 500px) 100vw, 500px" /></a></p>
<p>Uff&#8230;. rozpisałem się w tej pierwszej myśli. Ten i pozostały akapit będą już <strong>sekcjami technicznymi</strong>. Ale<strong> nie napiszę</strong> Ci tutaj jak od 0 postawić projekt który będzie wyświetlał logi. Chcę tylko zwrócić uwagę na pewne rzeczy, które programiści robią często przez <strong>copy-paste</strong>, de&#8217;facto nie wiedząc co robią (w efekcie czego działa to jako tako).</p>
<p>W kilku projektach spotkałem się z taką implementacją logback-spring.xml &#8211; umiesz powiedzieć co jest nie tak?</p><pre class="crayon-plain-tag">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;configuration&gt;
    &lt;include resource="org/springframework/boot/logging/logback/base.xml"/&gt;
    &lt;appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"&gt;
        &lt;encoder&gt;
            &lt;pattern&gt;%d{yyyy-MM-dd HH:mm:ss.SSS}:${HOSTNAME} %highlight(%-5level) %thread --- %logger{36} : %msg%n
            &lt;/pattern&gt;
        &lt;/encoder&gt;
    &lt;/appender&gt;
    &lt;root level="INFO"&gt;
        &lt;appender-ref ref="STDOUT"/&gt;
    &lt;/root&gt;
&lt;/configuration&gt;</pre><p>Wiem, że to mała rzecz&#8230; ale zwróć uwagę na <em>include</em>. Jeżeli zajrzymy do środka to zauważymy, że dzięki jednemu include&#8217;owi <strong>dostajemy w gratisie 2 appendery</strong>. Console i file output &#8211; co prawda, ten drugi nie zadziała dopóki nie zdefiniujemy w <em>application.properties</em> <strong>logging.path</strong>. Btw. <strong><a href="https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-logging" target="_blank" rel="noopener noreferrer">tutaj</a></strong> znajdziesz wszystko co powinieneś wiedzieć o ustawieniach logów w spring boocie.</p>
<p>Wracając do ustawień logów wyżej. Przy aktualnym ustawieniu nasz output będzie zduplikowany! Taki właśnie problem mieliśmy u siebie na projekcie. Nikt nie pomyślał o tym, żeby sprawdzić co dostajemy zaciągając ustawienia z <em>base.xml</em>. A tam właśnie dostajemy już fajnie przygotowany <em>console appender</em>. Warto też dodać, że używając startera spring boota (a jak używamy spring boota, to startera pewnie też), jeżeli nie będziemy majsterkować niczego przy logach to <strong>z automatu dostajemy</strong> domyślnego logback&#8217;a z konfiguracją z <em>base.xml</em>.</p>
<blockquote><p>By default, if you use the “Starters”, Logback is used for logging.</p></blockquote>
<p>Warto też dodać, że jeżeli używamy logbacka to odpowiednio nazwijmy nasz plik konfiguracyjny. Do wyboru mamy 4 opcje: <code>logback-spring.xml</code>, <code>logback-spring.groovy</code>, <code>logback.xml</code>, lub<code>logback.groovy</code>. Jednak tutaj, znów z pomocą przychodzi nam dokumentacja:</p>
<table>
<tbody>
<tr>
<td class="content">When possible, we recommend that you use the <code>-spring</code> variants for your logging configuration (for example, <code>logback-spring.xml</code> rather than <code>logback.xml</code>). If you use standard configuration locations, Spring cannot completely control log initialization.</td>
</tr>
</tbody>
</table>
<hr id="tipy" />
<h2>Kilka tipów odnośnie logów</h2>
<p>Na koniec chcę każdemu devowi chcę podrzucić kilka porad, na co zwracać uwagę przy ustawieniach logback&#8217;a.<a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/lightbulb/" rel="attachment wp-att-976"><img decoding="async" class="aligncenter wp-image-976" src="https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb.jpg" alt="" width="535" height="307" srcset="https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb.jpg 700w, https://www.bdabek.pl/wp-content/uploads/2020/05/Lightbulb-300x172.jpg 300w" sizes="(max-width: 535px) 100vw, 535px" /></a></p>
<p>&nbsp;</p>
<ol>
<li>Na środowiskach nieprodukcyjnych <strong>&#8217;rozluźnij&#8217; logowanie</strong> &#8211; co mam na myśli? Większość z nas używa jakiegoś framework&#8217;a który będzie generował zapytania do bazy. Może się zdarzyć tak, że zamiast wykonać jedno zapytanie, wykonujemy ich 50 &#8211; bo złapaliśmy się na problem N+1. <strong>Nie mając odpowiednich logów, możemy się o tym nie dowiedzieć</strong>. W najlepszym przypadku spowolnimy nieco działanie systemu, w najgorszym <strong>zabijemy go wykonując miliony niepotrzebnych zapytań</strong>.</li>
<li>Jeżeli pracujesz ze spring-bootem i używasz logbacka, <strong>przygotuj profil logów dla środowiska produkcyjnego</strong>. Dzięki temu, nie będziesz zaskoczony gdy ktoś Cię o to poprosi. Pamiętaj tylko, że tutaj polityka logowania <strong>powinna być już odpowiednio zaostrzona</strong>. Do jakiego poziomu? To zależy &#8211; takiego, który nie będzie w żaden sposób inwazyjny dla aplikacji i jednocześnie będzie mógł dać Ci informację co się stało w przypadku błędów. Jeżeli podczas developmentu będziesz stosować się do punktu 1 to <strong>prawdopodobnie warn lub error</strong> dla większości środowisk będzie odpowiedni (wybadaj to wcześniej na jakimś środwisku testowym).</li>
<li><strong>Ucz innych</strong> &#8211; jeżeli masz wiedzę w tym zakresie, to <strong>edukuj swoich współpracowników</strong> i zachęcaj żeby sami potestowali różne ustawienia. <strong>Dziel się wiedzą na projektowych sharepointach czy confluencach</strong>. To sprawi, że nowe osoby, wchodzące na projekt będą miały referencję i będą znały standardy jakich używacie w projekcie. Dzięki wiedzy ogólnej, nikt nie będzie w stanie zrobić bałaganu cichaczem i czegoś pozmieniać. Świadomość zespołu zawsze wpłynie pozytywnie na projekt.</li>
</ol>
<hr />
<h2>Podsumowanie</h2>
<p>Celem tego wpisu było zasianie motywacji. Motywacji do tego żeby dbać o to co robimy. Większość z nas <strong>pracuje dla biznesów</strong>, które czerpią z tego zyski &#8211; a jeżeli biznesowi wiedzie się dobrze to i nam będzie dobrze. Po za aspektami czysto finansowymi uważam, że to, co każdy z nas wytwarza pokazuje charakter człowieka. Są ludzie, którzy zawsze będą robili wszystko na odwal, aby było &#8211; nie potępiam (taki charakter) ale też nie szanuję. Wracając do samych logów, korzystaj z gotowych rozwiązań (np. dostarczanych przez springa), korzystaj z dokumentacji i testuj. Jeżeli coś nie działa to to popraw. <strong>Weź odpowiedzialność na siebie &#8211; opłaci się</strong>.</p>
<hr />
<h2>Za Tydzień</h2>
<p>Weźmiemy na tapetę <a href="https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html" target="_blank" rel="noopener noreferrer">EntityManagera</a>. Będzie bardzo technicznie <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>Artykuł <a href="https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/">Co się dzieje gdy nie ma osoby odpowiedzialnej? Historia Z Projektu</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/spring-boot-i-logi-ustawienia-logbacka/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Przez rok nie działało na produkcji 😲!! Czyli @Cacheable i @Cacheput w Springu 🔥🔥</title>
		<link>https://www.bdabek.pl/przez-rok-nie-dzialalo-na-produkcji/</link>
					<comments>https://www.bdabek.pl/przez-rok-nie-dzialalo-na-produkcji/#comments</comments>
		
		<dc:creator><![CDATA[Bartosz Dąbek]]></dc:creator>
		<pubDate>Sat, 08 Feb 2020 07:59:12 +0000</pubDate>
				<category><![CDATA[Programowanie]]></category>
		<category><![CDATA[Spring]]></category>
		<guid isPermaLink="false">https://www.bdabek.pl/?p=221</guid>

					<description><![CDATA[<p>Cześć 🖐. Tytuł nie jest żadnym click baitem. To się wydarzyło🤦‍♂️&#8230; Przez rok mieliśmy zaimplementowaną funkcjonalność która nie działała i nikt tego nie zauważył! W styczniu tego roku (2020) do jednego z systemów jaki rozwijamy mieliśmy dodać nowy słownik który powinien być przechowywany w pamięci cache oraz dodatkowo odświeżać się gdy ktoś wgra jego nowszą wersję.&#8230;&#160;<a href="https://www.bdabek.pl/przez-rok-nie-dzialalo-na-produkcji/" rel="bookmark">Dowiedz się więcej &#187;<span class="screen-reader-text">Przez rok nie działało na produkcji 😲!! Czyli @Cacheable i @Cacheput w Springu 🔥🔥</span></a></p>
<p>Artykuł <a href="https://www.bdabek.pl/przez-rok-nie-dzialalo-na-produkcji/">Przez rok nie działało na produkcji 😲!! Czyli @Cacheable i @Cacheput w Springu 🔥🔥</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h3>Cześć <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f590.png" alt="🖐" class="wp-smiley" style="height: 1em; max-height: 1em;" />. Tytuł nie jest żadnym click baitem. To się wydarzyło<img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f926-200d-2642-fe0f.png" alt="🤦‍♂️" class="wp-smiley" style="height: 1em; max-height: 1em;" />&#8230; Przez rok mieliśmy zaimplementowaną funkcjonalność która nie działała i nikt tego nie zauważył!</h3>
<hr />
<p>W styczniu tego roku (2020) do jednego z systemów jaki rozwijamy mieliśmy dodać nowy słownik który powinien być przechowywany w pamięci cache oraz <strong>dodatkowo odświeżać się</strong> gdy ktoś wgra jego nowszą wersję. Zadanie wydawało się być proste &#8211; tym bardziej, że mieliśmy bardzo podobną implementację w naszym systemie od roku&#8230;</p>
<p>I tu zaczyna się cała historia.</p>
<p>Programista, który to implementował zaufał istniejącemu kodowi i postanowił przekopiować rozwiązanie zmieniając tylko poszczególne parametry. Takie podejście pewnie by przeszło ale&#8230; na całe szczęście pojawił się tester <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f575-1f3fb.png" alt="🕵🏻" class="wp-smiley" style="height: 1em; max-height: 1em;" />, który sprawdził to zadanie i jak się domyślasz po tytule &#8211; coś nie zadziałało. Słownik jak najbardziej zapisywał się w cache&#8217;u (dlatego programista nie wykrył błędu sam) &#8211; problem występował w momencie gdy była wgrywana nowa wersja słownika &#8211; cache się nie aktualizował.</p>
<p>&lt;Tu pojawia się rola mojej skromnej osoby &#8211; bo programista, który to implementował był niedostępny a zadanie wróciło z testów&gt;</p>
<p>Tak wyglądał kod klasy odpowiedzialnej za zarządzaniem cache&#8217;em dla tego słownika</p><pre class="crayon-plain-tag">@Service
public class SlownikUprawnienDodatkowychCache  {
    
    @CachePut("UprawnieniaDodatkowe")
    public Set&lt;Uprawnienia&gt; getSlownikToCache() {
        return this.getSlownikUprawnieniaDodatkowe();
    }

    @Cacheable("UprawnieniaDodatkowe")
    public Set&lt;Uprawnienia&gt; getSlownikFromCache() {
        return this.getSlownikUprawnieniaDodatkowe();
    }

    public void aktualizujCache() {
        getSlownikToCache();
    }

    private Set&lt;Uprawnienia&gt; getSlownikUprawnieniaDodatkowe() {
        // jakaś kosztowna operacja
    }
}</pre><p>Pierwszą myślą jaka mi przyszła do głowy było sprawdzić jak działają pozostałe słowniki &#8211; i znów jak możesz domyślać się z tytułu &#8211; <strong>odświeżanie innych słowników nie działało</strong>. Moje na tamten czas doświadczenie z cache&#8217;m w Springu było zerowe więc to od czego zacząłem były jakieś szybkie tutoriale. Po wstępnym zapoznaniu się &#8211; jak na prawdziwego developera przystało &#8211; opisałem problem w google i przeszukiwałem <em>podobne</em> problemy (stackoverflow :)). Nie umiałem znaleźć odpowiedzi na mój problem &#8211; choć jak się później okazało&#8230;</p>
<p><img decoding="async" class="size-full wp-image-300 aligncenter" src="https://www.bdabek.pl/wp-content/uploads/2020/02/spring-cache-stackoverflow.png" alt="" width="824" height="221" srcset="https://www.bdabek.pl/wp-content/uploads/2020/02/spring-cache-stackoverflow.png 824w, https://www.bdabek.pl/wp-content/uploads/2020/02/spring-cache-stackoverflow-300x80.png 300w, https://www.bdabek.pl/wp-content/uploads/2020/02/spring-cache-stackoverflow-768x206.png 768w" sizes="(max-width: 824px) 100vw, 824px" /></p>
<p>I to jeszcze jako najpopularniejszy problem dotyczący Spring cache. Ja jednak ze swoją pełną ignorancją sięgnąłem do <strong>dokumentacji.</strong> Dokumentacja w Springu jest napisana bardzo dobrze ale i tam odpowiedzi nie potrafiłem znaleźć &#8211; choć była &#8211; wystarczyło przeczytać na spokojnie ze zrozumieniem.</p>
<table border="0" summary="Note">
<tbody>
<tr>
<td align="left" valign="top">In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual caching at runtime even if the invoked method is marked with <code class="interfacename">@Cacheable</code> &#8211; considering using the aspectj mode in this case.</td>
</tr>
</tbody>
</table>
<p>Po dniu takiego przeszukiwania i eksperymentowania postanowiłem, że zajrzę do kodu zarządzającego cach&#8217;em w Springu. Zapiąłem się debugiem w paru miejscach i ogień <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f525.png" alt="🔥" class="wp-smiley" style="height: 1em; max-height: 1em;" />. Dodam jeszcze, że słowniki były ładowane przy starcie aplikacji a kod wyglądał mniejwięcej tak:</p><pre class="crayon-plain-tag">public class CacheConfig {
....
    @EventListener(ApplicationStartedEvent.class)
    public void addToCache() {
        ....
        log.info("START pobrania slownika uprawnien dodatkowych do cache");
        this.slownikUprawnienDodatkowych.getSlownikToCache();
        log.info("STOP pobrania slownika uprawnien dodatkowych do cache");
        ...
    }
}</pre><p>(I tu była kolejna wksazówka, którą tak bardzo przeoczyłem. Metoda <em>getSlownikToCache()</em> wywoływana jest bezpośrednio z docelowego obiektu)</p>
<p>Po starcie aplikacji słownik ładuje się do cache &#8211; wszystko wygląda dobrze, nowe obiekty są w pamięci, gdy się do nich odwołuję przychodzą z cache&#8217;a. Wgrywam nową wersję słownika, wciskam aktualizację cache i cisza <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f92b.png" alt="🤫" class="wp-smiley" style="height: 1em; max-height: 1em;" />.</p><pre class="crayon-plain-tag">public class CacheConfig {
   ...
    public void aktualizacjaSlownikaUprawnienDodatkowych() {
        slownikUprawnienDodatkowych.aktualizujCache();
    }
    ...
}</pre><p>Po stronie Springa nic się nie dzieje <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f92f.png" alt="🤯" class="wp-smiley" style="height: 1em; max-height: 1em;" />. Mechanim uaktualnienia cache się nie uruchamia. Po chwili zorientowałem się, że aktualizacja idzie przez metodę pośrednią <em>aktualizujCache()</em>. Na tamten moment nie wiedziałem jeszcze, że to jest przyczyną a próbowałem już wielu innych rzeczy &#8211; i prawdę mówiąc byłem nieco poirytowany. Tak czy siak zmieniłem wywołanie na coś takiego</p><pre class="crayon-plain-tag">public class CacheConfig {
....
    public void aktualizacjaSlownikaUprawnienDodatkowych() {
        slownikUprawnienDodatkowych.getSlownikToCache();
    }
....
}</pre><p>Nie miałem wielkich oczekiwań, że to zadziała &#8211; choć bardzo chciałem żeby zadziałało <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f604.png" alt="😄" class="wp-smiley" style="height: 1em; max-height: 1em;" />. Uruchamiam aktualizację w debugerze i <strong>JEST</strong>! Cache się zaktualizował ! Cieszyłem się troche jak dziecko. Po czasie połączyłem wszystkie fakty i nadrobiłem braki w przeglądnietej tylko wcześniej przeze mnie dokumentacji. Teraz wiem, że da się zrobić tak aby aktualizowanie działało przez metodę pośredniczącą. Natomiast dla naszego rozwiązania i prostoty nie było takiej potrzeby. Poprawiłem kod dla pozostałych słowników i przekazałem zadanie testerowi.</p>
<h3>Lekcje do wyciągnięcia na przyszłość:</h3>
<ul>
<li><strong>czytać uważniej dokumentacje / opis podobnych problemów</strong> &#8211; gdybym z uwagą przeczytał dokumentację lub wpis na stackoverflow (albo to i to), mógłbym zaoszczędzić sobie dzień pracy.</li>
<li><strong>głebiej analizować istniejący kod</strong> &#8211; tutaj problem polegał na tym, że sugerowałem się jak już to było rozwiązane. Inne słowniki też próbowały się odświeżać przez metodę pośrednią przez co całość nie działała. Gdybym skupił się na tym co działa (ładowanie do cache przy starcie aplikacji) i porównał z tym co mam &#8211; znów &#8211; mógłbym sobie zaoszczędzić czasu.</li>
<li><strong>nie ufać w 100% cudzemu kodu</strong> &#8211; chyba nie trzeba tego komentować. Ja zaufałem, że ktoś zrobił to dobrze a wcale tak nie było i koniec końców rezultat był taki, że przynajmniej nauczyłem się jak działa cache w Springu &#8211; więc dziękuje osobie która to implementowała <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></li>
</ul>
<p>Artykuł <a href="https://www.bdabek.pl/przez-rok-nie-dzialalo-na-produkcji/">Przez rok nie działało na produkcji 😲!! Czyli @Cacheable i @Cacheput w Springu 🔥🔥</a> pochodzi z serwisu <a href="https://www.bdabek.pl">bdabek.pl</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bdabek.pl/przez-rok-nie-dzialalo-na-produkcji/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
