1. 程式人生 > >JAVA基礎(一)——代理模式

JAVA基礎(一)——代理模式

throws tle ddb 加載 dynamic pro return 描述 類加載

實現java代理一般分為靜態代理和動態代理(jdk代理和cglib代理)

代理模式

技術分享圖片

簡單的說就是對原有的業務進行代理,外界通過代理訪問真實對象,代理類似現在的中介機構,房產中介就是一個代理,代理房東,租戶只要找到代理而無須關心房東是誰,代理能在房東的基礎上增強房東的行為。

代理模式代碼

JAVA靜態代理

業務接口

package com.rrg.proxy.jdk.staticProxy;
/**
 * 
 * @author abc
 *
 */
public interface Count {
    /**
     * 查詢余額
     */
    public void queryMoney();
    
    
/** * 轉賬 */ public void transferMoney(); }

業務實現類

package com.rrg.proxy.jdk.staticProxy;

public class CountImpl implements Count {

    
    public void queryMoney() {
        System.out.println("queryMoney()");
    }

    public void transferMoney() {
        System.out.println("transferMoney()");
    }

}

代理

package com.rrg.proxy.jdk.staticProxy;
/**
 * java靜態代理
 * @author abc
 *
 */
public class JDKStaticProxy implements Count {

    private CountImpl countImpl;
    
    public JDKStaticProxy(CountImpl countImpl) {
        this.countImpl = countImpl;
    }

    public void queryMoney() {
        System.out.println(
"===開始查詢==="); countImpl.queryMoney(); System.out.println("===查詢結束==="); } public void transferMoney() { System.out.println("===開始轉賬==="); countImpl.transferMoney(); System.out.println("===轉賬成功==="); } }

測試

/**
     * jdk靜態代理
     */
    @Test
    public void test1(){
        CountImpl impl = new CountImpl();
        JDKStaticProxy proxy = new JDKStaticProxy(impl);
        proxy.queryMoney();
        System.out.println();
        proxy.transferMoney();
    }

JAVA動態代理

模擬業務方法接口UserService.java

package com.rrg.proxy.jdk.dynamic;
/**
 * 創建業務接口
 * @author abc
 *
 */
public interface UserService {
    /**
     * 新增人員
     */
    public void add();
}

業務方法實現UserServiceImpl.java

package com.rrg.proxy.jdk.dynamic;

public class UserServiceImpl implements UserService {

    public void add() {
        System.out.println("add()");
    }

}

代理類,負責處理代理

package com.rrg.proxy.jdk.dynamic;

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

public class JDKDynamicHandler implements InvocationHandler {

    private UserService userService;
    
    public JDKDynamicHandler(UserService userService) {
        super();
        this.userService = userService;
    }
    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        System.out.println("===添加人員處理===");
        Object result = method.invoke(userService, args);
        System.out.println("===添加人員完畢===");
        
        return result;
    }

    public Object getProxy() {
        //通過反射機制,創建一個代理類對象實例並返回。用戶進行方法調用時使用
        //創建代理對象時,需要傳遞該業務類的類加載器(用來獲取業務實現類的元數據,在包裝方法是調用真正的業務方法)、接口、handler實現類
        
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), this.userService.getClass().getInterfaces(), this);
    }
}

測試

/**
     * jdk動態代理
     */
    @Test
    public void test2() {
        UserService userService = new UserServiceImpl();
        JDKDynamicHandler handler = new JDKDynamicHandler(userService);
        UserService proxy = (UserService) handler.getProxy();
        proxy.add();
    }

CGLIB動態代理

不需要接口直接代理實現類

業務實現類

package com.rrg.proxy.cglib;

public class BookFacadeImpl {

    /**
     * 添加圖書
     */
    public void addBook() {
        System.out.println("addBook()");
    }
}

代理

package com.rrg.proxy.cglib;

import java.lang.reflect.Method;

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

public class BookFacadeCglib implements MethodInterceptor {

    private BookFacadeImpl bookService;
    
    public Object getInstance(BookFacadeImpl bookService) {
        Enhancer enhancer = new Enhancer(); //創建加強器,用來創建動態代理類
        enhancer.setSuperclass(this.bookService.getClass());  //為加強器指定要代理的業務類(即:為下面生成的代理類指定父類)
        //設置回調:對於代理類上所有方法的調用,都會調用CallBack,而Callback則需要實現intercept()方法進行攔
        enhancer.setCallback(this); 
        // 創建動態代理類對象並返回  
        return enhancer.create(); 
    }
    //回調方法
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("===準備添加圖書===");
        methodProxy.invokeSuper(object, args);
        System.out.println("===完成添加圖書===");
        return null;
    }

}

測試

/**
     * cglib動態代理
     */
    @Test
    public void test3() {
        BookFacadeImpl bookService = new BookFacadeImpl();
        BookFacadeCglib cglib = new BookFacadeCglib();
        BookFacadeImpl bookCglib = (BookFacadeImpl) cglib.getInstance(bookService);
        bookCglib.addBook();
    }

總結


(1)靜態代理是在編譯時創建一個業務代理類,通過代理訪問同名方法,實現對原方法的包裝(代理類繼承業務類)
(2)JDK動態代理通過接口的方法名,在動態的代理類調用同名業務方法,實現對原方法的包裝(實現InvocationHandler)
(3)CGLIB動態代理通過繼承業務類,創建出一個增強的業務類(實現MethodInterceptor)

代理是一個AOP思想的體現,切面編程對業務方法的前後進行增強

在Spring的AOP編程中:
  如果加入容器的目標對象有實現接口,用JDK代理
  如果目標對象沒有實現接口,用Cglib代理

JAVA基礎(一)——代理模式