0
点赞
收藏
分享

微信扫一扫

【Java基础】动态代理原理

罗子僧 2022-02-04 阅读 39
java后端

JDK代理

基本使用

public class JDKProxy<T> implements InvocationHandler {

	private T target;

	public void setTarget(T target) {
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("jdk proxy before");
		Object ret = method.invoke(target, args);
		System.out.println("jdk proxy after");
		return ret;
	}

	public static void main(String[] args) {
		JDKProxy<TargetService> jdkProxy = new JDKProxy<>();
		jdkProxy.setTarget(new TargetService());
		Service service = (Service) Proxy.newProxyInstance(TargetService.class.getClassLoader(), TargetService.class.getInterfaces(), jdkProxy);
		service.print();

	}
}

原理

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import jiankunking.Subject;
 
public final class ProxySubject
  extends Proxy
  implements Subject
{
  private static Method m1;
  private static Method m3;
  private static Method m4;
  private static Method m2;
  private static Method m0;
  
  public ProxySubject(InvocationHandler paramInvocationHandler)
  {
    super(paramInvocationHandler);
  }
  
  public final boolean equals(Object paramObject)
  {
    try
    {
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String SayGoodBye()
  {
    try
    {
      return (String)this.h.invoke(this, m3, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String SayHello(String paramString)
  {
    try
    {
    // 这里传的是接口的方法, 第一个参数是代理类的实例
      return (String)this.h.invoke(this, m4, new Object[] { paramString });
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final String toString()
  {
    try
    {
      return (String)this.h.invoke(this, m2, null);
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  public final int hashCode()
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (Error|RuntimeException localError)
    {
      throw localError;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }
  
  static
  {
    try
    {
    	//由于jdk是代理的接口,所以关注下m3,m4 是接口的方法,而不是实现类的方法。
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("jiankunking.Subject").getMethod("SayGoodBye", new Class[0]);
      m4 = Class.forName("jiankunking.Subject").getMethod("SayHello", new Class[] { Class.forName("java.lang.String") });
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

public Object invoke(Object proxy, Method method, Object[] args)

proxy:是代理类的实例
method:是接口的方法,所以我们在使用spring中的aop时,获得方法时接口的方法;所以标注的在实现类中的注解时获得不到的。
args:参数

cglib代理

基本使用

public class CglibProxy<T> implements MethodInterceptor {

	private T target;

	public void setTarget(T target) {
		this.target = target;
	}

	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		System.out.println("cglib proxy before");
		//只调用自己的方法
		Object ret = method.invoke(target, objects);
		// 通过父类方法调用自己
//		methodProxy.invokeSuper(o, objects);
		System.out.println("cglib proxy after");
		return null;
	}

	public static void main(String[] args) {
		TargetService service = new TargetService();
		CglibProxy<TargetService> cglibProxy = new CglibProxy<>();
		cglibProxy.setTarget(service);

		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(service.getClass());
		enhancer.setCallback(cglibProxy);
		Service proxyService = (Service) enhancer.create();
		proxyService.print();
	}
}

原理

	// 通过子类调用父类的方法
    final void CGLIB$gotoHome$0() {
        super.gotoHome();
    }
    
    // 创建一个子类,重写父类的方法。 
    public final void gotoHome() {
        MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
        if (this.CGLIB$CALLBACK_0 == null) {
            CGLIB$BIND_CALLBACKS(this);
            var10000 = this.CGLIB$CALLBACK_0;
        }

        if (var10000 != null) {
        	// CGLIB$gotoHome$0$Method是被代理类的方法。
            var10000.intercept(this, CGLIB$gotoHome$0$Method, CGLIB$emptyArgs, CGLIB$gotoHome$0$Proxy);
        } else {
            super.gotoHome();
        }
    }

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)

o:代理类
method:实现类的方法,所以这种是可以获取到方法中的注解的。
objects:参数
methodProxy:方法代理,可以通过该类,调用子类的方法,在子类中调用父类的方法:

        // 直接调用被代理类的方法,所以在这个方法中如果调用自身的方法,是调用的被代理的方法 
		method.invoke(target, objects);
		// 调用父类中的代理方法,该方法调用父类的方法,
		// 如果在被代理类中调用自身方法,会调用子类的方法;
		methodProxy.invokeSuper(o, objects);

举例子:
使用method.invoke(target, objects);

public class TargetService implements Service {

	@Override
	public void print() {
		System.out.println("target method");
		// 调用自身方法
		test();
	}

	public void test() {
		System.out.println("target test ...");
	}
}

这里调用的被代理类的方法

cglib proxy before
target method
target test ...
cglib proxy after

使用methodProxy.invokeSuper(o, objects);
调用的是子类中的方法,所以在进入到test方法后会进入了代理方法。

cglib proxy before
target method
cglib proxy before
target test ...
cglib proxy after
cglib proxy after

所以在@Transactional的方法中,调用自身方法不能生效。而在@configuraton注解中生效,得到bean对象。(代理中判断如果有实例了就从IOC容器中取,否则就调用@Bean方法实例化。)

举报

相关推荐

0 条评论