1. 程式人生 > >java靜態代理與動態代理理解

java靜態代理與動態代理理解

#1.靜態代理
其實就是一個典型的代理模式實現,在代理類中包裝一個被代理物件,然後影響被代理物件的行為

程式碼示例:

// 介面
public interface Hello {

public void sayHello(String name);

}

// 實現類
@Slf4j
public class HelloImpl implements Hello {

    @Override
    public void sayHello(String name) {

//        log.info("----->HelloImpl:{}", name);

        System.out.println(">>>>>:HelloImpl" + name);

    }

}

/**
* @Auther: 18030501
* @Date: 2018/10/15 16:51
* @Description: 代理類
*/
@Slf4j
public class HelloProxy implements Hello {

private Hello hello;

    public HelloProxy(Hello hello) {

        this.hello = hello;

    }

    @Override
    public void sayHello(String name) {

        log.info("do sayHello before...");
        hello.sayHello(name);
        log.info("do sayHello after...");

    }

}

/**
* @Auther: 18030501
* @Date: 2018/10/15 16:56
* @Description: 靜態代理測試
*/
public class TestHelloProxy {

public static void main(String[] args) {

        Hello hello =new HelloProxy(new HelloImpl());
        hello.sayHello("李峰");

    }

}

執行結果:
靜態代理測試結果.png

#2.動態代理
分類:JDK動態代理與CGLIB動態代理
####JDK動態代理:
此時代理物件和目標物件實現了相同的介面,目標物件作為代理物件的一個屬性,具體介面實現中,可以在呼叫目標物件相應方法前後加上其他業務處理邏輯。
代理模式在實際使用時需要指定具體的目標物件,如果為每個類都新增一個代理類的話,會導致類很多,同時如果不知道具體類的話,怎樣實現代理模式呢?這就引出動態代理。JDK動態代理只能針對實現了介面的類生成代理!

程式碼示例:

/**
 * @Auther: 18030501
 * @Date: 2018/10/15 17:23
 * @Description: 介面
 */
public interface UserService {
    public abstract void login(String name);
    void logout(String name);
}

/**
 * @Auther: 18030501
 * @Date: 2018/10/15 17:23
 * @Description: 實現類
 */
@Slf4j
public class UserServiceImpl implements UserService {

    @Override
    public void login(String name) {
        log.info("{} login...", name);
    }

    @Override
    public void logout(String name) {
        log.info("{} logout...", name);
    }
}

/**
 * @Auther: 18030501
 * @Date: 2018/10/15 17:24
 * @Description: 增強的類
 */
@Slf4j
public class UserServiceHandler implements InvocationHandler {

    private UserService userService;

    public UserServiceHandler(UserService userService) {
        this.userService = userService;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 執行前可以做點什麼
        log.info("before do method...");
        // 執行被代理類的方法
        Object obj = method.invoke(userService, args);
        // 執行後可以做點什麼
        log.info("after do method...");
        return obj;
    }
}

/**
 * @Auther: 18030501
 * @Date: 2018/10/15 17:27
 * @Description: JDK動態代理
 */
public class ProxyFactory {

    public static void main(String[] args) throws Exception {
        UserService userService = new UserServiceImpl();
        UserService obj = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new UserServiceHandler(userService));
        obj.login("拿著核武器的程式設計師");
        // 輸出代理類的class檔案
//        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[]{userService.getClass()});
//        FileOutputStream os = new FileOutputStream("Proxy0.class");
//        os.write(bytes);
//        os.flush();
//        os.close();
//        obj.logout();
//        userService.logout();
    }

執行結果:
JDK動態代理執行結果.png

####CGLIB動態代理:
CGLIB代理是針對類實現代理,
主要是對指定的類生成一個子類,覆蓋其中的所有方法,使用的是繼承的方式,所以該類或方法不能宣告稱final的。
CGLib是一個強大、高效能的Code生產類庫,可以實現執行期動態擴充套件java類,Spring在執行期間通過
CGlib繼承要被動態代理的類,重寫父類的方法,實現AOP面向切面程式設計

程式碼示例:

/**
 * @Auther: 18030501
 * @Date: 2018/10/15 19:08
 * @Description: CGLIB動態代理
 */
@Slf4j
public class ProxyFactory2 implements MethodInterceptor {

    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ProxyFactory2 proxyFactory2 = new ProxyFactory2();
        UserService proxyObject = proxyFactory2.getProxyObject(userService.getClass());
        proxyObject.login("拿著核武器的程式設計師");
    }


    // 提供對應的增強操作類
    private Enhancer enhancer = new Enhancer();

    public UserService getProxyObject(Class clazz) {
        // 設定所要增強的類的父類
        enhancer.setSuperclass(clazz);
        // 設定回撥物件
        enhancer.setCallback(this);
        // 建立對應的物件
        return (UserService) enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        log.info("do before....");
        // 這裡需要注意,由於methodProxy物件是增強後的Method物件,所以這裡需要呼叫的
        // 是methodProxy父類的方法,也就是所要增強的類的方法,以實現原來的功能
        Object obj = methodProxy.invokeSuper(o, objects);
        log.info("do after....");
        return obj;
    }
}

執行結果:
CGLIB動態代理執行結果.png

##JDK動態代理與CGLIB動態代理的區別:
1.JDK針對介面的類實現代理,CGLIB針對類實現代理
2.JDK代理的方式是生產介面實現類的兄弟類用來完成代理,
CGLIB代理的方式通過繼承被代理類的方式完成的代理。