浅入浅出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代理)

JDK原生动态代理是Java原生支持的,不需要任何外部依赖,但是它只能基于接口进行代理;

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) {
        //通过JDK动态代理获取UserService的代理对象
            UserService proxy = (UserService) Proxy.newProxyInstance(
                    userService.getClass().getClassLoader(), //1. 类加载器
                    userService.getClass().getInterfaces(), // 2. 代理需要实现的接口,可以有多个
                    new InvocationHandler() { // 3. 方法调用的实际处理者

                        @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代理

CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。
CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法处理final的情况。

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来指定要代理的目标对象、实际处理代理逻辑的对象
             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

    原文作者:stephenhuang
    原文地址: https://segmentfault.com/a/1190000019791078
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