Java設計模式--代理模式+動態代理+CGLib代理

靜態代理

抽象主題角色:聲明真實主題和代理主題的共同接口。程序員

代理主題角色:代理主題內部含有對真實主題的引用,從而在任什麼時候候操做真實主題對象;代理主題提供一個與真實主題相同的接口,以便在任什麼時候候均可以代替真實主題。代理角色一般在將客戶端調用傳遞給真實的主題以前或以後,都要執行某個操做,而不是單純的傳遞調用。面試

真實主題角色:定義代理角色所表明的的真實對象。mybatis

UML圖:ide

抽象主題post

public interface Subject {
    void request();
}

 

真實主題this

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("真實對象的方法");
    }
}

 

代理主題spa

public class ProxySubject implements Subject {

    private RealSubject subject;

    public ProxySubject() {
    }

    @Override
    public void request() {
        pre();
        if (subject == null){
            subject = new RealSubject();
        }
        subject.request();
        post();
    }

    private void pre(){
        System.out.println("方法執行以前");
    }

    private void post(){
        System.out.println("方法執行以後");
    }
}

 

執行:設計

    public static void main(String[] args) throws Exception {
        ProxySubject subject = new ProxySubject();
        subject.request();
    }

 

輸出:代理

方法執行以前
真實對象的方法
方法執行以後 

動態代理

JDK自帶的動態代理,實現InvocationHandler接口。code

聲明接口

public interface MyConnection extends AutoCloseable {

    void createStatement() throws Exception;

    @Override
    void close() throws Exception;
}

 

真實主題

public class MyDefaultConnection implements MyConnection {
    @Override
    public void createStatement() throws Exception {
        System.out.println("Create Statement ...");
    }

    @Override
    public void close() throws Exception {
        System.out.println("Close Connection ...");
    }
}

 

代理主題

public class MyConnectionProxy implements InvocationHandler {

    private MyConnection conn;
    private MyConnection proxyConn;

    public MyConnectionProxy(MyConnection conn) {
        this.conn = conn;
        this.proxyConn = (MyConnection) Proxy.newProxyInstance(MyConnection.class.getClassLoader(), new Class<?>[] {MyConnection.class}, this);
    }

    public MyConnection getConn() {
        return conn;
    }

    public MyConnection getProxyConn() {
        return proxyConn;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        System.out.println("==代理方法:" + methodName);
        if("close".equals(methodName)){
            System.out.println("**不執行close方法");
        }else{
            return method.invoke(conn, args);
        }
        return null;
    }
}

 

執行:

    public static void main(String[] args) throws Exception {
        MyConnection connection = new MyDefaultConnection();
        MyConnectionProxy proxy = new MyConnectionProxy(connection);
        proxy.getProxyConn().createStatement();
        proxy.getProxyConn().close();
    }

 

你會發現個人代理對象去哪裏了?實際上我放在InvocationHandler的實現類裏面了,這裏參考的是mybatis源碼的設計。

輸出:

==代理方法:createStatement
Create Statement ...
==代理方法:close
**不執行close方法

CGLib

面試的時候可能問你:JDK動態代理和CGLib的區別是什麼,說的最多的就是JDK須要一個接口,而CHLib不須要接口就能實現動態代理。

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.12</version>
</dependency>

 

須要代理的對象

public class Programmer {

    public void work(){
        System.out.println("程序員正在敲代碼...");
    }

    public final void finalCannotOverride(){
        System.out.println("final方法不能被生成的子類覆蓋");
    }

    private void privateCannotOverride(){
        System.out.println("private方法不能被生成的子類覆蓋");
    }
}

 

代理類

public class ProgrammerProxy implements MethodInterceptor {

    // 真實對象
    private Object realObject;
    // 代理對象
    private Object proxyObject;

    public ProgrammerProxy(Object realObject) {
        this.realObject = realObject;
        Enhancer enhancer = new Enhancer();
        // 設置須要代理的對象
        enhancer.setSuperclass(realObject.getClass());
        // 設置代理人
        enhancer.setCallback(this);
        this.proxyObject = enhancer.create();
    }

    public Programmer getProxyObject() {
        return (Programmer) proxyObject;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        pre();
        Object result = method.invoke(realObject, objects);
        post();
        return result;
    }

    private void pre(){
        System.out.println("==先吃早餐");
    }

    private void post(){
        System.out.println("==下班打卡");
    }
}

 

執行:

    public static void main(String[] args) throws Exception {
        Programmer programmer = new Programmer();
        ProgrammerProxy proxy = new ProgrammerProxy(programmer);
        proxy.getProxyObject().finalCannotOverride();
        proxy.getProxyObject().work();
    }

 

輸出:

final方法不能被生成的子類覆蓋
==先吃早餐
程序員正在敲代碼...
==下班打卡
相關文章
相關標籤/搜索