Frage

I am trying to use apache pool2 to pool some resources. I have it working fine in a unit test, but when I try using it in spring 3, I get an error.

Everything else is working with the Controller and Service. I could access the endpoint before I added the pooling code, and the autowired service is not null. This is all wired together using context:component-scan

If I set a breakpoint in the controller method, I see that the object returned from the borrow is org.apache.cxf.jaxws.JaxWsClientProxy@15de00c . Then inspecting the object in the active pool gives org.apache.cxf.jaxws.JaxWsClientProxy@15de00c

So, my question is this: why does this work in the unit test, but fails in the spring controller/service

controller:

 @Controller
 public class TestController() {

 @Autowired
 private TestService testService

 @RequestMapping(value="/test", method=RequestMethod.GET)
 public ModelAndView getTest() throws Exception {

 GenericObjectPool<MyObj> pool = testService.getPool();
pool.returnObject(pool.borrowObject());

 return new ModelAndView("jsp/test", "command", new TestObj()); //not really relevant yet

   }
 }     

and the service:

 @Service
 public class TestService implements DisposableBean {

 GenericObjectPool<MyObj> pool;

public TestService () {
    pool = new GenericObjectPool<MyObj>(new MyObjPooledObjectFactory());
}

public GenericObjectPool<MyObj> getPool() {
    return pool;
}

public void setPool(GenericObjectPool<MyObj> pool) {
    this.pool = pool;
}


@Override
public void destroy() throws Exception {
    LOG.info("DESTROYING Service");
    this.pool.close();
}
 }

Factory:

 MyObjPooledObjectFactory extends BasePooledObjectFactory<MyObj> {
  @Override
 public MyObjc create() throws Exception {
       MyObj myObj = expensive call.
     return myObj;
  }
 @Override
  public PooledObject<MyObj> wrap(MyObj obj) {
    return new DefaultPooledObject<MyObj>(obj);
}
 }


@Override
public void destroyObject(PooledObject<MyObj > p) throws Exception {
super.destroyObject(p);
 p.releaseConnection();
 }

and finally I have

 @Test
public void testMe() {


    TestService service = new TestService();
        GenericObjectPool<MyObj> pool = service.getPool();
    try {
        pool.returnObject(pool.borrowObject());
    } catch (Exception e) {
        e.printStackTrace();
        fail();
    }


}

the error I get is:

 java.lang.IllegalStateException: Returned object not currently part of this pool
 at org.apache.commons.pool2.impl.GenericObjectPool.returnObject(GenericObjectPool.java:537)
 at com.example.controller.TestController.getTest(TestController.java:56)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
 at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
 at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
 at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
 at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
 at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
 at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
 at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
 at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:779)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
 at javax.servlet.http.HttpServlet.service(HttpServlet.java:821)
 at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
 at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
 at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300)
 at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:27)
 at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:57)
 at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:89)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
 at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:57)
 at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3715)
 at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3681)
 at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
 at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
 at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2277)
 at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2183)
 at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1454)
 at weblogic.work.ExecuteThread.execute(ExecuteThread.java:207)
 at weblogic.work.ExecuteThread.run(ExecuteThread.java:176)

Also, it doesn't seem to help if I replace the @Autowired TestService with new TestService().

Well, I don't know why it is failing, but I've narrowed it down to a completely different problem:

            if (!myObj.equals(myObj)) {
                throw new IllegalStateException("WTF, Why is this not equal to itself!");
            }

will throw an exception. So now I need to figure out what is going on with this jaxWsClientProxy

War es hilfreich?

Lösung

I have the same issue when I am trying polled jaxws client port. The root cause is the same equals method does not work for Proxy object. If we want to compare on object identity inside our equals() method (i.e. with "=="), however, this does not work, because we are comparing the wrapped object to a proxy object, which is obviously false. To solve that issue I have introduce wrapper object around proxy, where define field "id" which can be used in equals() and hashCode() methods.

Code

public class DefaultCommonsPooledObject<T> extends DefaultPooledObject<T> {

private final UUID id = UUID.randomUUID();

/**
 * Create a new instance that wraps the provided object so that the pool can track the state of the pooled object.
 * 
 * @param object The object to wrap
 */
public DefaultCommonsPooledObject(T object) {
    super(object);
}

@Override
public boolean equals(Object o) {
    if (this == o)
        return true;
    if (!(o instanceof DefaultCommonsPooledObject))
        return false;

    DefaultCommonsPooledObject that = (DefaultCommonsPooledObject) o;

    if (id != null ? !id.equals(that.id) : that.id != null)
        return false;

    return true;
}

@Override
public int hashCode() {
    return id != null ? id.hashCode() : 0;
}

}

Andere Tipps

I saw the same weirdness with the jaxws port proxy, where (obj == obj) is true but (obj.equals(obj)) was false. So like you mentioned in the comment, I had to wrap the Jaxws service port to override the equals and hashcode, before putting the port object into the pool.

The Groovy Proxy class makes this pretty simple. Here is the Proxy that I'm using:

class JaxwsPortProxy<T> extends Proxy {
    private final UUID poolId = UUID.randomUUID()

    @Override
    boolean equals(Object o) {
        if (this == o)
            return true
        if (!(o instanceof JaxwsPortProxy))
            return false

        JaxwsPortProxy that = (JaxwsPortProxy) o

        poolId == null ? that.poolId == null : poolId.equals(that.poolId)
    }

    @Override
    int hashCode() {
        poolId?.hashCode() ?: 0
    }
}

And then the end of my BasePooledObjectFactory.create() method simply wraps the service port like this:

return new JaxwsPortProxy<RuleServiceWS>().wrap(ruleService)

Thanks for helping me get to this solution!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top