Spring Cloud 动态代理异常处理

代理异常

Caused by: org.springframework.messaging.MessagingException: Exception thrown while invoking com.mmtvip.frontprovider.mq.ReceiverServer#receiveR00001[1 args]; nested exception is java.lang.IllegalStateException: The mapped handler method class 'com.mmtvip.frontprovider.mq.ReceiverServer$$EnhancerBySpringCGLIB$$bd47ad77' is not an instance of the actual endpoint bean class 'com.mmtvip.frontprovider.mq.ReceiverServer$$EnhancerBySpringCGLIB$$7cbf057b'. If the endpoint requires proxying (e.g. due to @Transactional), please use class-based proxying.

出现原因

Spring Aop默认使用的JDK动态代理,而项目中用到了CGLIB代理,产生冲突。

引发问题

1.@scheduled 定时任务不执行

2.@StreamListener 监听报错,MQ消息接收不到。

解决办法

# AOP

# 开启aop(默认为true)
spring.aop.auto=true

# 开启CGLib代理(true:启用cglib代理,false:启用jdk代理,默认为false)
spring.aop.proxy-target-class=true

另外需要在代理类上加@Aspect (作用是把当前类标识为一个切面供容器读取)

 

 

proxy-target-class标签的实现原理

打开Spring-aop包里,META-INF下的spring.handlers

http://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler

AopNamespaceHandler就是aop标签的处理类

public class AopNamespaceHandler extends NamespaceHandlerSupport {

    /**
     * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
     * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
     * and '{@code scoped-proxy}' tags.
     */
    @Override
    public void init() {
        // In 2.0 XSD as well as in 2.1 XSD.
        registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
        registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
        registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());

        // Only in 2.0 XSD: moved to context namespace as of 2.1
        registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
    }

}

AspectJAutoProxyBeanDefinitionParser是aspectj-autoproxy标签的解析类,解析aspectj-autoproxy标签的各个属性

class AspectJAutoProxyBeanDefinitionParser implements BeanDefinitionParser {

    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
        extendBeanDefinition(element, parserContext);
        return null;
    }

继续跟踪AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法

public static void registerAspectJAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {

        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAutoProxyCreatorIfNecessary(
                parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }

    public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(
            ParserContext parserContext, Element sourceElement) {

        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(
                parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }

    private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, Element sourceElement) {
        if (sourceElement != null) {
- [x]           boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
            if (proxyTargetClass) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }
            boolean exposeProxy = Boolean.valueOf(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
            if (exposeProxy) {
                AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
            }
        }
    }

重点看下useClassProxyingIfNecessary方法,

 boolean proxyTargetClass = Boolean.valueOf(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
            if (proxyTargetClass) {
                AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            }

取出proxy-target-class的属性,如果是true,则使用基于Class的代理

  public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }
    }

forceAutoProxyCreatorToUseClassProxying方法会将proxyTargetClass值为true的属性添加到BeanDefinition中,初始化bean的时候,会取出此字段

  public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
        if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
            BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
            definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
        }
    }

打开DefaultAopProxyFactory,createAopProxy方法中,会校验是不是配置了proxyTargetClass为true,如果配置了(config.isProxyTargetClass())就会使用Cglib来创建代理类(ObjenesisCglibAopProxy(config))

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
        Class targetClass = config.getTargetClass();
        if (targetClass == null) {
            throw new AopConfigException("TargetSource cannot determine target class: " +
                    "Either an interface or a target is required for proxy creation.");
        }
        if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
            return new JdkDynamicAopProxy(config);
        }
        return new ObjenesisCglibAopProxy(config);
    }
    else {
        return new JdkDynamicAopProxy(config);
    }
}

 

你可能感兴趣的:(Spring,Cloud)