标签:
一、静态代理:
假设原来有一个实现了指定接口/抽象类的子类:
class RealSubject implements Subject{  
    public void request(){  
        System.out.print("real request handling\n");  
    }  
} 现在有两种情况会发生:
1新的代码需要调用Subject接口,但是需要给每个接口加入新代码(比如日志记录、权限控制等);
2旧的代码已经使用了Subject接口,需要不改动现有代码情况下加入新的代码(比如日志记录,权限控制);
对于这这两种情况,最直接的想法就是重新写一个代理类,同样实现Subject接口,针对RealSubject的所有接口进行封装,加入新的代码:
/************************************************ 
 * 静态代理,封装(控制)request方法的访问  
 ************************************************/  
class StaticProxySubject implements Subject{  
    private RealSubject realSubject;    //组合被代理的对象  
    public void request(){  
        //do some thing else...  
        if(realSubject == null){  
            realSubject = new RealSubject();  
        }  
        realSubject.request();          //真正的request调用  
        //do some thing else...  
    }     1面向Subject接口编程;
2创建Subject实例时采用工厂模式,通过读取配置文件决定反射哪个类的实例;
这样在创建一个新的静态代理时,才可以通过修改配置文件无缝集成到现有代码,修改行为而无需改动现有代码。
//通过静态代理来访问对象 Subject proxy = new StaticProxySubject(); proxy.request();
二、面向方面编程(AOP)
其实上面所说的第二种情况就是实现面向方面的编程的方式之一(将切面代码至于原始方法外面),在不改动现有代码的情况下,为所有业务横向插入公共逻辑(常见的如安全、事务控制、日志等),将交叉业务模块化。
三、动态代理
很明显静态代理有个大问题,就是一旦原始目标类接口过多,要为每个接口进行静态代理封装,那代价也很大。
因此Java中提出一个动态代理的概念,动态代理需要实现Java中的InvocationHandler接口:
/*********************************************************** 
 * 动态代理. java.lang.reflect包中有自己的代理支持,利用这个包 
 * 你可以在运行时动态创建一个代理类,实现一个或者多个接口,并将 
 * 方法的调用转发到你所指定的类。  
 * 因为实际的代理类是在运行时创建的,所以我们称这个技术为动态代理。 
 * ***********************************************************/  
class DynamicProxySubject implements InvocationHandler{  
    private Object realSubject;         //组合被代理的对象  
      
    public DynamicProxySubject(Object realSubject){  
        this.realSubject = realSubject;  
    }  
      
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        //do some thing else...  
        return method.invoke(realSubject, args);  //调用对象realSubject的method方法
        //do some thing else...  
    }  
}  RealSubject real = new RealSubject();  
Subject subject = (Subject) Proxy.newProxyInstance(  
                real.getClass().getClassLoader(),   //定义代理类的类加载器   
                real.getClass().getInterfaces(),    //代理类要实现的接口列表  
                new DynamicProxySubject(real));     //指派方法调用的调用处理程序  
subject.request();  (1)其中最后一个参数是动态代理类对象,组合了其真正要代理的类。
(2)倒数第二个参数需要传递要代理的真正的类的接口信息(Class信息),即Subject接口信息,这样返回的代理就是Subject类型的。
这样每次调用返回的Subject类型代理对象的接口时,都会转换为针对动态代理类中invoke方法的调用,在invoke方法中又调用真正代理的类的方法,我们可以将横切代码(日志、权限控制等)至于invoke方法中实现AOP。
四、动态代理原理
关键在于创建动态代理的newProxyInstance方法:
RealSubject real = new RealSubject();  
Subject subject = (Subject) Proxy.newProxyInstance(  
                real.getClass().getClassLoader(),   //定义代理类的类加载器   
                real.getClass().getInterfaces(),    //代理类要实现的接口列表  
                new DynamicProxySubject(real));     //指派方法调用的调用处理程序  
subject.request();  倒数第二个参数是要代理的类的接口(Subject)的Class对象。第三个参数是动态代理类。
newProxyInstance方法返回一个类对象,该类实现了Subject接口,同时继承自JavaProxy类:
classProxy{ 
    InvocationHandler h=null; 
    protected Proxy(InvocationHandler h) { 
        this.h = h; 
    } 
    ... 
}这个自动生成的类为什么能够实现Subject接口,答案是反射机制。
通过反射可以知道该接口所有方法,然后重写这些方法,简单地调用父类Proxy的动态代理属性的invoke方法即可。
publicfinal void request() { 
        try { 
            super.h.invoke(this,m3, null); 
            return; 
        } catch (Error e) { 
        } catch (Throwable throwable) { 
            throw newUndeclaredThrowableException(throwable); 
        } 
 
    }标签:
原文地址:http://blog.csdn.net/jiyiqinlovexx/article/details/46667035