大话版动态代理Proxy讲解

299 阅读2分钟

代理proxy

总结代理类作用:为原始目标类(目标对象)增加额外的功能。

public interface UserService {
    void login();
    void register();
}

public class UserServiceImpl implements UserService{
    @Override
    public void login() {
        System.out.println("login()....");
    }

    @Override
    public void register() {
        System.out.println("re");
    }
}

此时需求为login和register方法增加log日志

名词解释

目标类:我们称UserServiceImpl这样的类为原始类或者目标类
额外功能:即增加的log输出这功能,额外功能不影响原始目标类功能,可有可无

静态代理

通过静态代理实现上述需求,静态代理通过实现原始类接口,保证与原始类有同样的方法,代理对象内部拥有原始类。

public class UserServiceProxy implements UserService {
    UserServiceImpl userService = new UserServiceImpl();
    @Override
    public void login() {
        System.out.println("-------log-------------");
        userService.login();
    }
    @Override
    public void register() {
        System.out.println("-------log-------------");
        userService.register();
    }
}

缺点:

  • 当有新的类需要代理时,需要增加代理类,导致代理类逐渐增多,不利于代码维护;
  • 代码耦合度过高

动态代理

动态代理底层原理是通过字节码技术在JVM中生成代理类,即没有生成.class文件,生命周期与JVM保持一致,当JVM关闭后,代理类消失;

由此可以动态代理类好处:利于代码维护

常见的动态代理有JDK和cglib

JDK proxy

JDK代理主要通过Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h )方法创建,返回的即是目标类的代理对象

方法参数

ClassLoader loader:类加载器,借用

interfaces:目标类接口

InvocationHandler :接口,即上面提到的额外功能

public class JdkProxy {
    public static void main(String[] args) {
        //1、目标类
        UserService userService = new UserServiceImpl();
        //2、额外功能
        InvocationHandler handler = new InvocationHandler() {
            /**
             *
             * @param proxy  代理类,基本不用
             * @param method 目标类被调用的方法
             * @param args  目标类被调用方法参数
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object ret;
                System.out.println("----log---------------------------");
                ret = method.invoke(userService, args);
                return ret;
            }
        };
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
        userServiceProxy.login();
    }
}

JDK动态代理底层原理也是通过字节码技术实现目标类接口,所以JDK代理是必须要有接口;

总结JDK动态代理开发流程

1、创建目标类对象

2、实现额外功能 InvocationHandler接口

3、Proxy.newProxyInstance(...)创建代理对象

Cglib proxy

cglib底层原理是通过类继承实现, cglibProxy extends 目标类生成代理对象,拥有目标类所有方法。

public class UserServiceCglibProxy {
    public static void main(String[] args) {
        OrderService orderService = new OrderService();

        MethodInterceptor interceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("-------------log-------------------");
                return method.invoke(orderService,args);
            }
        };
        Enhancer enhancer = new Enhancer();
        //设置类加载器
        enhancer.setClassLoader(UserServiceCglibProxy.class.getClassLoader());
        //设置目标类
        enhancer.setSuperclass(orderService.getClass());
        //设置额外功能
        enhancer.setCallback(interceptor);
        //创建代理对象
        OrderService orderProxy = (OrderService) enhancer.create();
        orderProxy.show();
    }
}

总结Cglib开发流程

1、创建目标类对象

2、实现MethodInterceptor接口提供额外功能

3、Enhancer对象设置类加载器,目标类,额外功能

4、创建代理对象