PDA

View Full Version : Help with DefaultAdvisorAutoProxyCreator for ThrowsAdvice



turgayz
Sep 1st, 2004, 06:31 AM
Hi,
I want to define a DefaultAdvisorAutoProxyCreator, to be able to generate a database entry containing the details of an Exception. I want to define it so that, whenever an Exception is thrown, I want a row to be inserted into a table containing the details...

Here are my definitions:


<bean id="exceptionAdvice" class="util.ExceptionAdvice" >
<property name="userDAO"><ref local="userDAO"/></property>
<property name="systemDAO"><ref local="systemDAO"/></property>
</bean>

<bean id="exceptionAdvisor" class="org.springframework.aop.support.RegexpMethodPointc utAdvisor">
<property name="advice"><ref local="exceptionAdvice"/></property>
<property name="patterns">
<list>
<value>.*</value>
</list>
</property>
</bean>

<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.Defaul tAdvisorAutoProxyCreator">
<property name="advisorBeanNamePrefix">
<value>exceptionAdv</value>
</property>
<property name="usePrefix">
<value>true</value>
</property>
</bean>


Here is my ExceptionAdvice:


public class ExceptionAdvice implements ThrowsAdvice&#123;
private SystemDAO systemDAO = null;
private UserDAO userDAO = null;

public void setUserDAO&#40;UserDAO userDao&#41; &#123;
this.userDAO = userDao;
&#125;
public void setSystemDAO&#40;SystemDAO systemDao&#41; &#123;
this.systemDAO = systemDao;
&#125;

public void afterThrowing&#40;Method m,Object&#91;&#93; args,Object target,Exception ex&#41;&#123;
ApplicationErrorLog ael=new ApplicationErrorLog&#40;&#41;;
Timestamp now = new Timestamp&#40;System.currentTimeMillis&#40;&#41;&#41;;
ael.setCreatedTime&#40;now&#41;;

ael.setCreatedUser&#40;userDAO.retrieveUserByUserName&#40;"admin"&#41;&#41;;
ael.setDescription&#40;"Method&#58;"+m+" Exception&#58;"+ex&#41;;
ael.setErrorNumber&#40;"111"&#41;;
systemDAO.saveApplicationErrorLog&#40;ael&#41;;
&#125;
&#125;


I get the following Exception when I try to run this:


