JDK代理、CGLIB代理及静态代理

版权声明:欢迎分享转载 我可能会失败,但我不会一直失败 https://blog.csdn.net/u012637358/article/details/80321677

代理模式定义

代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法、实际执行的是被代理类的方法。

引用网上代理模式结构图

这里写图片描述

代理的分类

  • 静态代理:

    代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理。

  • JDK代理:
    JDK动态代理只能对实现了接口的类生成代理,而不能针对类

  • CGLIB代理:
    CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

代码实现

ICount.java

package com.xzsyr.statiz.proxy;

/**
 * Title: ICount.java Description: 账号接口
 * 
 * @author jizhuang.wang
 * @created 2018年5月10日 下午4:36:10
 */
public interface ICount {

    /**
     * @discription 查询账号列表
     * @author jizhuang.wang
     * @created 2018年5月10日 下午4:36:54
     */
    public void queryCount();
}

CountImpl.java

/**        
 * Title: CountImpl.java    
 * Description: 账号信息实现类
 * @author jizhuang.wang       
 * @created 2018年5月10日 下午4:37:40    
 */

public class CountImpl implements ICount{


    /** 
     * @discription 在此输入一句话描述作用
     * @author jizhuang.wang       
     * @created 2018年5月10日 下午4:37:54           
     * @see com.xzsyr.statiz.proxy.ICount#queryCount()     
     */  

    @Override
    public void queryCount() {
         System.out.println("我是queryCount方法.");     
    }

}

CountProxyImpl.java

package com.xzsyr.statiz.proxy;


/**        
 * Title: CountProxyImpl.java    
 * Description: 账号信息代理实现类
 * @author jizhuang.wang       
 * @created 2018年5月10日 下午4:39:37    
 */

public class CountProxyImpl implements ICount{

     private CountImpl count; 
    /** 
     * @discription 账号信息查询
     * @author jizhuang.wang       
     * @created 2018年5月10日 下午4:40:31           
     * @see com.xzsyr.statiz.proxy.ICount#queryCount()     
     */  

    @Override
    public void queryCount() {

        System.out.println("事务处理前.....");
        count.queryCount();
        System.out.println("事务处理后.....");
    }

    public CountProxyImpl(CountImpl count) {
        super();
        this.count = count;
    }

}

StaticMain.java

package com.xzsyr.statiz.proxy;

/**
 * @author Stronger
 *
 */
public class StaticMain {
  public static void main(String[] args) {
    CountImpl c = new CountImpl();
    CountProxyImpl p = new CountProxyImpl(c);
    p.queryCount();

}
}

静态代理执行结果

事务处理前…..
我是queryCount方法.
事务处理后…..

  • JDK代理

ICount.java

/**
 * Title: ICount.java Description: 账号接口
 * 目标类接口 
 * 目标类和动态生成的代理对象都实现的接口
 * @author jizhuang.wang
 * @created 2018年5月10日 下午4:36:10
 */
public interface ICount {

    /**
     * @discription 查询账号列表
     * @author jizhuang.wang
     * @created 2018年5月10日 下午4:36:54
     */
    public void queryCount();
}

CountImpl.java

/**
 * @author Stronger
 *
 */
public class CountImpl implements ICount{

    /* (non-Javadoc)
     * @see com.xzsyr.jdkdy.proxy.ICount#queryCount()
     */
    @Override
    public void queryCount() {

        System.out.println("我是queryCount方法");
    }

}

CountImpl.java

package com.xzsyr.jdkdy.proxy;

/**
 * @author jizhuang.wang
 *
 */
public class CountImpl implements ICount{

    /* (non-Javadoc)
     * @see com.xzsyr.jdkdy.proxy.ICount#queryCount()
     */
    @Override
    public void queryCount() {

        System.out.println("我是queryCount方法");
    }

}

MyInvocationHandler.java

package com.xzsyr.jdkdy.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**        
 * Title: MyInvocationHandler.java    
 * Description: JDK动态代理类
 * 代理对象的拦截器  
 * @author jizhuang.wang       
 * @created 2018年5月10日 下午5:00:41    
 */

public class MyInvocationHandler implements InvocationHandler{
    private CountImpl countImpl;


    /**
     * 构造函数
     * @param countImpl 被代理对象
     */
    public MyInvocationHandler(CountImpl countImpl) {
    //  super();
        this.countImpl = countImpl;
    }


