動態代理和攔截器


一、概述 

1、代理模式是常用的java設計模式,生成一個代理對象,來代替真正的對象,從而控制真實對象的訪問。

        客戶(調用者)----------商務(代理對象)-----------軟件工程師(真正對象)

2、我們需要在調用者調用對象之前就生成一個代理對象,而這個代理對象需要和真正對象建立代理關系

   -----代理對象和真正對象建立關系

   -----實現代理對象的代理邏輯方法

3、常用的代理對象方法:JDK動態代理,CGLIB

二、JDK動態代理

    JDK動態代理所用到的代理類在程序調用到代理類對象時才由JVM真正創建,JVM根據傳進來的 業務實現類對象以及方法名 ,動態地創建了一個代理類的class文件並被字節碼引擎執行,然后通過該代理類對象進行方法調用。

1、需要借助接口生成代理對象

public interface HelloWorld {
    public void sayHelloWorld();
}
public class HelloWorldImp implements HelloWorld{
    @Override
    public void sayHelloWorld() {
        System.out.println("你好");    
    }

}

2、實現代理邏輯類:需要實現java.lang,reflect.InvocationHandler接口,重寫invoke方法

package reflect;

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

import org.junit.Test;

public class JdkProxyExample implements InvocationHandler{
    //真實對象
    private Object target = null;
    //建立關系,返回代理對象
    public Object bind(Object target) {
        this.target = target;    
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),this);        
    }
    
    @Override
    //處理代理實例上的方法調用並返回結果。當在與其關聯的代理實例上調用方法時,將在調用處理程序上調用此方法。
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("調用真實對象服務之前的服務");
        Object obj = method.invoke(target, args);//相當於調用sayHelloWorld()
        System.out.println("調用真實對象服務之后的服務");
        return obj;
    }
    
    @Test
    public void testJdkProxyExample() {
        JdkProxyExample jdkProxyExample = new JdkProxyExample();
        HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImp());
        proxy.sayHelloWorld();
    }
    
}
1、該方法返回指定接口的代理類的實例,該接口將方法調用分派給指定的invocationhandler代理     
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException 
參數:InvocationHandler是由代理實例的調用處理程序實現的接口。每個代理實例都有一個關聯的調用處理程序。當在代理實例上調用方法時,
              方法調用被編碼並發送到其調用處理程序的invokemethod
2、Object invoke(Object proxy, Method method,Object[] args) throws Throwable{}
  處理代理實例上的方法調用並返回結果。當在與其關聯的代理實例上調用方法時,將在調用處理程序上調用此方法。
  參數:
Object proxy :就是newProxyInstance返回的代理對象
     Method method : 當前調度的接口中的方法
    
Object[] args : 調度方法中的參數

通俗點說就是實現java.lang,reflect.InvocationHandler接口,重寫invoke方法,但是重寫invoke()需要給它三個參數
參數一:Object proxy :需要通過newProxyInstance返回的獲取參數proxy

三、CGLIB動態代理

1、cglib是針對類來實現代理的,原理是對指定的業務類生成一個子類,並覆蓋其中業務方法實現代理。因為采用的是繼承,所以不能對final修飾的類進行代理。 

 (1)首先定義一個y業務類Hello

public class Hello {
     public void sayHello() {  
            System.out.println("hello...");  
        }  
}

(2)對指定的業務類生成一個子類,並覆蓋其中業務方法實現代理。

package reflect;

import java.lang.reflect.Method;

import org.junit.Test;

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

public class CGLIBProxyExample implements MethodInterceptor{
    //生成代理對象
    public Object getProxy(Class cls) {
        //增強類
        Enhancer enhance = new Enhancer();
        //設置增強的父類,即業務類
        enhance.setSuperclass(cls);
        /*setCallback()設置哪個類是它的代理類,參數是this為當前對象,
         * 要求當前對象實現MethodInterceptor接口並實現方法intercept*/        
        enhance.setCallback(this);
        return enhance.create();
    }
    @Override
    public Object intercept(Object proxy,Method method,Object[]args,
            MethodProxy methodProxy) throws Throwable {
            System.out.println("前");
            Object result = methodProxy.invokeSuper(proxy, args);
            System.out.println("后");
            return result;
        
    }
    @Test
    public void testCGLIBProxyExample() {
        CGLIBProxyExample cglibProxyExample = new CGLIBProxyExample();
        Hello proxy = (Hello) cglibProxyExample.getProxy(Hello.class);
        proxy.sayHello();
    }
}
MethodInterceptor、 Enhancer在cglib-nodep-3.2.10.jar下

四、攔截器

 1、因為攔截器可以進一步簡化動態代理的使用方法,是程序變得更簡單。

 2、實現步驟:(1)定義一個攔截器接口

            (2)定義攔截器的實現類

          (3)實現攔截器的邏輯

public interface Interceptor {
    public boolean before(Object proxy,Object target,Method method,Object[] args);
    public void around(Object proxy,Object target,Method method,Object[] args);
    public void after(Object proxy,Object target,Method method,Object[] args);
}
package interceptor;

import java.lang.reflect.Method;

public class InterceptorImp implements Interceptor{

    @Override
    /*當返回值為true時,反射真實對象原來的方法
     * 當返回值為false時,則調用around方法
     */
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("反射方法前邏輯");
        return false;
    }

    @Override
   //對原來的方法不滿意,進行調整
public void around(Object proxy, Object target, Method method, Object[] args) { System.out.println("取代原方法的邏輯"); } @Override public void after(Object proxy, Object target, Method method, Object[] args) { System.out.println("調用原方法或around后還要執行的邏輯"); } }
package interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class InterceptorJdkProxy implements InvocationHandler{
    private Object target;    
    private String interceptorClass = null;//定義攔截器類路徑
    public InterceptorJdkProxy(Object target,String interceptorClass) {
        this.target = target;
        this.interceptorClass = interceptorClass;
    }
    
    public static Object bind(Object target,String interceptorClass) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), 
                new InterceptorJdkProxy(target,interceptorClass));
    }
    
    @Override
    //第一個參數proxy的獲取通過Proxy.newProxyInstance()獲取
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(interceptorClass==null) {
            //沒有攔截器就直接反射原來方法
            return method.invoke(target, args);
        }
        //否則,通過反射生成攔截器
        Object result = null;
        Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();
        //判斷before方法
        if(interceptor.before(proxy, target, method, args)) {
            result = method.invoke(target, args);
        }else {
            interceptor.around(proxy, target, method, args);
        }
        interceptor.after(proxy, target, method, args);
        return result;
    }
       
    
    public static void main(String[] args) {
        //沒有使用代理
        HelloWorld helloWorld = new HelloWorldImp();
        helloWorld.sayHelloWorld();
        //使用了代理
        HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImp(),
                "interceptor.InterceptorImp");
        proxy.sayHelloWorld();
    }
}

 

 

 
 
        
 
        

      

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM