乐趣区

深入浅出Java代理的三种实现

注意:本文所有的 class 使用的 static 修饰主要是为了能在一个类里面测试。实际项目中不应该这样做的,应该分包分 class。
文字描述不是很多,还是看代码比较好理解吧 …

1. Java 代理的理解

代理模式 是一种 设计模式 ,简单说即是在不改变源码的情况下,实现对目标对象的功能扩展。
使用场景:如在方法执行前后计算执行时间,记录日志等。在不改变原码的条件下实现这些功能的扩展。

2. 代理模式的实现

2.1 静态代理

2.1.0 优缺点

  • 优点: 只对对需要的方法加代理逻辑。
  • 缺点: 1. 每次代理都需要实现一个代理类;2. 代理类功能固定,无法灵活改变。3. 项目会有一大批代理的代码,如果目标对象改变,代理类也需要对应改变,不利于代码的维护。

2.1.1 实现方式一: 继承代理(继承方式实现代理)

public class StaticProxyByExtendTest {

    // 目标对象
    public static class UserServiceImpl {public void login(String username, String pwd) {System.out.println("Welcome" + username);
        }
    }
    
    // 代理对象
    public static class UserServiceImplProxy extends UserServiceImpl{public void login(String username, String pwd) {System.out.println("before....");// 代理额外逻辑
            super.login(username, pwd);// 调用原实现方法
            System.out.println("after....");// 代理额外逻辑
        }
    }

    // 测试
    public static void main(String[] args) {UserServiceImpl ee = new UserServiceImplProxy();
        ee.login("Stephen", "123");
    }

}

2.1.2 实现方式二: 聚合方式(通过实现相同接口)

public class StaticProxyByGroupTest {

    public interface UserService {public void login(String username, String pwd);
    }
    
    // 目标对象
    public static class UserServiceImpl implements UserService {

        @Override
        public void login(String username, String pwd) {System.out.println("Welcome" + username);
        }
        
    }
    
    // 代理对象
    public static class UserServiceImplProxy implements UserService {

        private UserService userService;
        
        public UserServiceImplProxy(UserService userService) {this.userService = userService;}
        
        @Override
        public void login(String username, String pwd) {System.out.println("before....");// 代理额外逻辑
            userService.login(username, pwd);// 调用原实现方法
            System.out.println("after....");// 代理额外逻辑
        }
        
    }
    
    public static void main(String[] args) {UserService target = new UserServiceImpl();
        UserService tt = new UserServiceImplProxy(target);
        tt.login("Stephen", "123");
    }

}

使用聚合方式我们还可以添加其他的代理对象来对已经代理的对象继续做增强代理。

2.2 动态代理(JDK 代理)

2.2.0 优缺点

  • 优点: 动态代理所有接口。
  • 缺点: 必须依赖使用接口方式来实现代理。

主要实现是使用 JDK 自带的 Proxy 类来实现

newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

Returns an instance of a proxy class for the specified interfaces that dispatches method invocations to the specified invocation handler.

动态代理不需要对方法逐一实现代理,通过反射循环所有的接口方法,统一动态的加上代理逻辑。我们也可以通过执行方法的名字来过滤当前方法是否需要代理。

2.2.1 基本实现方式

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxyByJDKTest {
    
    public interface UserService {public void login(String username, String pwd);
    }
    
    // 目标对象
    public static class UserServiceImpl implements UserService {

        @Override
        public void login(String username, String pwd) {System.out.println("Welcome" + username);
        }
        
    }
    
    // 代理对象 1
    public static class UserServiceImplProxy {

        private UserService userServiceProxy;
        
        public UserServiceImplProxy(UserService userService) {UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), 
                    userService.getClass().getInterfaces(), 
                    new InvocationHandler() {

                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before....");// 代理额外逻辑
                            Object returnValue = method.invoke(userService, args);
                            System.out.println("after....");// 代理额外逻辑
                            return returnValue;
                        }
                        
                    });
            
            this.userServiceProxy = proxy;
        }

        public UserService getProxy() {return this.userServiceProxy;}
        
    }
    
    // 获取动态代理对象的公共方法
    @SuppressWarnings("unchecked")
    public static <T> T getJDKProxy(T t) {T proxy = (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), 
                t.getClass().getInterfaces(), 
                new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before....");// 代理额外逻辑
                        Object returnValue = method.invoke(t, args);
                        System.out.println("after....");// 代理额外逻辑
                        return returnValue;
                    }
                    
                });
        
        return proxy;
    }

    public static void main(String[] args) {UserService target = new UserServiceImpl();
        // 代理对象 1
        UserServiceImplProxy proxy = new UserServiceImplProxy(target);
        proxy.getProxy().login("Stephen", "123");
        
        // 代理对象
        UserService jdkProxy = getJDKProxy(target);
        jdkProxy.login("JDK Stephen", "123");
    }

}

2.2.2 优化动态代理

