一、静态代理实现与测试

  1. 实现方式
    静态代理通过手动编写代理类,在编译期确定代理关系,需满足以下步骤:
  2. 定义接口:定义目标对象和代理类共同遵循的接口。
    public interface Subject {
        void request();
    }
    
  3. 实现真实主题类:实现接口并完成核心业务逻辑。
    public class RealSubject implements Subject {
        @Override
        public void request() {
            System.out.println("真实主题的请求");
        }
    }
    
  4. 编写代理类:实现相同接口,并在方法中调用真实对象的方法,添加额外逻辑(如日志、权限校验)。
    public class Proxy implements Subject {
        private RealSubject realSubject;
        
        public Proxy() {
            realSubject = new RealSubject();
        }
        
        @Override
        public void request() {
            preRequest();  // 前置处理(如日志)
            realSubject.request();
            postRequest(); // 后置处理(如清理资源)
        }
        
        private void preRequest() { System.out.println("代理前置处理"); }
        private void postRequest() { System.out.println("代理后置处理"); }
    }
    
  5. 测试方法
    通过客户端代码调用代理类的方法,验证额外逻辑是否生效:
public class Client {
    public static void main(String[] args) {
        Subject proxy = new Proxy();
        proxy.request();
    }
}

预期输出:

代理前置处理
真实主题的请求
代理后置处理

二、动态代理实现与测试

  1. JDK动态代理
    JDK动态代理基于反射机制,无需手动编写代理类,需实现InvocationHandler接口。
    #实现步骤:
  2. 定义接口与实现类:
    public interface Subject {
        void request();
    }
    
    public class RealSubject implements Subject {
        @Override
        public void request() {
            System.out.println("真实主题的请求");
        }
    }
    
  3. 实现InvocationHandler接口:
    public class DynamicProxyHandler implements InvocationHandler {
        private Object target;
        
        public DynamicProxyHandler(Object target) {
            this.target = target;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("动态代理前置处理: " + method.getName());
            Object result = method.invoke(target, args);
            System.out.println("动态代理后置处理: " + method.getName());
            return result;
        }
    }
    
  4. 生成代理对象:
    public class ProxyFactory {
        public static Object getProxyInstance(Object target) {
            return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new DynamicProxyHandler(target)
            );
        }
    }
    

测试方法:

public class Client {
    public static void main(String[] args) {
        Subject realSubject = new RealSubject();
        Subject proxy = (Subject) ProxyFactory.getProxyInstance(realSubject);
        proxy.request();
    }
}

预期输出:

动态代理前置处理: request
真实主题的请求
动态代理后置处理: request

  1. CGLIB动态代理
    CGLIB通过生成目标类的子类实现代理,无需接口,但需依赖第三方库。

实现步骤:

  1. 添加CGLIB依赖:
    
        cglib
        cglib
        3.6.1
    
    
  2. 定义非接口类:
    public class RealSubject {
        public void request() {
            System.out.println("真实主题的请求");
        }
    }
    
  3. 实现MethodInterceptor接口:
    public class CglibProxy implements MethodInterceptor {
        private Object target;
        
        public CglibProxy(Object target) {
            this.target = target;
        }
        
        public Object getProxy() {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(target.getClass());
            enhancer.setCallback(this);
            return enhancer.create();
        }
        
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("CGLIB前置处理");
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("CGLIB后置处理");
            return result;
        }
    }
    

测试方法:

public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        CglibProxy cglibProxy = new CglibProxy(realSubject);
        RealSubject proxy = (RealSubject) cglibProxy.getProxy();
        proxy.request();
    }
}

预期输出:

CGLIB前置处理
真实主题的请求
CGLIB后置处理

三、实现方式对比与选择

类型JDK动态代理CGLIB动态代理
依赖JDK内置,无需额外库需引入CGLIB库
代理对象接口代理(需目标类实现接口)子类代理(无需接口)
性能方法调用稍慢(反射开销)方法调用更快(直接调用子类方法)
限制不能代理final类或方法不能代理final类或静态方法

四、测试注意事项

  1. 验证代理逻辑:确保代理方法调用时额外逻辑(如日志、事务)生效。
  2. 接口一致性:静态代理和JDK动态代理需确保代理类与目标类实现相同接口。
  3. 性能测试:动态代理在高频调用场景下需评估反射或子类生成的性能影响。

五、总结

静态代理:适用于简单场景,代码可控性强,但需手动维护代理类。

  • 动态代理:
    • JDK动态代理:适合已实现接口的目标类,代码简洁。
    • CGLIB:适合无接口的类,但需注意final类限制。
      根据实际需求选择代理方式,并通过测试验证功能与性能。
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