Announcement Announcement Module
Collapse
No announcement yet.
Per-instance Advice and Target pairs exposed as Prototype bean Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Per-instance Advice and Target pairs exposed as Prototype bean

    I have a prototype Product bean that needs to be decorated with a per-instance MethodBeforeAdvice. It must be a per-instance advice because it needs to store one piece of internal state that doesn't belong within the Product domain object.

    The code for the MethodBeforeAdvice is as follows:

    Code:
    public class ProductDetailsAdvice implements MethodBeforeAdvice
    {
      private volatile boolean productDetailsInitialized = false;
      private Dao dao;
      
      /**
       * @see MethodInterceptor#invoke(MethodInvocation)
       */
      public void before(Method method, Object[] arguments, Object target)
        throws Throwable
      {
        if(!isProductDetailsInitialized())
        {
          initializeProductDetails((Product)target);
        }//if
      }//method invoke()
      
      public synchronized void initializeProductDetails(Product product) throws
        DAOException
      {
        if(!isProductDetailsInitialized())
        {
          getDao().populateProduct(product);
          setProductDetailsInitialized(true);
        }//if
      }//method initializeProductDetails()
      
      public void setDao(Dao dao)
      {
        this.dao = dao;
      }//method setIcsDao()
    
      private Dao getDao()
      {
        return dao;
      }//method getIcsDao()
      
      private boolean isProductDetailsInitialized()
      {
        return productDetailsInitialized;
      }//method isProductDetailsInitialized()
      
      private void setProductDetailsInitialized(boolean productDetailsInitialized)
      {
        this.productDetailsInitialized = productDetailsInitialized;
      }//method setProductDetailsInitialized()
    
    }
    As I've said before the advice/product pairs (proxy) need to be exposed as prototypes. I can set the singleton property of the ProxyFactoryBean to false to to get a new proxy on each call but it will only return a new proxy to the same product unless i specify a custom targetSource implementation of PrototypeTargetSource. Unfortunately in this case I seem to be getting a new instance of Product as the target for each invocation within the same proxy!. This seems like incredibly odd behavior. All of the properties of the Product object are forgotten between each call!

    Code:
    Product product = context.getBean("product");
    product.setType(notNullType); // target is ...DefaultProduct@5a705a7
    product.getType()  // returns null and target is ...DefaultProduct@2a35ab7
    Why would the target bean change within the same proxy reference? This isn't a prototype this is a prototype with multiple personality disorder!

    Any help would be much appreciated. It really seems like this should be a problem that I can solve with Spring AOP, but at the moment it's got me stumped.

    Thanks,

    -Sean

  • #2
    Figured it out

    Apparently if you list the taget bean name as the last value in the list of "interceptorNames" and leave out the "target" and "targetSource" property configurations it will pair up with a prototype proxy in the way I was looking for.

    Code:
    <beans>
      
      <bean name="productDetailsAdvice" class="com.exampledomain.aop.ProductDetailsAdvice"
        singleton="false">
        <property name="dao">
          <ref bean="dao"/>
        </property>
      </bean>
      
      <bean name="productDetailsPointcut"
        class="org.springframework.aop.support.JdkRegexpMethodPointcut">
        <property name="patterns">
          <list>
            <value>.*getPropertyXxx</value>
            <value>.*getPropertyYyy</value>
            <value>.*getPropertyZzz</value>
          </list>
        </property>
      </bean>
      
      <bean name="productDetailsAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"
        singleton="false">
        <property name="advice">
          <ref bean="productDetailsAdvice"/>
        </property>
        <property name="pointcut">
          <ref bean="productDetailsPointcut"/>
        </property>
      </bean>
      
      <bean name="cardTarget" class="com.exampledomain.catalog.Card" singleton="false"/>
      
      <bean name="card" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="singleton" value="false"/>
        <property name="interceptorNames">
          <list>
            <value>productDetailsAdvisor</value>
            <value>cardTarget</value>
          </list>
        </property>
      </bean>
      
    </beans>

    Comment

    Working...
    X