PDA

View Full Version : Problem getting started



Jeff Gager
Aug 24th, 2004, 05:36 AM
I am having trouble getting a aop demo working in SPRING.

My test program starts a ClassPathXmlApplicationContext which loads the folling applicationContext;

<bean id="beforeAdvice" class="MyBeforeAdvice"/>

<bean id="beforeAdvisor"
class="org.springframework.aop.support.RegexpMethodPointc utAdvisor">
<property name="advice"><ref local="beforeAdvice"/></property>
<property name="pattern"><value>.*</value></property>
</bean>

<bean id="test1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>TestBean</value></property>
<property name="target"><bean class="TestBeanImpl"/></property>
<property name="interceptorNames">
<list>
<value>beforeAdvisor</value>
</list>
</property>
</bean>

beforeAdvice just prints a message so I know it is called.

The first time I run test app to get the 'test1' bean and call its methods I got

NoClassDefFoundError: net/sf/cglib/proxy/MethodInterceptor

I expected it to proxy the TestBean interface supplied to proxyInterfaces and not use cglib to proxy the TestBeanImpl class, but I go along with this anyway and put cglib on the classpath.

Now I have the following exception, any help with this would be greatly appreciated.

- Jeff


org.springframework.aop.framework.AopConfigExcepti on: Cannot create AopProxy with no advisors and no target source
at org.springframework.aop.framework.Cglib2AopProxy.<init>(Cglib2AopProxy.java:77)
at org.springframework.aop.framework.DefaultAopProxyF actory$CglibProxyFactory.createCglibProxy(DefaultA opProxyFactory.java:47)
at org.springframework.aop.framework.DefaultAopProxyF actory$CglibProxyFactory.access$000(DefaultAopProx yFactory.java:44)
at org.springframework.aop.framework.DefaultAopProxyF actory.createAopProxy(DefaultAopProxyFactory.java: 32)
at org.springframework.aop.framework.AdvisedSupport.c reateAopProxy(AdvisedSupport.java:454)
at org.springframework.aop.framework.ProxyFactoryBean .getSingletonInstance(ProxyFactoryBean.java:210)
at org.springframework.aop.framework.ProxyFactoryBean .getObject(ProxyFactoryBean.java:194)
at org.springframework.beans.factory.support.Abstract BeanFactory.getObjectForSharedInstance(AbstractBea nFactory.java:469)
at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:137)
at org.springframework.beans.factory.support.DefaultL istableBeanFactory.getBeansOfType(DefaultListableB eanFactory.java:144)
at org.springframework.beans.factory.BeanFactoryUtils .beansOfTypeIncludingAncestors(BeanFactoryUtils.ja va:109)
at org.springframework.beans.factory.support.DefaultL istableBeanFactory.findMatchingBeans(DefaultListab leBeanFactory.java:268)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.autowireByType(Abstract AutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.populateBean(AbstractAu towireCapableBeanFactory.java:460)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean(AbstractAuto wireCapableBeanFactory.java:232)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBean(AbstractAuto wireCapableBeanFactory.java:177)
at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:159)
at org.springframework.beans.factory.support.DefaultL istableBeanFactory.preInstantiateSingletons(Defaul tListableBeanFactory.java:177)
at org.springframework.context.support.AbstractApplic ationContext.refresh(AbstractApplicationContext.ja va:268)
at org.springframework.context.support.ClassPathXmlAp plicationContext.<init>(ClassPathXmlApplicationContext.java:58)
at RunTest.main(RunTest.java:14)
Ex

gpoirier
Aug 24th, 2004, 07:49 AM
If you want to make sure the JDK proxy are used, you have to specify the interfaces you want to be implemented by the proxy. I don't know why you got that error with CGLIB though.

Guillaume

irbouho
Aug 24th, 2004, 09:26 AM
Jeff Gager,

Could you provide the source code for your classes?

Jeff Gager
Aug 31st, 2004, 07:03 AM
OK this is my advisor

