{"id":3,"date":"2006-07-16T19:31:00","date_gmt":"2006-07-16T18:31:00","guid":{"rendered":"http:\/\/euve3303.vserver.de\/stefan\/blog\/?p=6"},"modified":"2011-12-02T20:36:32","modified_gmt":"2011-12-02T19:36:32","slug":"springs-aop-autoproxy-feature-mit-java-5-0-annotationen","status":"publish","type":"post","link":"https:\/\/cogito-ergo-blog.de\/blog\/2006\/07\/16\/springs-aop-autoproxy-feature-mit-java-5-0-annotationen\/","title":{"rendered":"Spring&#8217;s AOP Autoproxy Feature mit Java 5.0 Annotationen"},"content":{"rendered":"<h2>Autoproxing mit Spring <\/h2>\n<p>Das Applikation Framework Spring bringt ein sehr n\u00fctzliches Feature mit: Autoproxing. Damit lassen sich Spring Beans &#8211; also eigentlich jede POJO-Klasse &#8211; um Aspekte erweitern. Aspekte sind gem\u00e4ss AOP Belange eines Programms die sich quer zur eigentlichen Programmlogik erstecken (Cross-Cutting-Concerns). <\/p>\n<p>In der Aspektorientierten Programmierung kann man diese Aspekte getrennt vom Rest des Programms formulieren und erst die AOP Umgebung &quot;verwebt&quot; den Aspektcode mit dem eigentlichen Programmcode. Hier gibt es prinzipiell zwei unterschiedliche Vorgehensweisen 1. zur Compile-Time (w\u00e4hrend des Kompilierens) oder 2. zur Run-Time (w\u00e4hrend der Laufzeit). <\/p>\n<p>Der bekannteste Vertreter der 1. Variante ist sicher AspectJ, welches eine eigene Sprache formuliert und folglich auch einen eigenen Compiler mitbringt. Dieser Compiler sorgt f\u00fcr das Zusammenweben von Aspekten und restlichem Programmcode. Die Sprache liefert alle Mittel um Aspekte zu formulieren und dar\u00fcber hinaus festzulegen an welchen Stellen der Aspect-Code eingebunden werden muss (Definition von sogenannten Pointcuts). <\/p>\n<p>Beim Spring-Framework wird der Aspect-Code erst zur Laufzeit dem restlichen Programm hinzugef\u00fcgt. Wie kann man sich das vorstellen? Da Spring Bean-Instanzen immer \u00fcber die BeanFactory erzeugt werden, kann die Factory die erzeugten Instance beliebig ver\u00e4ndern, solange sie f\u00fcr die Applikation nur &quot;so aussehen&quot; wie eine Bean vom Type XY. Bei Beans die ein bestimmtes Interface implentieren, bedeutet das, das die erzeugte Instance eben immer noch diese Interface implementieren muss. Wird kein Interface implementiert, so wird eine abgeleitete Klasse mindestens die gleichen &quot;Public-Methods&quot; bieten, wie die Basis-Klasse. <\/p>\n<p><!--more--><\/p>\n<p>Mit Hilfe dieser Logik arbeitet das Proxy-Feature von Spring: Bei Klassen die ein Interface implentieren verwendet Spring sogenannte Dynamic-Proxies (seit JDK 1.4) ansonsten wird mit Hilfe der &quot;Code-Generating-Library&quot; CGLib dynamisch eine abgeleitete Klasse gebildet und diese instanziiert. <\/p>\n<p>Auf diese Weise kann Spring nun auf Wunsch jeden Methodenaufruf einrahmen (wrappen), um vor oder nach dem Methodenaufruf (oder beides) Aspektcode auszf\u00fchren. <\/p>\n<p>Damit man dieses Verhalten nun nich explizit in die BeanFactory bei allen Bean konfigurieren muss, kennt Spring das AutoProxy-Feature. Einmal aktiviert, wird bei jeder Bean automatisch \u00fcberpr\u00fcft, welche Methoden mit welchen Aspekten zu versehen sind. <\/p>\n<p>Dieser Zusammenhang wird nun nicht mit einer speziellen Sprache wie bei AspectJ festgelegt, sondern in nomalem Java &quot;ausprogrammiert&quot;. Man schreibt einen sogenannten &quot;Advisor&quot;, der das Interface <b>org.springframework.aop.PointcutAdvisor<\/b> implementiert. Sobald Spring nun einen potentiellen Kandidaten f\u00fcr das AutoProxing instanziieren soll, wird der Advisor der Reihe nach bei allen Methode gefragt, ob und mit welchem &quot;Advise&quot; die Methode versehen werden soll. <\/p>\n<p>Das Nutzen von Aspekten soll nun besonders einfach gestaltet werden in dem man Annotationen verwendet. \u00dcber Annotationen k\u00f6nnen Klassen oder Methoden (ja selbst Parameter) mit Metainformatonen versorgt werden, die mit Hilfe des neuen Reflection API von Java 5 auch zur Laufzeit abgefragt werden k\u00f6nnen. <\/p>\n<h2>Ein einfacher Advisor <\/h2>\n<p>Leider bin ich bei meinem ersten Ansatz mit einem SpringAdvisor auf Probleme gestossen: <\/p>\n<p>Solange es sich um Klassen handelte, die kein Interface implementierten und von daher mittels Code-Generation erweitert werden k\u00f6nnen, funktionierte noch alles wie erwartet. <\/p>\n<p>Ein Problem trat auf als eine Klasse mit Annotationen versehen wurde, die ein oder mehrere Interfaces implementierte. Wenn man die Calls an den Advisor mitprotokolliert, kann man sehn, dass f\u00fcr Methoden, die Teil des Interfaces sind, der Advisor &quot;zweimal&quot; aufgerufen wird: einmal f\u00fcr die konkrete Implementierung der Klasse, die Spring konkret instanziiert, einmal f\u00fcr die abstracte Interface-Methode. <\/p>\n<p>Ein solcher einfacher Advisor sieht so aus: <\/p>\n<blockquote style=\"border: 1px solid gray; font-family: courier new; font-size: 85%; background-color: rgb(238, 238, 238); overflow: auto; height: 200px;\"><p>\n<tt class=\"java\"><span class=\"java4\">package <\/span><span class=\"java10\">com.rinke.solutions.spring.test.aop;<\/p>\n<p><\/span><span class=\"java4\">import <\/span><span class=\"java10\">java.lang.annotation.Annotation;<br \/>\n<\/span><span class=\"java4\">import <\/span><span class=\"java10\">java.lang.reflect.Method;<\/p>\n<p><\/span><span class=\"java4\">import <\/span><span class=\"java10\">org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;<\/p>\n<p><\/span><span class=\"java14\">\/**<br \/>\n &#42; advisor that adds advice to a class od method, when a special annotation is present.<br \/>\n &#42; <\/span><span class=\"java11\">@author <\/span><span class=\"java14\">ster<br \/>\n &#42;\/<br \/>\n<\/span><span class=\"java4\">public class <\/span><span class=\"java10\">SimpleAnnotationSourceAdvisor <\/span><span class=\"java4\">extends <\/span><span class=\"java10\">StaticMethodMatcherPointcutAdvisor <\/span><span class=\"java8\">{<\/p>\n<p>&#xA0;&#xA0;&#xA0; <\/span><span class=\"java14\">\/** stores the annatation class to check.*\/<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">private <\/span><span class=\"java10\">Class&lt;? <\/span><span class=\"java4\">extends <\/span><span class=\"java10\">Annotation&gt; annotationToCheck;<br \/>\n&#xA0;&#xA0;&#xA0; <br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">public <\/span><span class=\"java9\">void <\/span><span class=\"java10\">setAnnotationToCheck<\/span><span class=\"java8\">(<\/span><span class=\"java10\">Class&lt;? <\/span><span class=\"java4\">extends <\/span><span class=\"java10\">Annotation&gt; annotationToCheck<\/span><span class=\"java8\">) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">this<\/span><span class=\"java10\">.annotationToCheck = annotationToCheck;<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">}<\/p>\n<p>&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">public <\/span><span class=\"java9\">boolean <\/span><span class=\"java10\">matches<\/span><span class=\"java8\">(<\/span><span class=\"java10\">Method method, Class clazz<\/span><span class=\"java8\">) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">return <\/span><span class=\"java10\">method.isAnnotationPresent<\/span><span class=\"java8\">(<\/span><span class=\"java10\">annotationToCheck<\/span><span class=\"java8\">)<\/span><span class=\"java10\">;<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">}<br \/>\n }<\/span><\/tt>\n<\/p><\/blockquote>\n<p>Es wird einfach nur gepr\u00fcft, ob bei der betroffenen Methode die &quot;annotationToCheck&quot; vorhanden ist. <\/p>\n<p>Wenn der Advisor nun &quot;den Fehler&quot; macht, den Advice nicht auch f\u00fcr die abstracte Methode des Interfaces zu setzen, dann wird der sp\u00e4tere Aufruf aus der Applikation, immer dann <i>ohne <\/i>den Advice ausgef\u00fchrt, wenn der Caller <i>nur<\/i> mit dem Interface arbeitet. <\/p>\n<p>Da der Advisor sich nach den Annotationen richtet, mit denen die Methode versehen ist, kann man dem dadurch begegnen, dass man auch die abstrakte Interface-Methode annotiert. Allerdings ist es oft gar nicht m\u00f6glich oder w\u00fcnschenswert, das Interface zu annotieren. Der Aspekt ist Teil der konkreten Implementierung und hat mit dem Interface nichts zu tun. <\/p>\n<p>Man kann dem aus dem Weg gehen, wenn man den Advisor etwas erweitert: <\/p>\n<blockquote style=\"border: 1px solid gray; font-family: courier new; font-size: 85%; background-color: rgb(238, 238, 238); overflow: auto; height: 300px;\"><p>\n<tt class=\"java\"><span class=\"java4\">package <\/span><span class=\"java10\">com.rinke.solutions.spring.test.aop;<\/p>\n<p><\/span><span class=\"java4\">import <\/span><span class=\"java10\">java.lang.annotation.Annotation;<br \/>\n<\/span><span class=\"java4\">import <\/span><span class=\"java10\">java.lang.reflect.Method;<br \/>\n<\/span><span class=\"java4\">import <\/span><span class=\"java10\">java.lang.reflect.Modifier;<\/p>\n<p><\/span><span class=\"java4\">import <\/span><span class=\"java10\">org.aopalliance.aop.Advice;<br \/>\n<\/span><span class=\"java4\">import <\/span><span class=\"java10\">org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;<\/p>\n<p><\/span><span class=\"java14\">\/**<br \/>\n &#42; advisor that adds advice to a class od method, when a special annotation is present.<br \/>\n &#42; <\/span><span class=\"java11\">@author <\/span><span class=\"java14\">ster<br \/>\n &#42;\/<br \/>\n<\/span><span class=\"java4\">public class <\/span><span class=\"java10\">AnnotationSourceAdvisor <\/span><span class=\"java4\">extends <\/span><span class=\"java10\">StaticMethodMatcherPointcutAdvisor <\/span><span class=\"java8\">{<\/p>\n<p>&#xA0;&#xA0;&#xA0; <\/span><span class=\"java14\">\/** stores the annatation class to check.*\/<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">private <\/span><span class=\"java10\">Class&lt;? <\/span><span class=\"java4\">extends <\/span><span class=\"java10\">Annotation&gt; annotationToCheck;<br \/>\n&#xA0;&#xA0;&#xA0; <br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java14\">\/**<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42; default ctor.<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42;\/<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">public <\/span><span class=\"java10\">AnnotationSourceAdvisor<\/span><span class=\"java8\">() {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">super<\/span><span class=\"java8\">()<\/span><span class=\"java10\">;<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">}<br \/>\n&#xA0;&#xA0;&#xA0; <br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java14\">\/**<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42; sets the advice<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42; <\/span><span class=\"java11\">@see <\/span><span class=\"java14\">org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor#setAdvice(org.aopalliance.aop.Advice)<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; *\/<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">public <\/span><span class=\"java9\">void <\/span><span class=\"java10\">setAdvice<\/span><span class=\"java8\">( <\/span><span class=\"java10\">Advice advice <\/span><span class=\"java8\">) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">super<\/span><span class=\"java10\">.setAdvice<\/span><span class=\"java8\">(<\/span><span class=\"java10\">advice<\/span><span class=\"java8\">)<\/span><span class=\"java10\">;<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">}<br \/>\n&#xA0;&#xA0;&#xA0; <br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java14\">\/**<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42; <\/span><span class=\"java11\">@param <\/span><span class=\"java14\">clazz the current class to check<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42; <\/span><span class=\"java11\">@param <\/span><span class=\"java14\">method the current method to check<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42; <\/span><span class=\"java11\">@return <\/span><span class=\"java14\">true, if the specified method has the annotation.<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42; <\/span><span class=\"java11\">@see <\/span><span class=\"java14\">org.springframework.aop.MethodMatcher#matches(java.lang.reflect.Method, java.lang.Class)<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42;\/<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">public <\/span><span class=\"java9\">boolean <\/span><span class=\"java10\">matches<\/span><span class=\"java8\">(<\/span><span class=\"java10\">Method method, Class clazz<\/span><span class=\"java8\">) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java3\">\/\/ this is tricky<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">if<\/span><span class=\"java8\">( <\/span><span class=\"java10\">clazz.equals<\/span><span class=\"java8\">(<\/span><span class=\"java10\">method.getDeclaringClass<\/span><span class=\"java8\">())) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">return <\/span><span class=\"java10\">method.isAnnotationPresent<\/span><span class=\"java8\">(<\/span><span class=\"java10\">annotationToCheck<\/span><span class=\"java8\">)<\/span><span class=\"java10\">;<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">} <\/span><span class=\"java4\">else <\/span><span class=\"java8\">{<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java3\">\/\/ if the methods declaring class is not the same as the implmenting class<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; \/\/ check the annotations on the implementing method not the asked method<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java9\">boolean <\/span><span class=\"java10\">r = <\/span><span class=\"java4\">false<\/span><span class=\"java10\">;<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">if<\/span><span class=\"java8\">( <\/span><span class=\"java10\">Modifier.isAbstract<\/span><span class=\"java8\">(<\/span><span class=\"java10\">method.getModifiers<\/span><span class=\"java8\">() ) ) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java3\">\/\/ try to get the implementing method from the real instance<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">try <\/span><span class=\"java8\">{<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java10\">Method methodToCheck = clazz.getDeclaredMethod<\/span><span class=\"java8\">(<\/span><span class=\"java10\">method.getName<\/span><span class=\"java8\">()<\/span><span class=\"java10\">,method.getParameterTypes<\/span><span class=\"java8\">())<\/span><span class=\"java10\">;<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">if<\/span><span class=\"java8\">( <\/span><span class=\"java10\">methodToCheck != <\/span><span class=\"java4\">null <\/span><span class=\"java8\">) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java10\">r = methodToCheck.isAnnotationPresent<\/span><span class=\"java8\">(<\/span><span class=\"java10\">annotationToCheck<\/span><span class=\"java8\">)<\/span><span class=\"java10\">;<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">}<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; } <\/span><span class=\"java4\">catch <\/span><span class=\"java8\">(<\/span><span class=\"java10\">SecurityException e<\/span><span class=\"java8\">) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; } <\/span><span class=\"java4\">catch <\/span><span class=\"java8\">(<\/span><span class=\"java10\">NoSuchMethodException e<\/span><span class=\"java8\">) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; }<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; }<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">return <\/span><span class=\"java10\">r;<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">}<br \/>\n<\/span><br \/>\n<span class=\"java8\">}<\/p>\n<p>&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">public <\/span><span class=\"java10\">Class getAnnotationToCheck<\/span><span class=\"java8\">() {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">return <\/span><span class=\"java10\">annotationToCheck;<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">}<\/p>\n<p>&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">public <\/span><span class=\"java9\">void <\/span><span class=\"java10\">setAnnotationToCheck<\/span><span class=\"java8\">(<\/span><span class=\"java10\">Class&lt;? <\/span><span class=\"java4\">extends <\/span><span class=\"java10\">Annotation&gt; annotationToCheck<\/span><span class=\"java8\">) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">this<\/span><span class=\"java10\">.annotationToCheck = annotationToCheck;<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">}<\/p>\n<p>}<\/span><\/tt>\n<\/p><\/blockquote>\n<p>Jetzt wird unterschieden, ob die Methode um die es geht, von der instanzieerten Klasse selbst stammt oder eben in einem Interface deklariert wurde. Wenn die Methode nicht von der Klasse selst stammt, dann wird die Annotation nicht auf der Methode gesucht, die dem Advisor \u00fcbergeben wurde, sondern auf der Methode, die die Interface-Methode implementiert. <\/p>\n<p>Auf diese Weise funktioniert die Annotation auf der Implementierungsklasse auch dann, wenn diese Klasse ein oder mehrere Interfaces implementiert. <\/p>\n<p>Ein vollst\u00e4ndiges Beispiel l\u00e4\u00dft sich <a href=\"http:\/\/www.lookingeye.de\/download\/springtest.zip\">hier<\/a> herunterladen. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Autoproxing mit Spring Das Applikation Framework Spring bringt ein sehr n\u00fctzliches Feature mit: Autoproxing. Damit lassen sich Spring Beans &#8211; also eigentlich jede POJO-Klasse &#8211; um Aspekte erweitern. Aspekte sind gem\u00e4ss AOP Belange eines Programms die sich quer zur eigentlichen &hellip; <a href=\"https:\/\/cogito-ergo-blog.de\/blog\/2006\/07\/16\/springs-aop-autoproxy-feature-mit-java-5-0-annotationen\/\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[],"_links":{"self":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/3"}],"collection":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/comments?post=3"}],"version-history":[{"count":1,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/3\/revisions"}],"predecessor-version":[{"id":10016,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/3\/revisions\/10016"}],"wp:attachment":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=3"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=3"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=3"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}