/** {@inheritDoc} */
  public void persistShoppingCart(
      final HttpServletRequest httpServletRequest,
      final HttpServletResponse httpServletResponse,
      final ShoppingCart shoppingCart) {

    CartTuplizer tuplizer = null;
    try {

      tuplizer = (CartTuplizer<HttpServletRequest, HttpServletResponse>) tuplizerPool.getTarget();
      try {
        tuplizer.tuplize(httpServletRequest, httpServletResponse, shoppingCart);
      } catch (CartTuplizationException e) {
        ShopCodeContext.getLog(this)
            .error(MessageFormat.format("Unable to create cookies from {0} cart", shoppingCart), e);
      }

    } catch (Exception e) {
      ShopCodeContext.getLog(this).error("Can process request", e);
    } finally {
      if (tuplizer != null) {
        try {
          tuplizerPool.releaseTarget(tuplizer);
        } catch (Exception e) {
          ShopCodeContext.getLog(this).error("Can return object to pool ", e);
        }
      }
    }
  }
  public void afterPropertiesSet() {
    if (this.target == null) {
      throw new IllegalArgumentException("Property 'target' is required");
    }
    if (this.target instanceof String) {
      throw new IllegalArgumentException(
          "'target' needs to be a bean reference, not a bean name as value");
    }

    ClassLoader proxyClassLoader = target.getClass().getClassLoader();

    ProxyFactory proxyFactory = new ProxyFactory();

    if (this.preInterceptors != null) {
      for (Object interceptor : this.preInterceptors) {
        proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
      }
    }

    // Add the main interceptor (typically an Advisor).
    proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));

    if (this.postInterceptors != null) {
      for (Object interceptor : this.postInterceptors) {
        proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
      }
    }

    proxyFactory.copyFrom(this);

    TargetSource targetSource = createTargetSource(this.target);
    proxyFactory.setTargetSource(targetSource);

    if (this.proxyInterfaces != null) {
      proxyFactory.setInterfaces(this.proxyInterfaces);
    } else if (!isProxyTargetClass()) {
      // Rely on AOP infrastructure to tell us what interfaces to proxy.
      proxyFactory.setInterfaces(
          ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), proxyClassLoader));
    }

    /**
     * use this option to let proxyFactory user cglib to create proxy,otherwise in dynamic script
     * ,this is no dynamic interface 使用这个选荋 将使用cglib 产生代理类,否则在动动的java中,没有动态的接口
     */
    proxyFactory.setOptimize(true);
    this.proxy = proxyFactory.getProxy(proxyClassLoader);
  }
 @SuppressWarnings("unchecked")
 <H> H extractTypeIfPossible(Object targetObject, Class<H> expectedType) {
   if (targetObject == null) {
     return null;
   }
   if (expectedType.isAssignableFrom(targetObject.getClass())) {
     return (H) targetObject;
   }
   if (targetObject instanceof Advised) {
     TargetSource targetSource = ((Advised) targetObject).getTargetSource();
     if (targetSource == null) {
       return null;
     }
     try {
       return extractTypeIfPossible(targetSource.getTarget(), expectedType);
     } catch (Exception e) {
       throw new IllegalStateException(e);
     }
   }
   return null;
 }
  private MessageHandlerMetrics enhanceHandlerMonitor(SimpleMessageHandlerMetrics monitor) {

    MessageHandlerMetrics result = monitor;

    if (monitor.getName() != null && monitor.getSource() != null) {
      return monitor;
    }

    // Assignment algorithm and bean id, with bean id pulled reflectively out of enclosing endpoint
    // if possible
    String[] names = beanFactory.getBeanNamesForType(AbstractEndpoint.class);

    String name = null;
    String endpointName = null;
    String source = "endpoint";
    Object endpoint = null;

    for (String beanName : names) {
      endpoint = beanFactory.getBean(beanName);
      Object field = null;
      try {
        field = extractTarget(getField(endpoint, "handler"));
      } catch (Exception e) {
        logger.trace("Could not get handler from bean = " + beanName);
      }
      if (field == monitor.getMessageHandler()) {
        name = beanName;
        endpointName = beanName;
        break;
      }
    }
    if (name != null && endpoint != null && name.startsWith("_org.springframework.integration")) {
      name = getInternalComponentName(name);
      source = "internal";
    }
    if (name != null && endpoint != null && name.startsWith("org.springframework.integration")) {
      Object target = endpoint;
      if (endpoint instanceof Advised) {
        TargetSource targetSource = ((Advised) endpoint).getTargetSource();
        if (targetSource != null) {
          try {
            target = targetSource.getTarget();
          } catch (Exception e) {
            logger.debug("Could not get handler from bean = " + name);
          }
        }
      }
      Object field = getField(target, "inputChannel");
      if (field != null) {
        if (!anonymousHandlerCounters.containsKey(field)) {
          anonymousHandlerCounters.put(field, new AtomicLong());
        }
        AtomicLong count = anonymousHandlerCounters.get(field);
        long total = count.incrementAndGet();
        String suffix = "";
        /*
         * Short hack to makes sure object names are unique if more than one endpoint has the same input channel
         */
        if (total > 1) {
          suffix = "#" + total;
        }
        name = field + suffix;
        source = "anonymous";
      }
    }

    if (endpoint instanceof Lifecycle) {
      // Wrap the monitor in a lifecycle so it exposes the start/stop operations
      result = new LifecycleMessageHandlerMetrics((Lifecycle) endpoint, monitor);
    }

    if (name == null) {
      name = monitor.getMessageHandler().toString();
      source = "handler";
    }

    if (endpointName != null) {
      beansByEndpointName.put(name, endpointName);
    }

    monitor.setSource(source);
    monitor.setName(name);

    return result;
  }
  private MessageSourceMetrics enhanceSourceMonitor(MessageSourceMetrics monitor) {

    MessageSourceMetrics result = monitor;

    if (monitor.getManagedName() != null) {
      return monitor;
    }

    // Assignment algorithm and bean id, with bean id pulled reflectively out of enclosing endpoint
    // if possible
    String[] names = this.applicationContext.getBeanNamesForType(AbstractEndpoint.class);

    String name = null;
    String endpointName = null;
    String source = "endpoint";
    Object endpoint = null;

    for (String beanName : names) {
      endpoint = this.applicationContext.getBean(beanName);
      Object field = null;
      if (monitor instanceof MessagingGatewaySupport && endpoint == monitor) {
        field = monitor;
      } else {
        try {
          field = extractTarget(getField(endpoint, "source"));
        } catch (Exception e) {
          logger.trace("Could not get source from bean = " + beanName);
        }
      }

      if (field == monitor) {
        name = beanName;
        endpointName = beanName;
        break;
      }
    }
    if (endpointName == null) {
      endpoint = null;
    }
    if (name != null && endpoint != null && name.startsWith("_org.springframework.integration")) {
      name = getInternalComponentName(name);
      source = "internal";
    }
    if (name != null && endpoint != null && name.startsWith("org.springframework.integration")) {
      Object target = endpoint;
      if (endpoint instanceof Advised) {
        TargetSource targetSource = ((Advised) endpoint).getTargetSource();
        if (targetSource != null) {
          try {
            target = targetSource.getTarget();
          } catch (Exception e) {
            logger.debug("Could not get handler from bean = " + name);
          }
        }
      }

      Object outputChannel = null;
      if (target instanceof MessagingGatewaySupport) {
        outputChannel = ((MessagingGatewaySupport) target).getRequestChannel();
      } else {
        outputChannel = getField(target, "outputChannel");
      }

      if (outputChannel != null) {
        if (!this.anonymousSourceCounters.containsKey(outputChannel)) {
          this.anonymousSourceCounters.put(outputChannel, new AtomicLong());
        }
        AtomicLong count = this.anonymousSourceCounters.get(outputChannel);
        long total = count.incrementAndGet();
        String suffix = "";
        /*
         * Short hack to makes sure object names are unique if more than one endpoint has the same input channel
         */
        if (total > 1) {
          suffix = "#" + total;
        }
        name = outputChannel + suffix;
        source = "anonymous";
      }
    }

    if (endpoint instanceof Lifecycle) {
      // Wrap the monitor in a lifecycle so it exposes the start/stop operations
      if (endpoint instanceof TrackableComponent) {
        if (monitor instanceof MessageSourceManagement) {
          result =
              new LifecycleTrackableMessageSourceManagement(
                  (Lifecycle) endpoint, (MessageSourceManagement) monitor);
        } else {
          result = new LifecycleTrackableMessageSourceMetrics((Lifecycle) endpoint, monitor);
        }
      } else {
        if (monitor instanceof MessageSourceManagement) {
          result =
              new LifecycleMessageSourceManagement(
                  (Lifecycle) endpoint, (MessageSourceManagement) monitor);
        } else {
          result = new LifecycleMessageSourceMetrics((Lifecycle) endpoint, monitor);
        }
      }
    }

    if (name == null) {
      name = monitor.toString();
      source = "source";
    }

    if (endpointName != null) {
      this.beansByEndpointName.put(name, endpointName);
    }

    monitor.setManagedType(source);
    monitor.setManagedName(name);

    return result;
  }
  /**
   * Implementation of <code>InvocationHandler.invoke</code>.
   *
   * <p>Callers will see exactly the exception thrown by the target, unless a hook method throws an
   * exception.
   */
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation = null;
    Object oldProxy = null;
    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;
    Class targetClass = null;
    Object target = null;

    try {
      if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
        // The target does not implement the equals(Object) method itself.
        return (equals(args[0]) ? Boolean.TRUE : Boolean.FALSE);
      }
      if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
        // The target does not implement the hashCode() method itself.
        return new Integer(hashCode());
      }
      if (!this.advised.opaque
          && method.getDeclaringClass().isInterface()
          && method.getDeclaringClass().isAssignableFrom(Advised.class)) {
        // Service invocations on ProxyConfig with the proxy config...
        return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      }

      Object retVal = null;

      if (this.advised.exposeProxy) {
        // Make invocation available if necessary.
        oldProxy = AopContext.setCurrentProxy(proxy);
        setProxyContext = true;
      }

      // May be <code>null</code>. Get as late as possible to minimize the time we "own" the target,
      // in case it comes from a pool.
      target = targetSource.getTarget();
      if (target != null) {
        targetClass = target.getClass();
      }

      // Get the interception chain for this method.
      List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      // Check whether we have any advice. If we don't, we can fallback on direct
      // reflective invocation of the target, and avoid creating a MethodInvocation.
      if (chain.isEmpty()) {
        // We can skip creating a MethodInvocation: just invoke the target directly
        // Note that the final invoker must be an InvokerInterceptor so we know it does
        // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
        retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
      } else {
        // We need to create a method invocation...
        invocation =
            new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
        // Proceed to the joinpoint through the interceptor chain.
        retVal = invocation.proceed();
      }

      // Massage return value if necessary.
      if (retVal != null
          && retVal == target
          && method.getReturnType().isInstance(proxy)
          && !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
        // Special case: it returned "this" and the return type of the method
        // is type-compatible. Note that we can't help if the target sets
        // a reference to itself in another returned object.
        retVal = proxy;
      }
      return retVal;
    } finally {
      if (target != null && !targetSource.isStatic()) {
        // Must have come from TargetSource.
        targetSource.releaseTarget(target);
      }
      if (setProxyContext) {
        // Restore old proxy.
        AopContext.setCurrentProxy(oldProxy);
      }
    }
  }