JDK Proxy 动态代理进一步优化:

  • 抽象出代理父类
  • 代理类实现自己的 before 和 after 方法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxyByJDKTest2 {
    // 目标接口
    public interface UserService {public void login(String username, String pwd);
    }
    
    // 目标对象
    public static class UserServiceImpl implements UserService {

        @Override
        public void login(String username, String pwd) {System.out.println("Welcome" + username);
        }
        
    }
    
    // 代理对象
    public static class UserServiceImplProxy extends JDKProxy {
        
        public UserService userServiceProxy;

        public UserServiceImplProxy(UserService userService) {this.userServiceProxy = getJDKProxy(userService);
        }
        
        @Override
        protected void before(Method method) {System.out.println("before....");// 代理额外逻辑
        }

        @Override
        protected void after(Method method) {System.out.println("after....");// 代理额外逻辑
        }

    }
    
    //Common proxy object class
    public static abstract class JDKProxy {protected abstract void before(Method method);
        
        protected abstract void after(Method method);
        
        @SuppressWarnings("unchecked")
        protected <T> T getJDKProxy(T t) {T proxy = (T) Proxy.newProxyInstance(t.getClass().getClassLoader(), 
                    t.getClass().getInterfaces(), 
                    new InvocationHandler() {

                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {before(method);// 代理额外逻辑
                            Object returnValue = method.invoke(t, args);
                            after(method);// 代理额外逻辑
                            return returnValue;
                        }
                        
                    });
            
            return proxy;
        }
    }
    
    public static void main(String[] args) {UserService target = new UserServiceImpl();
        // 代理对象
        UserServiceImplProxy proxy = new UserServiceImplProxy(target);
        proxy.userServiceProxy.login("Stephen", "123");
    }

}

2.3 Cglib 代理

2.3.0 优缺点

  • 优点:Cglib 代理不依赖接口,JDK 代理赖接口
  • 缺点:

在 Spring 的 AOP 编程中:

  • 如果加入容器的目标对象有实现接口,用 JDK 代理
  • 如果目标对象没有实现接口,用 Cglib 代理

2.3.1 使用 spring-core 实现 cglib 代理

需要引用 spring-core.jarSpring Core » 5.1.8.RELEASE

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class DynamicProxyBySpringCglibTest {

    // 目标接口
    public interface UserService {public void login(String username, String pwd);
    }
    
    // 目标对象
    public static class UserServiceImpl implements UserService {

        @Override
        public void login(String username, String pwd) {System.out.println("Welcome" + username);
        }
        
    }
    
    // 代理对象
    public static class ProxyFactory implements MethodInterceptor {

        private Object target;
        
        public ProxyFactory(Object target) {this.target = target;}
        
         public Object getProxyInstance(){
             //1. 工具类
             Enhancer en = new Enhancer();
             //2. 设置父类
             en.setSuperclass(target.getClass());
             //3. 设置回调函数
             en.setCallback(this);
             //4. 创建子类(代理对象)
             return en.create();}
        
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("before....");// 代理额外逻辑
            Object returnValue = method.invoke(target, args);
            System.out.println("after....");// 代理额外逻辑
            return returnValue;
        }

    }
    
    public static void main(String[] args) throws Exception {UserService target = new UserServiceImpl();
        UserService proxy = (UserService) new ProxyFactory(target).getProxyInstance();
        proxy.login("Stephen", "123");
    }

}

2.3.1 使用 spring-core 实现 cglib 代理(优化版本)

主要优化点:

  • 提取抽象公共的 ProxyFactory 类
  • 具体代理类的实现继承自 ProxyFactory
import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class DynamicProxyBySpringCglibTest1 {

    // 目标接口
    public interface UserService {public void login(String username, String pwd);
    }
    
    // 目标对象
    public static class UserServiceImpl implements UserService {

        @Override
        public void login(String username, String pwd) {System.out.println("Welcome" + username);
        }
        
    }
    
    //Common 代理对象
    public static abstract class ProxyFactory implements MethodInterceptor {

        private Object target;
        
        public ProxyFactory(Object target) {this.target = target;}
        
        public Object getProxyInstance(){
             //1. 工具类
             Enhancer en = new Enhancer();
             //2. 设置父类
             en.setSuperclass(target.getClass());
             //3. 设置回调函数
             en.setCallback(this);
             //4. 创建子类(代理对象)
             return en.create();}
         
        protected abstract void before(Method method);
            
        protected abstract void after(Method method);
        
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {before(method);
            Object returnValue = method.invoke(target, args);
            after(method);
            return returnValue;
        }

    }
    
    // 具体代理对象
    public static class UserServiceProxy extends ProxyFactory {public UserServiceProxy(Object target) {super(target);
        }

        @Override
        protected void before(Method method) {System.out.println("before...." + method.getName());// 代理额外逻辑
        }

        @Override
        protected void after(Method method) {System.out.println("after...." + method.getName());// 代理额外逻辑
        }
        
    }
    
    public static void main(String[] args) throws Exception {UserService target = new UserServiceImpl();
        UserService proxy = (UserService) new UserServiceProxy(target).getProxyInstance();
        proxy.login("Stephen", "123");
    }

}

3.Refs

  • API java.lang.reflect.Proxy
  • Spring Core » 5.1.8.RELEASE
  • 理解 java 的三种代理模式
  • java 代理
  • Java 代理和动态代理机制分析和应用
退出移动版