当前位置:   article > 正文

【八】Java设计模式GOF23之动态代理(JDK和CGLIB)_gglib基于接口机制实现的吗

gglib基于接口机制实现的吗

一、使用JDK原生动态代理

实现有2种,1.基于Java反射机制 2.基于native方法

Java动态代理是基于接口的,如果对象没有实现接口则选择用CGLIB方式实现动态代理。

实现步骤:

1.首先实现一个InvocationHandler,方法调用会被转发到该类的invoke()方法。

2.然后在需要使用真实对象的时候,通过JDK动态代理获取代理对象。

目录

接口:SayHello.java

  1. package com.sid.proxy.jdk;
  2. public interface SayHello {
  3. String sayHello();
  4. }

真实的处理:SayHelloImp.java

  1. package com.sid.proxy.jdk;
  2. /**
  3. * 真实的处理
  4. * */
  5. public class SayHelloImp implements SayHello {
  6. public String sayHello() {
  7. System.out.println("hello word");
  8. return "done";
  9. }
  10. }

代理类:HelloHandler.java

  1. package com.sid.proxy.jdk;
  2. import java.lang.reflect.InvocationHandler;
  3. import java.lang.reflect.Method;
  4. /**
  5. * 这是代理类,代理了SayHello接口的所有实现类
  6. * */
  7. //1.首先实现一个InvocationHandler接口,方法调用会被转发到该类的invoke()方法。
  8. public class HelloHandler implements InvocationHandler {
  9. SayHello sayHello;
  10. public HelloHandler(SayHello sayHello) {
  11. super();
  12. this.sayHello = sayHello;
  13. }
  14. /**
  15. * 所有的流程控制都在这里面处理
  16. * 调用真实的SayHello接口的实现类的所有方法,都会先进这个invoke方法,
  17. * 由method.invoke去真正的调用SayHello的方法
  18. *
  19. * 入参proxy是代理类,mehtod表示调用真实类的哪个方法,args表示调用真实类的方法的入参
  20. * */
  21. @Override
  22. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  23. System.out.println("前置方法");
  24. // obj是调用真实类方法的返回值
  25. Object obj = method.invoke(sayHello, args);
  26. System.out.println(obj);
  27. System.out.println("后续方法");
  28. return obj;
  29. }
  30. }

Main方法调用

  1. package com.sid.proxy;
  2. import com.sid.proxy.jdk.HelloHandler;
  3. import com.sid.proxy.jdk.SayHello;
  4. import com.sid.proxy.jdk.SayHelloImp;
  5. import java.lang.reflect.Proxy;
  6. public class MainClass {
  7. public static void main(String[] args) {
  8. //2.然后在需要使用SayHello的时候,通过JDK动态代理获取SayHello的代理对象。
  9. //newProxyInstance()会返回一个实现了指定接口的代理对象,对该对象的所有方法调用都会转发给InvocationHandler.invoke()方法
  10. SayHello proxy = (SayHello) Proxy.newProxyInstance(
  11. ClassLoader.getSystemClassLoader(),//1. 类加载器
  12. new Class[]{SayHello.class},//2. 代理需要实现的接口,可以有多个
  13. new HelloHandler(new SayHelloImp()) // 3. 方法调用的实际处理者,代理对象的方法调用都会转发到这里
  14. );
  15. proxy.sayHello();
  16. }
  17. }

运行结果

二、使用CGLIB动态代理

基于ASM的字节码生成库,它允许在运行时对字节码进行修改和动态生成。

CGLIB动态代理的原理就是用Enhancer生成一个被代理类的子类,并且设置好callback到proxy, 当被代理类的每个方法被调用就会转为调用实现了MethodInterceptor接口的proxy代理类的intercept() 函数。

优点:1.CGLIB通过继承方式实现代理。2.效率比JDK的代理要高。

缺点:CGLIB只能代理所有非final的类、方法。

实现步骤

1.首先实现一个MethodInterceptor接口,方法调用会被转发到该类的intercept()方法。

2.创建Enhancer对象,给enhancer设置父类(就是被代理的目标类),给enhancer设置callback(callback就是第一步实现的MethodInterceptor,就是拦截到目标类的方法后要做的代理逻辑),enhancer.create创建代理类。

设置callback的时候可以设置一组callback,即是有多个不同的MethodInterceptor实现,然后设置回调过滤器CallbackFilter来指定不同的真实方法使用不同的代理逻辑

CGLIB包对callback接口有一些简单实现:

1.FixedValue固定值,MethodInterceptor需要实现FixedValue接口。这会忽略被代理目标类调用的方法的返回值,使用固定值来替换。

2.NoOp.INSTANCE,直接调用真实被代理类的方法,在代理中对该方法不做任何逻辑处理。

