{"id":2,"date":"2006-08-01T18:36:17","date_gmt":"2006-08-01T17:36:17","guid":{"rendered":"http:\/\/euve3303.vserver.de\/stefan\/blog\/?p=5"},"modified":"2011-12-02T20:36:12","modified_gmt":"2011-12-02T19:36:12","slug":"springs-aop-proxies","status":"publish","type":"post","link":"https:\/\/cogito-ergo-blog.de\/blog\/2006\/08\/01\/springs-aop-proxies\/","title":{"rendered":"Spring&#8217;s AOP Proxies"},"content":{"rendered":"<p>Wenn Spring&#8217;s AOP Framework Proxies erzeugt um eigene Klassen mit zus\u00e4tzlichen Features zu versehen, kann das mitunter seltsame Effekte haben. Beispielsweise w\u00fcrde man doch vermuten, dass eine SpringBean die auf folgende Weise definiert ist:<\/p>\n<p><\/p>\n<table cellspacing=\"0\" cellpadding=\"0\" width=\"70%\" border=\"1\">\n<tbody>\n<tr>\n<td>\n<pre>&lt;bean name=&quot;testBean&quot; class=&quot;com.rinke.solutions.spring.test.SpringTestImpl&quot; \/&gt;<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>sich in einer Applikation immer in etwa in der Art verwenden l\u00e4\u00dft: <\/p>\n<p><\/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;\">\n<p><tt class=\"java\"><span class=\"java4\">package <\/span><span class=\"java10\">com.rinke.solutions.spring.test;<\/p>\n<p><\/span><span class=\"java4\">import <\/span><span class=\"java10\">org.springframework.context.ApplicationContext;<br \/>\n<\/span><span class=\"java4\">import <\/span><span class=\"java10\">org.springframework.context.support.ClassPathXmlApplicationContext;<\/p>\n<p><\/span><span class=\"java4\">public class <\/span><span class=\"java10\">TestSpring <\/span><span class=\"java8\">{<\/p>\n<p>&#xA0;&#xA0;&#xA0; <\/span><span class=\"java14\">\/**<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; * <\/span><span class=\"java11\">@param <\/span><span class=\"java14\">args<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0; &#42;\/<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java4\">public static <\/span><span class=\"java9\">void <\/span><span class=\"java10\">main<\/span><span class=\"java8\">(<\/span><span class=\"java10\">String<\/span><span class=\"java8\">[] <\/span><span class=\"java10\">args<\/span><span class=\"java8\">) {<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java10\">ApplicationContext ctx = <\/span><span class=\"java4\">new <\/span><span class=\"java10\">ClassPathXmlApplicationContext<\/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\">new <\/span><span class=\"java10\">String<\/span><span class=\"java8\">[] {<\/span><span class=\"java5\">&#34;applicationContext.xml&#34; <\/span><span class=\"java8\">})<\/span><span class=\"java10\">;<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; SpringTestImpl myBean = <\/span><span class=\"java8\">(<\/span><span class=\"java10\">SpringTestImpl<\/span><span class=\"java8\">) <\/span><span class=\"java10\">ctx.getBean<\/span><span class=\"java8\">(<\/span><span class=\"java5\">&#34;testBean&#34;<\/span><span class=\"java8\">)<\/span><span class=\"java10\">;<br \/>\n&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <\/span><span class=\"java3\">\/\/ ... do something<br \/>\n&#xA0;&#xA0;&#xA0; <\/span><span class=\"java8\">}<\/p>\n<p>}<\/span><\/tt><\/p>\n<\/blockquote>\n<p>Weit gefehlt! <\/p>\n<p><!--more--><\/p>\n<p>Je nach dem, ob die Klasse ein Interface implementiert oder nicht, funktioniert der Cast auf &quot;SpringTestImpl&quot; nicht mehr, sondern liefert eine ClassCastException. <\/p>\n<p>Dieses Verhalten r\u00fchrt daher, dass Spring beim Erzeugen von Proxies auf zwei unterschiedliche Mechanismen zur\u00fcckgreift: <\/p>\n<ol>\n<li>Die dynamischen Proxies aus dem JDK (seit Version 1.4) <\/li>\n<li>Auf dynamisch erzeugte Subclasses deren Bytecode zur Laufzeit mit der CGLib generiert wird. <\/li>\n<\/ol>\n<p>Das erste Verfahren ist das per Default bevorzugte, funktioniert aber nur, wenn die in Frage stehende Klasse wenigstens ein Interface implementiert. Wieso kommt es nun zu der ClassCastException? Ganz einfach, der erzeugte Proxy ist ein Proxy eines Interfaces, welches die Klasse implemeniert und dieser ist vom Typ her nicht auf die Implementierungsklasse &quot;herunter castbar&quot;. Obwohl man also weiss, dass eine ganz bestimmte Implementierung hinter einer Bean steckt, kann sie auf diesen Typ nicht gecastet werden. <\/p>\n<p>Jetzt mag man einwenden, dass es sowieso besserer Stil ist ein Interface zu definieren gegen das man programmiert. Aber die Alttag l\u00e4\u00dft einen oft genug diesen Schritt \u00fcberspringen, wenn weiter kein Nutzen davon entsteht, weil dieses Interface keine zus\u00e4tzlich Abstraktion bringt. Der Fehler kommt dann &quot;durch die Hintert\u00fcr&quot;, wenn die Implementierungsklasse aus anderen Gr\u00fcnden ein Interfaces implementieren muss (z.B. &quot;Serializable&quot;). Pl\u00f6tzlich entstehen so Exceptions, die da vorher nicht zu sehen waren. <\/p>\n<h2>Ausweg? <\/h2>\n<p>Schaut man einigermassen tief in die Spring Dokumentation, so findet sich eine Konfigurationseinstellung, die bewirkt, das das Erzeugen der Proxies <i>immer<\/i> mit Hilfe der CGLib gemacht wird. Das bewirkt als Nebeneffekt, dass der Cast aus dem Beispiel oben wieder funktioniert, denn nun ist der erzeugte Proxy eine echte Subklasse von SpringTestImpl und damit auch &quot;castbar&quot;. <\/p>\n<p>Die vollst\u00e4ndige BeanFactory Konfiguration sieht dann z.B. so aus: <\/p>\n<table cellspacing=\"0\" cellpadding=\"0\" width=\"70%\" border=\"1\">\n<tbody>\n<tr>\n<td>\n<pre><code><font face=\"Lucida Console\" color=\"#000080\">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<\/font><\/code><br \/><code><font face=\"Lucida Console\" color=\"#008080\">&lt;!DOCTYPE beans PUBLIC &quot;-\/\/SPRING\/\/DTD BEAN\/\/EN&quot; &quot;http:\/\/www.springframework.org\/dtd\/spring-beans.dtd&quot;&gt;\r\n\r\n<\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">beans<\/font><font face=\"Lucida Console\" color=\"#808080\">&gt;\r\n\r\n<\/font><font face=\"Lucida Console\" color=\"#ffffff\">     <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">bean <\/font><font face=\"Lucida Console\" color=\"#800000\">class<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot;&gt;<\/font><\/code><br \/><code><font face=\"Lucida Console\" color=\"#ffffff\">          <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">property <\/font><font face=\"Lucida Console\" color=\"#800000\">name<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">proxyTargetClass<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot; <\/font><font face=\"Lucida Console\" color=\"#800000\">value<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">true<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot;\/&gt;<\/font><\/code><br \/><code><font face=\"Lucida Console\" color=\"#ffffff\">     <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;\/<\/font><font face=\"Lucida Console\" color=\"#000080\">bean<\/font><font face=\"Lucida Console\" color=\"#808080\">&gt;\r\n\r\n<\/font><font face=\"Lucida Console\" color=\"#ffffff\">     <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">bean <\/font><font face=\"Lucida Console\" color=\"#800000\">class<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">com.rinke.solutions.spring.test.aop.AnnotationSourceAdvisor<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot;&gt;<\/font><\/code><br \/><code><font face=\"Lucida Console\" color=\"#ffffff\">          <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">property <\/font><font face=\"Lucida Console\" color=\"#800000\">name<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">annotationToCheck<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot; <\/font><font face=\"Lucida Console\" color=\"#800000\">value<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">com.rinke.solutions.spring.test.Writing<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot;\/&gt;<\/font><\/code><br \/><code><font face=\"Lucida Console\" color=\"#ffffff\">          <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">property <\/font><font face=\"Lucida Console\" color=\"#800000\">name<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">advice<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot; <\/font><font face=\"Lucida Console\" color=\"#800000\">ref<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">writeableCheckInterceptor<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot;\/&gt;<\/font><\/code><br \/><code><font face=\"Lucida Console\" color=\"#ffffff\">     <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;\/<\/font><font face=\"Lucida Console\" color=\"#000080\">bean<\/font><font face=\"Lucida Console\" color=\"#808080\">&gt;\r\n\r\n<\/font><font face=\"Lucida Console\" color=\"#ffffff\">     <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">bean <\/font><font face=\"Lucida Console\" color=\"#800000\">id<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">writeableCheckInterceptor<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot; <\/font><font face=\"Lucida Console\" color=\"#800000\">class<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">com.rinke.solutions.spring.test.aop.WriteableCheckInterceptor<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot;&gt;<\/font><\/code><br \/><code><font face=\"Lucida Console\" color=\"#ffffff\">          <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">property <\/font><font face=\"Lucida Console\" color=\"#800000\">name<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">readOnly<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot; <\/font><font face=\"Lucida Console\" color=\"#800000\">value<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">true<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot;\/&gt;<\/font><\/code><br \/><code><font face=\"Lucida Console\" color=\"#ffffff\">          <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">property <\/font><font face=\"Lucida Console\" color=\"#800000\">name<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">exceptionToThrow<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot; <\/font><font face=\"Lucida Console\" color=\"#800000\">value<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">com.rinke.solutions.spring.test.ReadOnlyException<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot;\/&gt;<\/font><\/code><br \/><code><font face=\"Lucida Console\" color=\"#ffffff\">     <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;\/<\/font><font face=\"Lucida Console\" color=\"#000080\">bean<\/font><font face=\"Lucida Console\" color=\"#808080\">&gt;\r\n\r\n<\/font><font face=\"Lucida Console\" color=\"#ffffff\">     <\/font><font face=\"Lucida Console\" color=\"#808080\">&lt;<\/font><font face=\"Lucida Console\" color=\"#000080\">bean <\/font><font face=\"Lucida Console\" color=\"#800000\">name<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">testBean<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot; <\/font><font face=\"Lucida Console\" color=\"#800000\">class<\/font><font face=\"Lucida Console\" color=\"#808080\">=&quot;<\/font><font face=\"Lucida Console\" color=\"#ff0000\">com.rinke.solutions.spring.test.SpringTestImpl<\/font><font face=\"Lucida Console\" color=\"#808080\">&quot; \/&gt;\r\n\r\n&lt;\/<\/font><font face=\"Lucida Console\" color=\"#000080\">beans<\/font><font face=\"Lucida Console\" color=\"#808080\">&gt;<\/font>\r\n<\/code><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Der entscheidende Konfiguration Schalter ist hier <font face=\"monospaced\">&lt;property name=&quot;proxyTargetClass&quot; value=&quot;true&quot;\/&gt;<\/font> womit eben immer auf CGLib zur\u00fcckgegriffen wird. <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wenn Spring&#8217;s AOP Framework Proxies erzeugt um eigene Klassen mit zus\u00e4tzlichen Features zu versehen, kann das mitunter seltsame Effekte haben. Beispielsweise w\u00fcrde man doch vermuten, dass eine SpringBean die auf folgende Weise definiert ist: &lt;bean name=&quot;testBean&quot; class=&quot;com.rinke.solutions.spring.test.SpringTestImpl&quot; \/&gt; sich in &hellip; <a href=\"https:\/\/cogito-ergo-blog.de\/blog\/2006\/08\/01\/springs-aop-proxies\/\">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\/2"}],"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=2"}],"version-history":[{"count":1,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/2\/revisions"}],"predecessor-version":[{"id":10014,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/posts\/2\/revisions\/10014"}],"wp:attachment":[{"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=2"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=2"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cogito-ergo-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=2"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}