SSMSSM
首页
  • 我的博客
  • 我的Github
首页
  • 我的博客
  • 我的Github
  • Java反射技术
  • 动态代理模式
  • 设计模式简介
  • 责任链模式
  • 观察者模式
  • 工厂模式与抽象工厂模式
  • 建造者模式
  • Web开发历史
  • Mybatis核心组件
  • Mybatis的反射
  • Mybatis配置

动态代理模式

  • 1.前言
  • 2.JDK动态代理
  • 3.CGLIB动态代理
  • 4.拦截器
  • 5.总结

1.前言

Java有多种动态代理技术,比如JDK、CGLIB、Javassist、ASM,其中最常用的动态代理技术有两种:一种是 JDK 动态代理,这是 JDK 自带的功能;另一种是 CGLIB,这是第三方提供的一种技术。目前 Spring 常用 JDK和CGLIB,而 MyBatis 还使用 Javassist ,无论哪种代理其技术,它们的理念都是相似的。

反射与动态代理的关系:

  • 反射是基础技术
  • 动态代理是基于反射实现的设计模式

2.JDK动态代理

特点:基于Java自带的类(java.lang.reflect.Proxy)实现,这个类涉及到接口,这也意味着JDK动态代理只能代理接口,类不行,类要用CGLIB。

JDK动态代理说明
用途给接口实现类“加壳”增强功能(如日志、安全、事务)
原理使用 Java 反射 + Proxy 动态生成代理对象
限制只能代理接口(类不行,类要用 CGLIB)
package com.learn.ssm.chapter2.reflect;

public interface HelloWorld {
    public void sayHelloWorld();
}
package com.learn.ssm.chapter2.reflect;

public class HelloWorldImpl implements HelloWorld {
    @Override
    public void sayHelloWorld() {
        System.out.println("Hello World");
    }
}
package com.learn.ssm.chapter2.reflect;

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

public class JdkProxyExample implements InvocationHandler {

    // 真实对象
    private Object target = null;

    // 1.建立代理对象与真实对象的代理关系,并返回代理对象
    // Proxy.newProxyInstance第二个参数限制了JDK动态代理只适应接口类型,不能直接代理类
    public Object bind(Object target) {
        this.target = target;//本该放到构造函数中,这里顺便做了
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    // 2.实现代理逻辑
    // 当调用代理对象的某个方法时,这个 invoke() 方法就会被触发。
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("在调度真实对象之前的服务");

        // 这行代码相当于调度真实对象的方法,只是通过反射实现而已。
        Object obj = method.invoke(target, args);//访问 当前类的成员变量 时,可省略this

        System.out.println("在调度真实对象之后的服务");
        return obj;
    }
}
// 5.JDK动态代理
JdkProxyExample jdk = new JdkProxyExample();
HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl());
proxy.sayHelloWorld();//这行代码会去执行代理对象的invoke方法
/**
 * 在调度真实对象之前的服务
 * Hello World
 * 在调度真实对象之后的服务
 */

3.CGLIB动态代理

JDK 动态代理必须提供接口才能使用,在一些不能提供接口的环境中,只能采用其他第三方技术, 比如 CGLIB 动态代理。

package com.learn.ssm.chapter2.reflect;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class CglibProxyExample implements MethodInterceptor {

    // 1.建立代理对象与真实对象的代理关系,并返回代理对象
    public Object getProxy(Class cls) {
        Enhancer enhancer = new Enhancer();

        //设置增强类型
        enhancer.setSuperclass(cls);

        //定义代理对象为当前对象,要求当前对象实现 MethodInterceptor 方法
        enhancer.setCallback(this);

        //生成并返回代理对象
        return enhancer.create();
    }

    // 2.实现代理逻辑
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用真实对象前");

        //CGLIB 反射调用真实对象方法
        Object result = methodProxy.invokeSuper(proxy, args);

        System.out.println("调用真实对象后");
        return result;
    }
}
// 6.Cglib动态代理
CglibProxyExample cpe = new CglibProxyExample();
ReflectServiceImpl obj = (ReflectServiceImpl) cpe.getProxy(ReflectServiceImpl.class);
obj.sayHello("Wendy");//这行代码会去执行代理对象的intercept方法
/**
 * 调用真实对象前
 * Hello, Wendy
 * 调用真实对象后
 */

4.拦截器

反射与动态代理与拦截器的关系:

  • 反射是基础技术
  • 动态代理是基于反射实现的设计模式
  • 拦截器是基于代理实现的应用场景
package com.learn.ssm.chapter2.reflect;

import java.lang.reflect.Method;

public interface Interceptor {
    public boolean before(Object proxy, Object target, Method method, Object[] args);
    public void around(Object proxy, Object target, Method method, Object[] args);
    public void after(Object proxy, Object target, Method method, Object[] args);
}
package com.learn.ssm.chapter2.reflect;

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

public class InterceptorJdkProxy implements InvocationHandler {

    private Object target;//真实对象
    private String interceptorClass = null;//拦截器全限定名

    //类的构造函数
    public InterceptorJdkProxy(Object target, String interceptorClass) {
        this.target = target;
        this.interceptorClass = interceptorClass;
    }

    // 1.建立代理对象与真实对象的代理关系,并返回代理对象
    public static Object bind(Object target, String interceptorClass) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InterceptorJdkProxy(target, interceptorClass));
    }

    // 2.实现代理逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(interceptorClass == null) {
            //没有拦截器则直接反射原有方法
            return method.invoke(target, args);
        }
        Object result = null;

        //通过反射生成拦截器对象
        Interceptor interceptor = (Interceptor) Class.forName(interceptorClass).newInstance();

        if(interceptor.before(proxy, target, method, args)) {//校验通过
            result = method.invoke(target, args);//调度真实对象的方法
        } else {//校验不通过
            interceptor.around(proxy, target, method, args);
        }
        interceptor.after(proxy, target, method, args);//finally
        return result;
    }
}
// 7.拦截器
HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(),
"com.learn.ssm.chapter2.reflect.MyInterceptor");
proxy2.sayHelloWorld();
/**
* 反射方法前逻辑
* 取代了被代理对象的方法
* 反射方法后逻辑
*/

5.总结

动态代理的意义在于在不修改原始对象的情况下,增加额外的功能。

这正是AOP(面向切面编程)思想的实现基础,也是现代Java框架(如Spring)的核心技术之一。

原始对象:🍎(一个干净的苹果)
↓
动态代理:🍎 + 📦(给苹果加了个包装盒)
        + 🎀(再系个蝴蝶结)
        + 💝(再加张贺卡)
  • 🍎:原始的业务功能
  • 📦🎀💝:代理添加的额外功能(日志、事务、安全等)
  • 关键:苹果本身没有被修改,只是被"包装"起来了
最近更新:: 2025/10/16 06:09
Contributors: fireworks99
Prev
Java反射技术
Next
设计模式简介