码迷,mamicode.com
首页 > 编程语言 > 详细

自定义Spring动态代理类型

时间:2015-08-27 18:54:18      阅读:1134      评论:0      收藏:0      [点我收藏+]

标签:spring   cglib   aop   

最近需要需要统计每一个节点memcache的命中、并发、超时情况。

memcache client选择的xmemcached

<dependency>
     <groupId>com.googlecode.xmemcached</groupId>
     <artifactId>xmemcached</artifactId>
     <version>2.0.0</version>
</dependency>

很容易想到@Aspect来解决。

@Aspect
@Configuration
public class MemcacheClientAspect {

@Around("execution(public * net.rubyeye.xmemcached.MemcachedClient.*(..)) ")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

    ...

但是加入代码后,Unable to proxy method

...
14:30:29,103  INFO  [org.springframework.aop.framework.CglibAopProxy.doValidateClass(CglibAopProxy.java:264)] Unable to proxy method [public final boolean net.rubyeye.xmemcached.XMemcachedClient.isShutdown()] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
14:30:29,104  INFO  [org.springframework.aop.framework.CglibAopProxy.doValidateClass(CglibAopProxy.java:264)] Unable to proxy method [private final void net.rubyeye.xmemcached.XMemcachedClient.registerMBean()] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
14:30:29,106  INFO  [org.springframework.aop.framework.CglibAopProxy.doValidateClass(CglibAopProxy.java:264)] Unable to proxy method [public final java.util.Map net.rubyeye.xmemcached.XMemcachedClient.getStats() throws net.rubyeye.xmemcached.exception.MemcachedException,java.lang.InterruptedException,java.util.concurrent.TimeoutException] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
14:30:29,107  INFO  [org.springframework.aop.framework.CglibAopProxy.doValidateClass(CglibAopProxy.java:264)] Unable to proxy method [public final net.rubyeye.xmemcached.GetsResponse net.rubyeye.xmemcached.XMemcachedClient.gets(java.lang.String,long,net.rubyeye.xmemcached.transcoders.Transcoder) throws java.util.concurrent.TimeoutException,java.lang.InterruptedException,net.rubyeye.xmemcached.exception.MemcachedException] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
14:30:29,109  INFO  [org.springframework.aop.framework.CglibAopProxy.doValidateClass(CglibAopProxy.java:264)] Unable to proxy method [public final net.rubyeye.xmemcached.GetsResponse net.rubyeye.xmemcached.XMemcachedClient.gets(java.lang.String) throws java.util.concurrent.TimeoutException,java.lang.InterruptedException,net.rubyeye.xmemcached.exception.MemcachedException] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
14:30:29,110  INFO  [org.springframework.aop.framework.CglibAopProxy.doValidateClass(CglibAopProxy.java:264)] Unable to proxy method [public final net.rubyeye.xmemcached.GetsResponse net.rubyeye.xmemcached.XMemcachedClient.gets(java.lang.String,long) throws java.util.concurrent.TimeoutException,java.lang.InterruptedException,net.rubyeye.xmemcached.exception.MemcachedException] because it is final: All calls to this method via a proxy will NOT be routed to the target instance.
...

Spring对AOP的支持有几种
- 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
- 如果目标对象没有实现了接口,必须采用CGLIB代理

看下createAopProxy的源码

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()) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }

    ...

Spring会自动在JDK动态代理和CGLIB之间转换,但是,但是,

package net.rubyeye.xmemcached;

import ...

/**
 * The memcached client‘s interface
 * 
 * @author dennis
 * 
 */
public interface MemcachedClient {

MemcachedClient是接口啊,是interface 没错啊,怎么就告诉我

because it is final: All calls to this method via a proxy will NOT be routed to the target instance.

那么这有接口的情况下用的是CglibAopProxy,为什么呢?因为历史原因,多处配置是这样的。

<aop:aspectj-autoproxy proxy-target-class="true" />

自动转换仅仅在

<aop:aspectj-autoproxy/>
<aop:aspectj-autoproxy proxy-target-class="false" />

历史原因的一些东西不能改的。默认情况下 proxy-target-classfalse。Spring会自动选择代理方式。想代理XMemcachedClient,由于其实现的方法几乎都加了final,cglib的方式是不可行的,只能选择JdkDynamicAopProxy的方式。

那么就得修改配置,但是,基本没提供什么可供修改的配置。看看代理的建立方式:

    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        AnnotationAttributes enableAJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }
    }

注意看forceAutoProxyCreatorToUseClassProxying ,只要有一个地方配置了 proxyTargetClass全部强制使用CglibAopProxy代理方式。

但是XMemcachedClient只能使用 JdkDynamicAopProxy ,因为实现都是final。由于ProxyFactory是单例的,只能在针对XMemcachedClient在创建一个了。

@Configuration
public class MemcacheClientJDKAspect {

    @Bean
    public MemcacheInterceptor memcacheInterceptor(){
        return new MemcacheInterceptor();
    }

    public MemcachedClient buildBean(MemcachedClient memcachedClient){
        //pointcut-ref
        AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression("execution(public * net.rubyeye.xmemcached.MemcachedClient.*(..))");

        Advisor advisor = new DefaultPointcutAdvisor(aspectJExpressionPointcut,memcacheInterceptor());

        ProxyFactory memcachedClientProxyFactory = new ProxyFactory(memcachedClient);
        memcachedClientProxyFactory.addAdvisor(advisor);
        memcachedClientProxyFactory.addAdvice(memcacheInterceptor());
        memcachedClientProxyFactory.setProxyTargetClass(false);

        return (MemcachedClient) memcachedClientProxyFactory.getProxy();
    }

}

这样,目的达到了。

版权声明:本文为博主原创文章,未经博主允许不得转载。

自定义Spring动态代理类型

标签:spring   cglib   aop   

原文地址:http://blog.csdn.net/wh_ouyangshuang/article/details/48027313

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!