public class MyAdvisor implements PointcutAdvisor {

private Advice advice;
private Pointcut pointcut;

/*
* @see org.springframework.aop.PointcutAdvisor#getPointcu t()
*/
public Pointcut getPointcut() {
if (pointcut == null) {
pointcut = new Pointcut() {
public ClassFilter getClassFilter() {
return new ClassFilter() {
public boolean matches(Class arg0) {
return true;
}
};
}
public MethodMatcher getMethodMatcher() {
return new MethodMatcher() {
public boolean matches(Method arg0, Class arg1) {
if (arg0.getName().indexOf("meth") == 0)
return true;
return false;
}
public boolean isRuntime() {
return false;
}
public boolean matches(Method arg0, Class arg1, Object[] arg2) {
return false;
}
};
}
};
}
return pointcut;
}

/*
* @see org.springframework.aop.Advisor#getAdvice()
*/
public Advice getAdvice() {
if (advice == null) {

advice = new MethodBeforeAdvice() {
private boolean initialised = false;
public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
Object o = arg2;
if (o instanceof Initializable && !initialised) {
Initializable i = (Initializable)o;
i.init();
initialised = true;
}
}
};
}
return advice;
}

/*
* @see org.springframework.aop.Advisor#isPerInstance()
*/
public boolean isPerInstance() {
return true;
}

}

irbouho
Aug 31st, 2004, 03:32 PM
Jeff,

I do not know where interface Initializable comes from, so I created a simple one for testing:


public interface Initializable &#123;
void init&#40;&#41;;
&#125;

TestBean interface:


public interface TestBean &#123;
int methodSum&#40;int a, int b&#41;;
&#125;

TestBeanImpl class:


public class TestBeanImpl implements TestBean, Initializable &#123;
public void init &#40;&#41; &#123;
System.out.println &#40;"initializing..."&#41;;
&#125;

public int methodSum&#40;int a, int b&#41; &#123;
return a + b;
&#125;
&#125;

and my applicationContext.xml


<beans>
<bean id="beforeAdvice" class="MyAdvisor"/>

<bean id="testBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>TestBean</value></property>
<property name="target"><bean class="TestBeanImpl"/></property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
</list>
</property>
</bean>
</beans>

This sample runs using JDK1.4, Jakarta commons logging, aopalliance.jar and of course spring.jar (no CGLIB).

gpoirier
Aug 31st, 2004, 04:22 PM
Jeff,

Looking at your code, there's some redundant stuff in there. First, when you provide an interceptor/advice that you want to apply to all methods of the instance, there's no need to wrap it in a RegexMethodPointcutAdvisor like you did. ProxyFactoryBean accept interceptors/advices, and providing one directly avoid the regexp layer which wouls make things slower.

Also, instead of implementing PointcutAdvisor, you can simply implement MethodBeforeAdvice, and pass that bean's name to the ProxyFactoryBean.

From your code, I don't see that any of it should fail, but eliminating the redundancy should probably make things easier to debug.

Guillaume

vickyk
Aug 31st, 2004, 11:31 PM
Also, instead of implementing PointcutAdvisor, you can simply implement MethodBeforeAdvice, and pass that bean's name to the ProxyFactoryBean.

I have a different opinion here . I have noticed the flow as
ProxyFactoryBean ------> createAdvisorChain() -----> addAdvisor() -----> namedBeanToAdvisorOrTargetSource() ----------------------------------------> DefaultAdvisorAdapterRegistry.wrap()
So the wrap does always make sure that your Advise is Wrapped . The following code shows that :


public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}

if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;