3.LazyLoader,继承了Callback接口,有一个loadObject的方法,LazyLoader只有在第一次调用时会执行loadObject获取对象。

4.Dispatcher,继承了Callback接口,有一个loadObject的方法,每次调用时都触发loadObject方法。

目录

 

需要引包

pom.xml

  1. <dependency>
  2. <groupId>cglib</groupId>
  3. <artifactId>cglib</artifactId>
  4. <version>3.1</version>
  5. </dependency>

真实类SayHelloImp.java

  1. public class SayHelloImp {
  2. public String sayHello1() {
  3. System.out.println("hello word 1");
  4. return "done";
  5. }
  6. public String sayHello2() {
  7. System.out.println("你好! 2");
  8. return "完成";
  9. }
  10. public void sayHello3() {
  11. System.out.println("我会被代理,但是callbackFilter里面设置的处理sayHello3方法是不做任何代理逻辑,直接调用真实方法. 3");
  12. }
  13. public final void sayHello4() {
  14. System.out.println("我是final方法,用cglib方式代理的时候,我不会被代理. 4");
  15. }
  16. }

代理处理逻辑 SayHelloMethodInterceptor1.java 和SayHelloMethodInterceptor2.java

  1. public class SayHelloMethodInterceptor1 implements MethodInterceptor {
  2. @Override
  3. public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  4. System.out.println("SayHelloMethodInterceptor1 do. param:"+ Arrays.toString(args) );
  5. System.out.println("before...");
  6. //通过调用MethodProxy.invokeSuper()方法,将调用转发给原始对象
  7. Object obj = methodProxy.invokeSuper(o, args);
  8. System.out.println(obj);
  9. System.out.println("after...");
  10. return obj;
  11. }
  12. }
  13. public class SayHelloMethodInterceptor2 implements MethodInterceptor {
  14. @Override
  15. public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
  16. System.out.println("SayHelloMethodInterceptor do.param:"+ Arrays.toString(args) );
  17. System.out.println("前置方法");
  18. //通过调用MethodProxy.invokeSuper()方法,将调用转发给原始对象
  19. Object obj = methodProxy.invokeSuper(o, args);
  20. System.out.println(obj);
  21. System.out.println("后续方法");
  22. return obj;
  23. }
  24. }

设置不同方法用不同代理逻辑CallbackFilterImpl.java

  1. public class CallbackFilterImpl implements CallbackFilter {
  2. // 这里设置真实对象不同的方法被调用,使用不同的MethodInterceptor代理逻辑来吹了
  3. @Override
  4. public int accept(Method method) {
  5. String methodName = method.getName();
  6. if ("sayHello1".equals(methodName)) {
  7. return 0; // sayHello1()方法使用callbacks[0]对象拦截。
  8. } else if ("sayHello2".equals(methodName)) {
  9. return 1; // sayHello2()方法使用callbacks[1]对象拦截。
  10. }else if ("sayHello3".equals(methodName)) {
  11. return 2; // sayHello3()方法使用callbacks[2]对象拦截。
  12. }
  13. return 0;
  14. }
  15. }

Main方法调用 

  1. public class MainClassCglib {
  2. public static void main(String[] args) {
  3. // 2. 然后在需要使用真实对象的时候,通过CGLIB动态代理获取代理对象。
  4. //通过CGLIB的Enhancer来指定要代理的目标对象
  5. Enhancer enhancer = new Enhancer();
  6. enhancer.setSuperclass(SayHelloImp.class);
  7. //指定实际处理代理逻辑的对象 这样只设置了一个MethodInterceptor,真实类所有的方法都被同一个MethodInterceptor处理
  8. //enhancer.setCallback(new SayHelloMethodInterceptor1());
  9. // 回调实例数组
  10. Callback[] callbacks = new Callback[] { new SayHelloMethodInterceptor1(), new SayHelloMethodInterceptor1(), NoOp.INSTANCE };
  11. enhancer.setCallbacks(callbacks);
  12. enhancer.setCallbackFilter(new CallbackFilterImpl());
  13. //通过调用create()方法得到代理对象
  14. //对这个对象所有非final方法的调用都会转发给MethodInterceptor.intercept()方法
  15. SayHelloImp star = (SayHelloImp)enhancer.create();
  16. star.sayHello1();
  17. star.sayHello2();
  18. star.sayHello3();
  19. star.sayHello4();
  20. }
  21. }

结果

 

三、JDK动态代理和Gglib动态代理的区别

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

FastClass机制的原理简单来说就是:为代理类和被代理类各生成一个Class,这个Class会为代理类或被代理类的方法分配一个index(int类型)。 这个index当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/562254
推荐阅读
相关标签
  

闽ICP备14008679号