    /** 
     * @discription 在此输入一句话描述作用
     * @author jizhuang.wang       
     * @created 2018年5月10日 下午5:01:22      
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable     
     * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])     
     */  

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("事务处理前。。。。");
         method.invoke(countImpl, args);
         System.out.println("事务处理后。。。。");
        return null;
    }

}

JDKMain.java

package com.xzsyr.jdkdy.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * @author jizhuang.wang
 *
 */
public class JDKMain {
    public static void main(String[] args) {
        CountImpl count = new CountImpl();
        count.queryCount();
        System.out.println("==========================================");
        /** 
         * 以下代码会生成一个$Proxy对象,该对象实现了ICount接口,具体的方法体就是InvocationHandler里面的invoke方法。 
         */ 
        InvocationHandler  hander = new MyInvocationHandler(count);
        ICount proxyInstance = (ICount) Proxy.newProxyInstance(count.getClass().getClassLoader(), count.getClass().getInterfaces(), hander);
        proxyInstance.queryCount();
    }
}

JDK动态代理执行结果

我是queryCount方法
事务处理前。。。。
我是queryCount方法
事务处理后。。。。

  • CGLib代理
    ICount.java
package com.xzsyr.cglibdy.proxy;

/**
 * Title: ICount.java Description: 账号接口
 * 
 * @author jizhuang.wang
 * @created 2018年5月10日 下午4:36:10
 */
public class ICount {

    /**
     * @discription 查询账号列表
     * @author jizhuang.wang
     * @created 2018年5月10日 下午4:36:54
     */
    public void queryCount() {
        System.out.println("账户类查询方法");
    }
}

CountImpl.java

package com.xzsyr.cglibdy.proxy;



/**
 * @author jizhuang.wang
 *
 */
public class CountImpl {

public void quryCount(){
    System.out.println("查询querycount方法");
}
}

CountImplCglib.java

package com.xzsyr.cglibdy.proxy;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * @author jizhuang.wang
 *
 */
public class CountImplCglib implements MethodInterceptor{
    ///业务类对象,供代理方法中进行真正的业务方法调用
    private Object target;

    //相当于JDK动态代理中的绑定
    public Object getInstance(Object target){
         //创建加强器,用来创建动态代理类
         this.target = target; 
          //创建加强器,用来创建动态代理类
         Enhancer enhancer = new Enhancer();
         //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
         enhancer.setSuperclass(this.target.getClass());  
         //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
         enhancer.setCallback(this); 
        // 创建动态代理类对象并返回  
        return enhancer.create(); 
    }
   // 实现回调方法 
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("预处理——————");
        proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法
        System.out.println("调用后操作——————");
        return null;
    }

}

CGLIBMain.java

package com.xzsyr.cglibdy.proxy;

/**
 * @author jizhuang.wang
 *
 */
public class CGLIBMain {
 public static void main(String[] args) {
    CountImpl c = new CountImpl();
    CountImplCglib cglib = new CountImplCglib();
    CountImpl ccglib = (CountImpl) cglib.getInstance(c);
    ccglib.quryCount();
}
}

CGLIB动态代理执行结果

预处理——————
查询querycount方法
调用后操作——————


而AOP,是通过动态代理实现的。

  • Spring在选择用JDK还是CGLiB的依据

    (1)当Bean实现接口时,Spring就会用JDK的动态代理
    (2)当Bean没有实现接口时,Spring使用CGlib是实现
    (3)可以强制使用CGlib
    (在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)
    
  • CGlib与JDK比较(参考)
    (1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。
    (2)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。
     


关于cglib代理编码依赖包说明
cglib必须依赖一下jar:

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
<dependency>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm</artifactId>
    <version>5.0.4</version>
</dependency>

使用CGlib出现java.lang.NoClassDefFoundError: org/objectweb/asm/Type异常
报错显示有找不到的类,上网查了以下知道了很多java字节码操作和分析的第三方类库都引用了asm.jar文件,由于工程不是Maven管理的,无法解决以来传递问题,所以要手动引入asm.jar文件。把asm.jar文件添加到项目路径类,运行,然后就正常了。

非maven项目
cglib.jar下载
asm.jar下载
https://github.com/xzsyr/craft-cloud/tree/master/repo

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页