java動態代理實現Proxy和InvocationHandler cglib




概念:java

靜態代理:由程序員建立或特定工具自動生成源代碼,再對其編譯。在程序運行前,代理類的.class文件就已經存在了。 
動態代理:在程序運行時,運用反射機制動態建立而成。
程序員


JDK的動態代理用起來很是簡單,當它有一個限制,就是使用動態代理的對象必須實現一個或多個接口。若是想代理沒有實現接口的繼承的類,該怎麼辦?如今咱們能夠使用CGLIB包。spring



JDK動態代理實現
app

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;


public class ProxyTest {
    static StringBuilder sBuilder=new StringBuilder();
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        
        //代理類字節碼
Class clazzProxy1=    Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
//代理類構造方法列表,沒有無參構造方法
System.out.println("...........begin constructors list............");
    Constructor[] constructors= clazzProxy1.getConstructors();
     for(Constructor constructor:constructors){
         StringBuilder sBuilder=new StringBuilder();
        sBuilder.append(constructor.getName()).append("(");
        Class[] clazzparams =constructor.getParameterTypes();
    
        for(Class clazzparam:clazzparams){
            
            sBuilder.append(clazzparam.getName()).append(",");
            
        }
        
        if(clazzparams.length!=0){
            
            sBuilder.deleteCharAt(sBuilder.length()-1);
        }
        sBuilder.append(")");
        System.out.println( sBuilder.toString());
     }
    
    //代理類方法列表
    System.out.println("...........begin methods list............");
     
    Method[] methods= clazzProxy1.getMethods();
     for(Method method:methods){
         StringBuilder sBuilder=new StringBuilder();
        sBuilder.append(method.getName()).append("(");
        Class[] clazzparams =method.getParameterTypes();
    
        for(Class clazzparam:clazzparams){
            
            sBuilder.append(clazzparam.getName()).append(",");
            
        }
        
        if(clazzparams.length!=0){
            
            sBuilder.deleteCharAt(sBuilder.length()-1);
        }
        sBuilder.append(")");
        System.out.println( sBuilder.toString());
     }
     
     //經過字節碼建立代理類的實例,不能用newInstance(),構造方法傳入InvocationHandler
     System.out.println("...........begin create instance object............");
    
        Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class);
        
    Collection proxy1=    (Collection) constructor.newInstance(new InvocationHandler(){

            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                
                return null;
            }
            
        });
        
    System.out.println(proxy1);
    proxy1.clear();//無返回值的方法成功

    //一步到位建立代理類實例
    Collection proxy2=(Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),new Class[]{Collection.class}, new InvocationHandler(){
        ArrayList target=new ArrayList<>();//被代理對象,目標對象
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            
            long begintime=System.currentTimeMillis();
            Object retVal=method.invoke(target, args);
            long endtime=System.currentTimeMillis();
            System.out.println(method.getName()+" running time is " +(endtime-begintime));
            return retVal;
        }
        
    });
    
    proxy2.add("lhm");
    proxy2.add("zxx");
    proxy2.add("bxd");
    System.out.println(proxy2.size());
    System.out.println(proxy2.getClass().getName());
    }
        
    
    
    
}


CGLIB(CODE GENERLIZE LIBRARY)代理是針對類實現代理,ide

主要是對指定的類生成一個子類覆蓋其中的全部方法,因此該類或方法不能聲明稱final的。工具


spring中Aspect動態代理設置
ui

Spring提供了兩種方式來生成代理對象: JDKProxy和Cglib,具體使用哪一種方式生成由AopProxyFactory根據AdvisedSupport對象的配置來決定。spa

默認的策略是若是目標類是接口,則使用JDK動態代理技術,若是目標對象沒有實現接口,則默認會採用CGLIB代理。代理

若是目標對象實現了接口,能夠強制使用CGLIB實現代理(添加CGLIB庫,並在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。對象

相關文章
相關標籤/搜索