关于JDK动态代理方法的调用

为什么想到这个?来源于http://blog.csdn.net/y943623901/article/details/50847334

这篇文章关于JDK动态代理的演示让我有点迷惑,又重新看了下动态代理

1.首先JDK动态代理是针对接口的,
用提供的被代理对象获得该对象所有实现了的接口,重新生成的一个类

针对这个,像spring注解事务应该放在接口的方法上,这个代理类实现接口方法时是可以获得接口上方法的注释的

2.仔细想,在invoke方法里执行method.invoke(target, args),即使里面有嵌套方法,也是通过target对象调用的,而不是代理对象,所以嵌套方法上的事务注解是无效的

3.为什么CGLIB里的嵌套方法有效

// CGLIB代理类具体实现
public class HelloConcrete$$EnhancerByCGLIB$$e3734e52  extends HelloConcrete
  implements Factory
{
  ...
  private MethodInterceptor CGLIB$CALLBACK_0; // ~~
  ...
   
  public final String sayHello(String paramString)
  {
    ...
    MethodInterceptor tmp17_14 = CGLIB$CALLBACK_0;
    if (tmp17_14 != null) {
      // 将请求转发给MethodInterceptor.intercept()方法。
      return (String)tmp17_14.intercept(this, 
              CGLIB$sayHello$0$Method, 
              new Object[] { paramString }, 
              CGLIB$sayHello$0$Proxy);
    }
    return super.sayHello(paramString);
  }
  ...
public class BookFacadeCglib implements MethodInterceptor {  
	   
    private Object target;  
   
    /** 
    * 创建代理对象 
    *  
    * @param target 
    * @return 
    */  
    public Object getInstance(Object target) {  
       this.target = target;  
       Enhancer enhancer = new Enhancer();  
       enhancer.setSuperclass(this.target.getClass());  
       // 回调方法  
       enhancer.setCallback(this);  
       // 创建代理对象  
       return enhancer.create();  
    }  
   
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {  
       Annotation annotation = obj.getClass()  
                                  .getSuperclass()  
                                  .getDeclaredMethod(method.getName(), method.getParameterTypes())  
                                  .getAnnotation(Transaction.class);  
       System.out.println("invoke");  
       if (annotation == null) {  
           proxy.invoke(target, args);  
       } else {  
           System.out.println("事务开始");  
           proxy.invokeSuper(obj, args);  //这里明显去调用object父类也就是被代理对象的方法
           System.out.println("事务结束");  
       }  
       return null;  
    }

}  
可以看到,CGLIB生成的类为原始类的子类,第一次经过的方法会打印一次invoke,然后调用原对象方法,如果这个方法里又嵌套了方法,这时,子类也复写了这个方法,所以仍然通过代理对象调用,所以会再走一次invoke


4.我们在自定义连接池,创建时动态代理要求用这种new Class[]{Connection.class} 方式获取接口集合,原因在于,数据库驱动返回的connection对象继承了某个类,而这个类或这个类的父类之前实现的接口通过connection对象的getInterfaces()是获取不到的,可以测试下,那么问题来到了,如果这个Class数组是个空数组,创建的代理对象是怎样的

// 对con创建其代理对象

Connection proxy = (Connection) Proxy.newProxyInstance(con.getClass().getClassLoader(),    // 类加载器

//con.getClass().getInterfaces(),  

new Class[]{Connection.class},      // 目标对象实现的接口

new InvocationHandler() {

	for(Class c:con.getClass().getInterfaces())
		{
		  System.out.println(c);
		}       

    System.out.println(con.getClass().getInterfaces().length);// 这边输出是0 

})


4.具体不做分析,主要追究代理对象生成的源码,一般情况下,interface[]length不为0,生成的代理类如下


而,像connection这种集合为0的情况,生成的类,只会$Proxy0 extends Proxy ,不实现任何接口,这样自然不能像接口转型,会报cast异常


main方法中加入System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"),这样就会把生成的代理类Class文件保存在本地磁盘上,然后再反编译可以得到代理类的源码


System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");  --该设置用于输出cglib动态代理产生的类
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");   --该设置用于输出jdk动态代理产生的类

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值