Exception in constructor&#58; testCreateAndDeleteUser &#40;org.springframework.beans.factory.BeanCreationExc eption&#58; Error creating bean with name 'userManagerFacade' defined in class path resource &#91;applicationContext.xml&#93;&#58; Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigExcepti on&#58; Unexpected AOP exception; nested exception is java.lang.IllegalArgumentException&#58; Cannot subclass final class class $Proxy3
org.springframework.aop.framework.AopConfigExcepti on&#58; Unexpected AOP exception; nested exception is java.lang.IllegalArgumentException&#58; Cannot subclass final class class $Proxy3
java.lang.IllegalArgumentException&#58; Cannot subclass final class class $Proxy3
at net.sf.cglib.proxy.Enhancer.generateClass&#40;Enhancer .java&#58;448&#41;
at net.sf.cglib.core.DefaultGeneratorStrategy.generat e&#40;DefaultGeneratorStrategy.java&#58;63&#41;
at net.sf.cglib.core.AbstractClassGenerator.create&#40;Ab stractClassGenerator.java&#58;192&#41;
at net.sf.cglib.proxy.Enhancer.createHelper&#40;Enhancer. java&#58;406&#41;
at net.sf.cglib.proxy.Enhancer.create&#40;Enhancer.java&#58;3 18&#41;
at org.springframework.aop.framework.Cglib2AopProxy.g etProxy&#40;Cglib2AopProxy.java&#58;240&#41;
at org.springframework.aop.framework.Cglib2AopProxy.g etProxy&#40;Cglib2AopProxy.java&#58;213&#41;
at org.springframework.aop.framework.ProxyFactoryBean .getSingletonInstance&#40;ProxyFactoryBean.java&#58;210&#41;
at org.springframework.aop.framework.ProxyFactoryBean .setBeanFactory&#40;ProxyFactoryBean.java&#58;177&#41;
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean&#40;AbstractAuto wireCapableBeanFactory.java&#58;245&#41;
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean&#40;AbstractAuto wireCapableBeanFactory.java&#58;177&#41;
at org.springframework.beans.factory.support.Abstract BeanFactory.getBean&#40;AbstractBeanFactory.java&#58;159&#41;
at org.springframework.beans.factory.support.DefaultL istableBeanFactory.preInstantiateSingletons&#40;Defaul tListableBeanFactory.java&#58;177&#41;
at org.springframework.context.support.AbstractApplic ationContext.refresh&#40;AbstractApplicationContext.ja va&#58;268&#41;
at org.springframework.context.support.ClassPathXmlAp plicationContext.<init>&#40;ClassPathXmlApplicationContext.java&#58;68&#41;
at service.BaseServiceTestCase.<init>&#40;BaseServiceTestCase.java&#58;14&#41;
at service.UserManagerFacadeTest.<init>&#40;UserManagerFacadeTest.java&#58;12&#41;
at sun.reflect.NativeConstructorAccessorImpl.newInsta nce0&#40;Native Method&#41;
at sun.reflect.NativeConstructorAccessorImpl.newInsta nce&#40;NativeConstructorAccessorImpl.java&#58;39&#41;
at sun.reflect.DelegatingConstructorAccessorImpl.newI nstance&#40;DelegatingConstructorAccessorImpl.java&#58;27&#41;
at java.lang.reflect.Constructor.newInstance&#40;Construc tor.java&#58;274&#41;
at service.UserManagerFacadeTest.main&#40;UserManagerFaca deTest.java&#58;69&#41;
&#41;
at service.UserManagerFacadeTest.main&#40;UserManagerFaca deTest.java&#58;69&#41;


It complains about the bean 'userManagerFacade' , so here is the bean definition:


<bean id="FacadeTemplate" lazy-init="true"
class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<property name="transactionManager"><ref local="transactionManager"/></property>
<property name="transactionAttributes">
<props>
<prop key="update_*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>

<bean id="userManagerFacade" parent="FacadeTemplate" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><ref local="userManagerFacadeTarget"/></property>
<property name="interceptorNames">
<list>
<value>securityAdvisor</value>
</list>
</property>
</bean>

<bean id="userManagerFacadeTarget" class="service.impl.UserManagerFacadeImpl">
<property name="userDAO"><ref local="userDAO"/></property>
<property name="systemDAO"><ref local="systemDAO"/></property>
</bean>


What can be the problem?
Thanks a lot, regards,
Turgay Zengin

Rod Johnson
Sep 1st, 2004, 07:41 AM
It looks like one of the classes you're trying to advise is final. CGLIB generates a subclass at runtime to apply interception: it can't do this if a class is final.

turgayz
Sep 1st, 2004, 08:04 AM
Thanks Rod,
But I have no final classes.

I suspect that the bean 'userManagerFacadeTarget' is causing the problem. I get the exception after the following:


DEBUG - AbstractAutowireCapableBeanFactory.destroyBean&#40;849 &#41; | Applying DestructionAwareBeanPostProcessors to bean with name 'userManagerFacadeTarget'


Probably there is an error with this bean definition, but I can't figure out how to fix it: (All configuration is in the first post)


<bean id="userManagerFacade" parent="FacadeTemplate" class="org.springframework.aop.framework.ProxyFactoryBean">


Can I use both "parent" and "class" in the same bean definition?

Regards,
Turgay Zengin

turgayz
Sep 2nd, 2004, 02:08 AM
While playing with the context definition, I made it work, but don't know why it works now. Looks like the order of definitions are important when using parent="a template" (first I define the TransactionalFacadeTemplate, then the SecureFacadeTemplate and then finally the facade bean).

Also, there is one difference which may be the reason it works now: There is another template bean for the security advice now. The userManagerFacade bean uses this SecureFacadeTemplate bean to have security advice functionality.

