zoukankan      html  css  js  c++  java
  • JAVA的动态代理


    代理模式 
    代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。 
    按照代理的创建时期,代理类可以分为两种。 
    静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
    动态代理:在程序运行时,运用反射机制动态创建而成。 

    静态代理:

    interface IBase{
    	public void dosomething();
    	public void doelsething(); 
    }
    class Derived implements IBase{
    	@Override
    	public void dosomething() {
    		System.out.println("Derived dosomething");
    	}
    	@Override
    	public void doelsething() {
    		System.out.println("Derived doelsething");
    	}
    }
    
    //声明代理类
    class TestProxy implements IBase{
    	//委托类
    	private IBase iBase ;
    	public TestProxy(IBase iBase) {
    		this.iBase = iBase;
    	}
    	@Override
    	public void dosomething() {
    		System.out.println("代理类开始执行dosomething");
    		iBase.doelsething();
    		System.out.println("代理类结束执行dosomething");
    	}
    	@Override
    	public void doelsething() {
    		System.out.println("代理类开始执行doelsething");
    		iBase.doelsething();
    		System.out.println("代理类结束执行doelsething");	
    	}	
    }
    
    public class Test {
    	public static void main(String[] args) {
    		TestProxy testProxy = new TestProxy(new Derived());
    		testProxy.dosomething();
    		testProxy.doelsething();
    	}
    }
    
    
    输出:
    
    代理类开始执行dosomething
    Derived doelsething
    代理类结束执行dosomething
    代理类开始执行doelsething
    Derived doelsething
    代理类结束执行doelsething
    

      

    观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 

    JDK动态代理中包含一个类和一个接口: 

    InvocationHandler接口: 
    public interface InvocationHandler { 
        public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; 
    } 
    

    参数说明: 
    Object proxy:指被代理的对象。 
    Method method:要调用的方法 
    Object[] args:方法调用时所需要的参数 

    可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。 

    Proxy类: 
    Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法: 
    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
    InvocationHandler h) 
                                   throws IllegalArgumentException 
    参数说明: 
    ClassLoader loader:类加载器 
    Class<?>[] interfaces:得到全部的接口 
    InvocationHandler h:得到InvocationHandler接口的子类实例 

    Ps:类加载器 
    在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; 
    Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; 
    Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jrelibext目录中的类; 
    AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 

    动态代理 
    与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    interface IBase{
    	public void dosomething();
    	public void doelsething(); 
    }
    interface IBase2{
    	public void dodo();
    }
    class Derived implements IBase,IBase2{
    	@Override
    	public void dosomething() {
    		System.out.println("Derived dosomething");
    	}
    	@Override
    	public void doelsething() {
    		System.out.println("Derived doelsething");
    	}
    	@Override
    	public void dodo() {
    		System.out.println("Derived dodo");
    	}
    }
    
    class Derived2 implements IBase{
    
    	@Override
    	public void dosomething() {
    		System.out.println("Derived2 dosomething");
    	}
    
    	@Override
    	public void doelsething() {
    		System.out.println("Derived2 doelsething");
    	}
    	
    }
    //声明代理类
    class TestProxy implements InvocationHandler{
    	private Object target; //委托类
    	//绑定生成代理对象
    	public Object bind(Object target){
    		this.target = target;
    		return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
    	}
    	@Override
    	public Object invoke(Object proxy, Method method, Object[] args)
    			throws Throwable {
    		Object result = null;
    		System.out.println("事物开始。。。。");
    		result = method.invoke(this.target, args);
    		System.out.println("事务结束......");
    		return result;
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		TestProxy proxy = new TestProxy();
    		
    		IBase iBase = (IBase)proxy.bind(new Derived());
    		iBase.dosomething();
    		iBase.doelsething();
    	
    		IBase2 base2 = (IBase2)proxy.bind(new Derived());
    		base2.dodo();
    		
    		iBase = (IBase)proxy.bind(new Derived2());
    		iBase.dosomething();
    		iBase.doelsething();
    		
    	}
    }
    

      

    但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。 

    Cglib动态代理 
    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 

    这里不做介绍。。。

    参考:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

  • 相关阅读:
    Spring Security 记住我功能 详解
    浅谈前端SPA(单页面应用)
    Token问什么可以避免CSRF/XSRF?
    总结 XSS 与 CSRF 两种跨站攻击
    localStorage,sessionStorage和cookie的区别及使用
    cookie,token验证的区别
    彻底弄懂session,cookie,token
    HTTP cookies 详解
    纯css3实现文字间歇滚动效果
    我的less学习之路
  • 原文地址:https://www.cnblogs.com/E-star/p/3436266.html
Copyright © 2011-2022 走看看