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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章