Here is the changed bean definitions:


<bean id="TransactionalFacadeTemplate" lazy-init="true"
class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<property name="transactionManager"><ref local="transactionManager"/></property>
<property name="transactionAttributes">
<props>
<prop key="update_*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>

</bean>

<bean id="SecureFacadeTemplate" lazy-init="true" parent="TransactionalFacadeTemplate"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>securityAdvisor</value>
</list>
</property>

</bean>

<bean id="userManagerFacade" parent="SecureFacadeTemplate" >
<property name="proxyInterfaces"><value>service.UserManagerFacade</value></property>
<property name="target"><ref local="userManagerFacadeTarget"/></property>
</bean>

<bean id="userManagerFacadeTarget" class="service.impl.UserManagerFacadeImpl">
<property name="userDAO"><ref local="userDAO"/></property>
<property name="systemDAO"><ref local="systemDAO"/></property>
</bean>



Now the exception advice works...

Regards,
Turgay Zengin

gpoirier
Sep 2nd, 2004, 08:48 AM
It sounds like you had DefaultAdvisorAutoProxyCreator trying to proxy a proxy. The JDK's proxies are final classes, thus they cannot be proxied by CBLIB.

turgayz
Sep 2nd, 2004, 10:03 AM
Thank you, that explains the exception java.lang.IllegalArgumentException: Cannot subclass final class class $Proxy3

Rod Johnson
Sep 3rd, 2004, 03:09 AM
It sounds like you had DefaultAdvisorAutoProxyCreator trying to proxy a proxy
Proxying a proxy is usually a bad idea (although I've seen people doing it successfully, unintentionally) because of the additional performance overhead (not usually a problem, though) and the added depth to stack traces for debugging and analysing production problems.

turgayz
Sep 3rd, 2004, 03:19 AM
So, what is the recommended way to have the same service object (my userManagerFacade in this example) to have both TransactionProxyFactoryBean functionality, and another AOP functionality (securityAdvisor in this example)?

irbouho
Sep 3rd, 2004, 02:11 PM
So, what is the recommended way to have the same service object (my userManagerFacade in this example) to have both TransactionProxyFactoryBean functionality, and another AOP functionality (securityAdvisor in this example)?
You can use


<bean id="TransactionalFacadeTemplate" lazy-init="true"
class="org.springframework.transaction.interceptor.Transa ctionProxyFactoryBean">
<property name="transactionManager">
<ref local="transactionManager"/>
</property>
<property name="transactionAttributes">
<props>
<prop key="update_*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>
</props>
</property>
</bean>

<bean id="SecureFacadeTemplate" lazy-init="true" parent="TransactionalFacadeTemplate">
<property name="preInterceptors">
<list>
<ref local="securityAdvisor"/>
</list>
</property>
</bean>

<bean id="userManagerFacade" parent="SecureFacadeTemplate" >
<property name="proxyInterfaces"><value>service.UserManagerFacade</value></property>
<property name="target">
<bean id="userManagerFacadeTarget" class="service.impl.UserManagerFacadeImpl">
<property name="userDAO"><ref local="userDAO"/></property>
<property name="systemDAO"><ref local="systemDAO"/></property>
</bean>
</property>
</bean>

turgayz
Sep 6th, 2004, 09:41 AM
Thank you,
I used the part that you insert "userManagerFacadeTarget" as a nested bean. But the other part caused problems (where you set the preInterceptors). I got an exception saying:



testCreateAndDeleteUser&#40;service.UserManagerFacadeT est&#41;org.springframework.orm.hibernate.HibernateSys temException&#58; a different object with the same identifier value was already associated with the session&#58; 2, of class&#58; domain.User; nested exception is net.sf.hibernate.NonUniqueObjectException&#58; a different object with the same identifier value was already associated with the session&#58; 2, of class&#58; domain.User


I understood the pre-post interceptors, thank you. But I couldn't make it work that way. My config works the other way (described in post dated Sep 02, 2004 4:08 am), so I'll use that.

Regards,
Turgay Zengin