zoukankan      html  css  js  c++  java
  • 动态代理双剑客--JDK Proxy与CGLIB

     

    背景:


    研究过设计模式的同胞们都知道代理模式可以有两种实现方案:


    1.接口实现(或继承抽象类)

     

    核心代码片段

    ProxySubject-->>doOperation()

     

    //dosomething before
    realSubject.doOperation()
    //dosomething after

     

    2.继承父类


    核心代码片段

    ProxySubject-->>doOperation()

     

    //dosomething before
    super.doOperation()
    //dosomething after

    总结:

    相同点

    都可以通过Proxy控制对Target的访问

    不同点

    1.灵活性

    “接口实现”的方式更加灵活,代理类可以代理所有实现了ISubject接口的类;

    “继承父类”的方式代理类只能代理它的父类,因为java中只支持单继承

    2.可行性

    如果Target有直接接口,那么这两种方式都可以;

    如果没有实现任何接口,那只能采取“继承父类”的方式了

     



    正文


    Java中动态代理对应着也有两种实现方式


    1.“接口实现"---JDK Proxy

    用到JDK提供的InvocationHandler接口和Proxy


    类之间的关系如下

    InvocationHandler接口

    用于处理方法请求

    Proxy

    用于生成代理对象


    代码演示

    ISubject接口

     

    public interface ISubject {
    	
    	public void showName(String name);
    }
    

    RealSubject

    public class RealSubject implements ISubject {
    
    	@Override
    	public void showName(String name) {
    		System.out.println(name+"闪亮登场");
    	}
    
    }
    

    LogHandler

    为了更明确的说明动态代理的工作原理,将代理的创建过程放到了LogHandler的外部,即main方法中

    public class LogHandler implements InvocationHandler {
    
    	Object target=null;
    	
    	public Object getTarget() {
    		return target;
    	}
    
    	public void setTarget(Object target) {
    		this.target = target;
    	}
    
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		Object result=null;
    		//调用目标对象方法前的逻辑
    		System.out.println("下面有一个大人物要出现");
    		//调用目标对象的方法,这句代码将代理与目标类联系了起来
    		method.invoke(target, args);
    		//调用目标对象方法后的逻辑
    		System.out.println("大家鼓掌欢迎");
    		return result;
    				
    	}
    
    }



    客户端 类Client

     

    public class Client {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		
    		LogHandler logHandler=new LogHandler();
    		logHandler.setTarget(new RealSubject());
    		//创建代理对象
    		ISubject proxySubject=(ISubject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), logHandler);
    		System.out.println("-------JDK Proxy-------------");
    		proxySubject.showName("委座");
    
    	}
    
    }
    

    执行结果


     

    调用过程时序图



     



    2.“继承父类”---CGLIB

    用到了CBLIB提供的Enhancer类和MethodInterceptor接口 


    类之间的关系如下

    需要引入第三方jar包

     

    • cglib-2.2.jar
    • asm-3.1.jar

     

    Enhancer

    用于创建代理对象

    MethodInterceptor接口

    用于处理方法请求

     

    代码演示

    ISubject接口,RealSubject类同上

     

    LogIntercept类

    public class LogIntercept implements MethodInterceptor {
    	Object target=null;
    	
    	public Object getTarget() {
    		return target;
    	}
    
    	public void setTarget(Object target) {
    		this.target = target;
    	}
    	
    	@Override
    	public Object intercept(Object arg0, Method arg1, Object[] arg2,
    			MethodProxy arg3) throws Throwable {
    		
    		Object result=null;
    		//调用目标对象方法前的逻辑
    		System.out.println("下面有一个大人物要出现");
    		//调用目标对象的方法,这句代码将代理与目标类联系了起来
    		arg3.invoke(target, arg2);
    		//调用目标对象方法后的逻辑
    		System.out.println("大家鼓掌欢迎");
    		return result;
    	}
    
    }



    客户端类Client

    public class Client {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		
    		LogIntercept logIntercept=new LogIntercept();
    		logIntercept.setTarget(new RealSubject());
    		Enhancer enhancer=new Enhancer();
    		enhancer.setSuperclass(RealSubject.class);
    		enhancer.setCallback(logIntercept);
    		
    		ISubject proxySubject=(ISubject)enhancer.create();
    		System.out.println("-------CBLIB-------------");
    		proxySubject.showName("委座");
    
    	}
    
    }
    



    调用过程时序图



    总结

    大家可以看到JDK ProxyCGLIB这两种动态代理的实现过程是非常相似的,但也有区别

    相同点:

    • 都用到了一个接口一个类;
    • 接口用于处理方法调用,类用于创建代理对象

    JDK Proxy

    InvocationHandler接口

    Proxy

    CGLIB

    MethodIntercept接口

    Enhancer

    不同点:

    JDK Proxy

    使用目标类的接口创建动态代理

    CBLIB

    使用目标类的子类创建动态代理

     

    最后

              JDK ProxyCGLIB两种动态代理各有千秋,具体用哪个方案要看具体情况。如果目标类实现了对应接口,两种方案都可以;如果没有实现任何接口则要使用CBLIB比如Hibernate中的实体类是POJO类,没有实现任何接口,那么要通过代理实现延迟加载就只能采用CGLIB方案了。




  • 相关阅读:
    SortedList的使用示例
    oracle 查询
    sql group by统计
    删除隐藏盘符的隐藏共享,打开隐藏盘符
    【C#】Entity Framework 增删改查和事务操作
    CSS rem长度单位
    HTML 页面meta标签
    VUE 生成二维码(qrcodejs)
    VUE 密码验证与提示
    JavaScript 加解密库(crypto-js)
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3310568.html
Copyright © 2011-2022 走看看