代理模式

    科技2026-03-19  7

    静态代理

    用父亲帮儿子找对象来举例: public interface Person { public void findLove(); } public class Son implements Person { @Override public void findLove() { System.out.println("儿子要找一个对象"); } } public class Father implements Person { private Son son; public Father (Son son){ this.son = son ; } @Override public void findLove() { System.out.println("开始物色"); son.findLove(); System.out.println("找到"); } } public class StaticProxyTest { public static void main(String[] args) { Father father = new Father(new Son()); father.findLove(); } }

    输出:

    开始物色 儿子要找一个对象 找到

    代 理对象持有被代理对象的引用,客户端调用代理对象方法,同时也调用被代理对象的方 法,但是在代理对象前后增加一些处理。这就是一个简单的静态代理。

    动态代理:

    public class Girl implements Person{ @Override public void findLove() { System.out.println("女兒要找一个对象"); } } public class JDKProxy implements InvocationHandler{ private Object target; public Object getInstance(Object target){ this.target = target; Class<?> clazz = target.getClass(); return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始物色"); Object invoke = method.invoke(this.target, args); System.out.println("找到"); return invoke; } } public class JDKProxyTest { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // Object instance = new JDKProxy().getInstance(new Girl()); // Method method = instance.getClass().getMethod("findLove", null); // method.invoke(instance); //或者: Person instance =(Person) new JDKProxy().getInstance(new Girl()); instance.findLove(); } }

    CGLib方式

    public class CGLibProxy implements MethodInterceptor { public Object getInstance(Class<?> clazz){ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(clazz); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("开始物色"); Object object = methodProxy.invokeSuper(o, objects); System.out.println("找到"); return object; } } public class CglibTest { public static void main(String[] args) { Girl instance = (Girl)new CGLibProxy().getInstance(Girl.class); instance.findLove(); } }

    JDK动态代理的实现原理

    1、拿到被代理类的引用,并且获取它的所有的接口(反射获 取)。2、JDK Proxy类重新生成一个新的类,实现了被代理类所有 接口的方法。3、动态生成Java代码,把增强逻辑加入到新生成代码中。4、编译生成新的Java代码的class文件。5、再重新加载到 JVM 中运行。

    CGLib 和 JDK 动态代理对比

    1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM 框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法, CGLib 执行效率更高。

    代理模式与 Spring

    ProxyFactoryBean 核心的方法就是 getObject()方法

    public Object getObject() throws BeansException { initializeAdvisorChain(); if (isSingleton()) { return getSingletonInstance(); }else { if (this.targetName == null) { logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " + "Enable prototype proxies by setting the 'targetName' property."); }return newPrototypeInstance(); } }

    在 getObject()方法中,主要调用 getSingletonInstance()和 newPrototypeInstance(); 在 Spring 的配置中,如果不做任何设置,那么 Spring 代理生成的 Bean 都是单例对象。 如果修改 scope 则每次创建一个新的原型对象。

    Spring 中的代理选择原则

    1、当 Bean 有实现接口时,Spring 就会用 JDK 的动态代理2、当 Bean 没有实现接口时,Spring 选择 CGLib。3、Spring 可以通过配置强制使用 CGLib,只需在 Spring 的配置文件中加入如下代码: <aop:aspectj-autoproxy proxy-target-class=“true”/>

    代理模式的优缺点

    使用代理模式具有以下几个优点:
    1、代理模式能将代理对象与真实被调用的目标对象分离。2、一定程度上降低了系统的耦合度,扩展性好。3、可以起到保护目标对象的作用。4、可以对目标对象的功能增强。
    缺点
    1、代理模式会造成系统设计中类的数量增加。2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。3、增加了系统的复杂度。
    Processed: 0.014, SQL: 9