if (advice instanceof Interceptor) {
// So well-known it doesn't even need an adapter
return new DefaultPointcutAdvisor(advice);
}
for (int i = 0; i < this.adapters.size(); i++) {
// Check that it is supported
AdvisorAdapter adapter = (AdvisorAdapter) this.adapters.get(i);
if (adapter.supportsAdvice(advice)) {
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}


Jeff Gager , can you post all the code here ? I mean the Interface , the Target class TestBean .

Regards
Vicky

gpoirier
Aug 31st, 2004, 11:55 PM
I have a different opinion here . I have noticed the flow as
ProxyFactoryBean ------> createAdvisorChain() -----> addAdvisor() -----> namedBeanToAdvisorOrTargetSource() ----------------------------------------> DefaultAdvisorAdapterRegistry.wrap()
So the wrap does always make sure that your Advise is Wrapped . The following code shows that :

I'm not sure how what you're saying is any different than what I said? My point was that you don't have to make your own Advisor, you can just pass an Advice to ProxyFactoryBean and it will nicely wraps it in an Advisor.

Jeff,

I also noticed your code is not synchronized. If your TestBeanImpl was to be called in concurrent threads, then the init method might be called twice.

vickyk
Sep 1st, 2004, 12:14 AM
I'm not sure how what you're saying is any different than what I said? My point was that you don't have to make your own Advisor, you can just pass an Advice to ProxyFactoryBean and it will nicely wraps it in an Advisor.

Ya that is correct , I have interpreted it wrongly .In this case he could use the DefaultPointcutAdvisor.


ProxyFactoryBean accept interceptors/advices, and providing one directly avoid the regexp layer which wouls make things slower.

Do you mean the slower Development or Slower Execution here ?

Regards
Vicky

gpoirier
Sep 1st, 2004, 12:23 AM
I meant slower Execution. Using a regular expression is slower then just returning true. Might not be a huge difference, especially if the method's gonna do DB stuff, but there's no real gain for using RegexpMethodPointcutAdvisor when you want to match all methods. It also adds uneeded configuration code.

vickyk
Sep 1st, 2004, 12:54 AM
I meant slower Execution. Using a regular expression is slower then just returning true. Might not be a huge difference, especially if the method's gonna do DB stuff, but there's no real gain for using RegexpMethodPointcutAdvisor when you want to match all methods. It also adds uneeded configuration code.
I am sure about the RegexpMethodPointcutAdvisor , I have not been aware of regular expression as the word . Do you mean the following snippet


return new MethodMatcher() {
public boolean matches(Method arg0, Class arg1) {
if (arg0.getName().indexOf("meth") == 0)
return true;
return false;
}

can be replaced by


return new MethodMatcher() {
public boolean matches(Method arg0, Class arg1) {
//if (arg0.getName().indexOf("meth") == 0)
return true;
}


Rgds
Vicky

vickyk
Sep 1st, 2004, 01:04 AM
I meant slower Execution. Using a regular expression is slower then just returning true. Might not be a huge difference, especially if the method's gonna do DB stuff, but there's no real gain for using RegexpMethodPointcutAdvisor when you want to match all methods. It also adds uneeded configuration code.
Should not the Introduciton Advisor be used in the case of matching all the methods ?

Rgds
Vicky

Jeff Gager
Sep 1st, 2004, 02:58 AM
Wow this is a great forum - thanks to everyone for the help and advice.

It's working fine now :)

gpoirier
Sep 1st, 2004, 08:29 AM
Jeff,

I'm glad we could help you. However, I also forgot a last thing that I'm not sure
you were aware. For your MyBeforeAdvice to work on multiple target instances, your
advice/advisor must be a prototype, otherwise the same advice instance will be used
for each target, thus only on one of your targets would init be called.


Vickyk,



I am sure about the RegexpMethodPointcutAdvisor , I have not been aware of regular expression as the word . Do you mean the following snippet
[...]
can be replaced by
[...]


No, what I meant is replacing the XML code:



<bean id="beforeAdvice" class="MyBeforeAdvice"/>

<bean id="beforeAdvisor"
class="org.springframework.aop.support.RegexpMethodPointc utAdvisor">
<property name="advice"><ref local="beforeAdvice"/></property>
<property name="pattern"><value>.*</value></property>
</bean>

<bean id="test1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>TestBean</value></property>
<property name="target"><bean class="TestBeanImpl"/></property>
<property name="interceptorNames">
<list>
<value>beforeAdvisor</value>
</list>
</property>
</bean>

by


<bean id="beforeAdvice" class="MyBeforeAdvice"/>

<bean id="test1" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"><value>TestBean</value></property>
<property name="target"><bean class="TestBeanImpl"/></property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
</list>
</property>
</bean>


And previously, for the Advice/Advisor thing, I meant that instead of the
MyAdvisor defined in Jeff's post, he could use the following code, with the
new XML snippet I mentionned above. But I considering the name change from
MyBeforeAdvice in the first post, to MyAdvisor in the second, I guess it's
what he did at first, except with the XML snippet using the RegexpMethodPointcutAdvisor.



public class MyBeforeAdvice implements MethodBeforeAdvice &#123;
private boolean initialised = false;

public synchronized void before&#40;Method method, Object&#91;&#93; args, Object target&#41; throws Throwable &#123;
if &#40;!initialised && target instanceof Initializable&#41; &#123;
Initializable i = &#40;Initializable&#41;o;
i.init&#40;&#41;;
initialised = true;
&#125;
&#125;
&#125;




Should not the Introduciton Advisor be used in the case of matching all the methods ?
The purpose of the Introduction Advisor is to add interfaces to a target, it isn't for interception of existing methods.