Java設計模式-動態代理的使用

動態代理: 相對於靜態代理(字節碼一上來就創建好,並完成加載)相比,具有字節碼隨用隨創建,隨用隨加載的特點。主要作用是在不修改源碼的基礎上對方法進行增強。

1. 基於接口的動態代理

涉及的類 提供者 要求 方法
Proxy JDK官方 被代理類最少實現一個接口,如果沒有則不能使用 newProxyInstance

public static Object newProxyInstance​(ClassLoader loader,
               Class<?>[ ] interfaces,
              InvocationHandler h)
Parameters:
loader - the class loader to define the proxy class
interfaces - the list of interfaces for the proxy class to implement
h - the invocation handler to dispatch method invocations to
Returns:
a proxy instance with the specified invocation handler of a proxy class that is defined by the specified class loader and that implements the specified interfaces


ClassLoader loader: 類加載器
  它是用於加載代理對象的字節碼文件的。和被代理對象使用相同的類加載器。固定寫法。
Class<?>[] interfaces: 字節碼數組
  它是用於讓代理對象和被代理對象實現相同的方法。固定寫法。
InvocationHandler h: 用於提供增強的代碼
  它是讓我們寫如何代理。我們一般都是寫一個該接口的實現類,通常情況下都是匿名內部類,但不是必須的。此接口的實現類都是誰用誰寫。


使用示例:

public interface UserService {

    Float sell(Float money);

}
public class UserServiceImpl implements UserService {

    public Float sell(Float money) {
        return money;
    }

    public void show() {
        System.out.println("實現類特有方法");
    }
}
  public static void main(String[] args) {
        //匿名內部類訪問外部變量時,該成員必須爲final
        final UserServiceImpl userService = new UserServiceImpl();
        //只能強轉爲接口類型而不能是實現類類型
        UserService proxyBasedOnInterface = (UserService) Proxy.newProxyInstance(
                  userService.getClass().getClassLoader(),userService.getClass().getInterfaces(),
                  new InvocationHandler() {
                    /**
                     *作用:代理對象執行被代理對象的 任何接口方法 都會經過該方法
                     * @param proxy 代理對象的引用
                     * @param method 執行的方法
                     * @param args 方法的參數
                     * @return
                     * @throws Throwable
                     */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

               if ("sell".equals(method.getName())) {
                   //方法的內部邏輯的增強
                   System.out.println("方法內部邏輯增強");
                   //方法參數的增強
                   Float money = (Float) args[0] * 2;
                   //方法返回值的增強
                   Float returnValue = (Float)method.invoke(userService, money) + 100f;
                   return returnValue;
               }
               return null;

            }
        });
        proxyBasedOnInterface.sell(1024f);
  }

2. 基於子類的動態代理

涉及的類 提供者 要求 方法
Enhancer 第三方cglib庫 被代理類不能是最終類 create

public static Object create(Class type,Callback callback)
Helper method to create an intercepted object. For finer control over the generated instance, use a new instance of Enhancer instead of this static method.
Parameters:
type - class to extend or interface to implement
callback - the callback to use for all methods


Class type: 字節碼對象
  它是用於指定被代理對象的字節碼。
Callback callback: 用於提供增強的代碼
  它是讓我們寫如何代理。我們一般都是寫一個該接口的實現類,通常情況下都是匿名內部類,但不是必須的。此接口的實現類都是誰用誰寫。我們一般寫的都是該接口的子接口的實現類,MethodInterceptor


使用示例: 需要導入cglib庫

        <!-- https://mvnrepository.com/artifact/cglib/cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
  public static void main(String[] args) {
        //匿名內部類訪問外部變量時,該成員必須爲final
        final UserServiceImpl userService = new UserServiceImpl();
        //可以強轉爲接口類型或者實現類類型,因此可以調用實現類特有方法
        UserServiceImpl proxyBasedOnSubclass = (UserServiceImpl)Enhancer.create(
                              userService.getClass(), new MethodInterceptor() {
            /**
             * 代理對象執行被代理對象的任何方法都會經過此方法
             * @param proxy
             * @param method
             * @param args
             * 以上三個參數與基於接口的動態代理invoke方法的參數是一樣的
             * @param methodProxy 當前執行方法的代理對象
             * @return
             * @throws Throwable
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

                if ("sell".equals(method.getName())) {
                    //方法的內部邏輯的增強
                    System.out.println("方法內部邏輯增強");
                    //方法參數的增強
                    Float money = (Float) args[0] * 2;
                    //方法返回值的增強
                    Float returnValue = (Float)method.invoke(userService, money) + 20f;
                    return returnValue;
                }
                System.out.println("調用了此方法");
                return null;
            }
        });
        proxyBasedOnSubclass.sell(300f);
        proxyBasedOnSubclass.show();
  }
發佈了46 篇原創文章 · 獲贊 1 · 訪問量 2521
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章