SpringBoot实践(三十六):动态代理和反射

时间:2025-02-16 18:45:58

动态代理

动态代理从大的讲是动态语言特性,JAVA作为需要编译才能运行的静态语言,动态代理机制可以为JAVA提供在运行态时对某些对象进行功能增强,Spring中如果有对象使用了AOP相关注解,那么在bean进行实例化后会将对应的动态代理对象放在bean工厂,动态代理有2种实现方式:实现JDK原生动态代理接口,或者使用cglib实现,在默认情况下 Spring AOP 会采用 Java 动态代理实现,而当该类没有对应接口时才会使用 CGLib 动态代理实现。

jdk动态代理

该种动态代理的实现前提是被代理的对象实现了某个接口,代理对象将被强制转换成接口实现,通过调用该接口实现方法完成功能增强;
如下TestService是个公共的接口方法,OrderServer实现了该方法,它是被代理的对象,OrderServerProxy是代理对象,通过java的反射包里面的()方法,再强转成接口的实现,创建1个接口:

public interface TestService {
    void sell();
}
  • 1
  • 2
  • 3

实现该接口的实现类(被代理对象):

@Service
public class OrderServer implements TestService {

    @Override
    public void sell(){
        System.out.println("begin to sell something.");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

实现动态代理接口的代理类(代理对象):

public class OrderServerProxy implements InvocationHandler {
    private Object object;

    public OrderServerProxy(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("do something before.");
        return method.invoke(object,args);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

测试方法和输出:

    @GetMapping("/test/proxy")
    public void test1(){
        OrderServer orderServer = new OrderServer();
        TestService testService = (TestService) Proxy.newProxyInstance(orderServer.getClass().getClassLoader(), orderServer.getClass().getInterfaces(), new OrderServerProxy(orderServer));
        testService.sell();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
do something before.
begin to sell something.
  • 1
  • 2

cglib实现代理

(Code Generation Library)该种代理方式是采用了开源的字节码工具ASM完成,它不需要被代理对象继承某个接口,在实现上直接把代理对象作为被代理对象的子类,首先引入cglib的pox依赖:

        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

创建一个被代理对象,这个被代理对象不需要实现某个接口:

@Service
public class OrderServer2   {
    public void sell(){
        System.out.println("begin to sell something.");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

创建代理对象,实现拦截器方法:

public class ServiceInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("do something in cglib interceptor...");
        methodProxy.invokeSuper(o, objects);
        return o;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

测试和输出:

    @GetMapping("/test/cglib")
    public void test2(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(OrderServer2.class);
        enhancer.setCallback(new ServiceInterceptor());
        OrderServer2 orderServer2 = (OrderServer2) enhancer.create();
        orderServer2.sell();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
do something in cglib interceptor...
begin to sell something.
  • 1
  • 2

反射机制

java中的反射机制能够让开发者在程序运行态中获取到已经被实例化的bean中的属性和方法,甚至能够修改其中的属性值和方法实现,所以反射是动态代理的基础,比如上面的().getClassLoader()和().getInterfaces()分别是获取已经被实例化的orderServer对象的的类加载器和实现的接口列表,orderServer是1个已经被放在堆内存中的对象;