静态代理以及jdk动态代理
近期接触了一个项目里面用到了动态代理,自己发现对动态代理的理解还不够深入,于是重新对代理进行了学习。
学习自https://blog.csdn.net/luanlouis/article/details/24589193
动态代理的一部分代码引用自某博客,当时未保存博客地址,故无法给出引用。
静态代理
静态代理的使用场景
public interface TicketService {
//售票
public void sellTicket();
//问询
public void inquire();
//退票
public void withdraw();
}
定义一个接口
public class Station implements TicketService {
@Override
public void sellTicket() {
System.out.println("\n\t售票.....\n");
}
@Override
public void inquire() {
System.out.println("\n\t问询。。。。\n");
}
@Override
public void withdraw() {
System.out.println("\n\t退票......\n");
}
}
实现了这个接口
这时如果需要在售票前显示一下金额,直观的解决方式是直接在sellTicket加入一个显示金额的语句
public class Station implements TicketService {
@Override
public void sellTicket() {
System.out.println("\n\t显示金额.....\n");
System.out.println("\n\t售票.....\n");
}
@Override
public void inquire() {
System.out.println("\n\t问询。。。。\n");
}
@Override
public void withdraw() {
System.out.println("\n\t退票......\n");
}
}
但是这种方式并不合理,因为这个实现类并不是仅仅在此被调用,还会被其他地方使用,直接修改会影响其他程序调用。
静态代理的实现
这时可以使用静态代理方法
方法的核心是生成一个静态代理类,将原对象通过构造方法传递给代理类,代理对象调用代理类的方法实际上是通过原对象调用原方法。
public class Client {
private static final Logger LOGGER = LoggerFactory.getLogger(Client.class);
//静态代理 将原对象 通过构造方法 传入到 代理类中,代理对象调用方法 实际是原对象去调用
public static void main(String[] args) {
LOGGER.trace("请求参数:content:{}", "1111");
StationProxy stationProxy=new StationProxy(new Station());
stationProxy.sellTicket();
}
}
新建一个原始类对象,通过构造方法将原始变量赋值给代理类里的Station station属性。代理对象调用代理类中的sellTicket方法。
public class StationProxy implements TicketService {
private Station station;
public StationProxy(Station station) {
this.station = station;
}
@Override
public void sellTicket() {
// 1.做真正业务前,提示信息
System.out.println("××××您正在使用车票代售点进行购票,每张票将会收取5元手续费!××××");
// 2.调用真实业务逻辑
station.sellTicket();
// 3.后处理
System.out.println("××××欢迎您的光临,再见!××××\n");
}
@Override
public void inquire() {
station.inquire();
}
@Override
public void withdraw() {
station.withdraw();
}
}
代理类方法中 通过原始类的对象调用原始类的方法
JDK动态代理
由上面静态代理可知,实现代理是通过代理类中的原始对象调用原始方法实现的。而JDK动态代理时通过InvocationHandler,由反射实现的。
JDK动态代理的实现
public interface Subject
{
public void rent();
public void hello(String str);
}
定义一个接口
public class RealSubject implements Subject {
@Override
public void rent()
{
System.out.println("I want to rent my house");
}
@Override
public void hello(String str)
{
System.out.println("hello: " + str);
}
}
实现这个接口
public class InvocationHandlerImpl implements InvocationHandler {
// 这个就是我们要代理的真实对象
private Object subject;
// 构造方法,给我们要代理的真实对象赋初值
public InvocationHandlerImpl(Object subject)
{
this.subject = subject;
}
@Override
public Object invoke(Object object, Method method, Object[] args)
throws Throwable
{
// 在代理真实对象前我们可以添加一些自己的操作
System.out.println("before rent house");
System.out.println("Method:" + method);
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(subject, args);
// 在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after rent house");
return null;
}
}
实现了InvocationHandler接口,并重写invoke方法。
public class ClienDynamic {
public static void main(String[] args)
{
// 我们要代理的真实对象
Subject realSubject = new RealSubject();
// 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new InvocationHandlerImpl(realSubject);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
.getClass().getInterfaces(), handler);
System.out.println(subject.getClass().getName());
subject.rent();
subject.hello("world");
}
}
测试类
动态代理的结果
JDK动态代理的原理分析
Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject
.getClass().getInterfaces(), handler);
System.out.println(subject.getClass().getName());
subject.rent();
subject.hello("world");
上面的代码中通过这种方式创建代理对象,并通过代理对象去调用,注意调用的方法是生成的代理类里对应的方法。
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
Proxy.newProxyInstance()方法中有一段这个代码,先是把我们自定义的handler 赋值给了代理类,然后新建了代理类的对象返回。
这一步我目前理解是生成一个实现了参数interfaces里所有接口且继承了Proxy的代理类的字节码(.class文件),然后用参数里的classLoader加载这个代理类。
然后通过反编译软件可以看到如下代码(以下代码来自于参考博客里的例子,方法名是不一致的)
import com.foo.proxy.Rechargable;
import com.foo.proxy.Vehicle;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
/**
生成的动态代理类的组织模式是继承Proxy类,然后实现需要实现代理的类上的所有接口,而在实现的过程中,则是通过将所有的方法都交给了InvocationHandler来处理
*/
public final class ElectricCarProxy extends Proxy
implements Rechargable, Vehicle
{
private static Method m1;
private static Method m3;
private static Method m4;
private static Method m0;
private static Method m2;
public ElectricCarProxy(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{ // 方法功能实现交给InvocationHandler处理
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 void rent()
throws
{
try
{
// 方法功能实现交给InvocationHandler处理
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void hello()
throws
{
try
{
// 方法功能实现交给InvocationHandler处理
this.h.invoke(this, m4, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
// 方法功能实现交给InvocationHandler处理
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
// 方法功能实现交给InvocationHandler处理
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{ //为每一个需要方法对象,当调用相应的方法时,分别将方法对象作为参数传递给InvocationHandler处理
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.foo.proxy.Rechargable").getMethod("recharge", new Class[0]);
m4 = Class.forName("com.foo.proxy.Vehicle").getMethod("drive", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
测试类中调用对应的方法,即调用了上面代理类里对应的方法,如:
public final void rent()
throws
{
try
{
// 方法功能实现交给InvocationHandler处理
this.h.invoke(this, m3, null);
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
this.h 即由Proxy.newProxyInstance()传递进来的InvocationHandler handler = new InvocationHandlerImpl(realSubject); handler对象。
我们可以看到 代理类继承与Proxy类,ElectricCarProxy extends Proxy,handler属性定义于Proxy类中。
public class Proxy implements java.io.Serializable {
private static final long serialVersionUID = -2222568056686623797L;
/** parameter types of a proxy class constructor */
private static final Class<?>[] constructorParams =
{ InvocationHandler.class };
/**
* a cache of proxy classes
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
/**
* the invocation handler for this proxy instance.
* @serial
*/
protected InvocationHandler h;
最終this.h.invoke(this, m3, null);其实是调用了InvocationHandlerImpl中的重写的invoke方法。
@Override
public Object invoke(Object object, Method method, Object[] args)
throws Throwable
{
// 在代理真实对象前我们可以添加一些自己的操作
System.out.println("before rent house");
System.out.println("Method:" + method);
// 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
method.invoke(subject, args);
// 在代理真实对象后我们也可以添加一些自己的操作
System.out.println("after rent house");
return null;
}
}
方法内部再通过反射,执行原始类里的对应的方法。