先定义一个接口类,该接口是我们要代理的接口
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);
}
}
接下来是动态代理类, 该类必须实现InvocationHandler接口
public class DynamicProxy implements InvocationHandler
{
private Object subject;
public DynamicProxy(Object subject)
{
super();
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("before method:" + method.getName());
method.invoke(subject, args);
System.out.println(method);
System.out.println("after method:" + method.getName());
return subject;
}
}
接下来是测试类,用来测试动态代理的机制,以及作用
/*
* 动态代理的作用:
* 在实现要代理的对象的核心功能的基础上
* 添加额外的一些功能
*/
public class Client
{
@Test
public void mainTest()
{
// 利用代理机制创建了一个跟realSubject实现了相同接口的类
Subject realSubject = new RealSubject();
InvocationHandler handler = new DynamicProxy(realSubject);
// 制定要创建的代理实例使用的ClassLoader、要实现的哪些接口、代理该实例的代理类(invocationHandler)
Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass()
.getClassLoader(), new Class[]
{ Subject.class }, handler);
System.out.println(subject.getClass().getName() + "与" + realSubject
+ "作比较");
realSubject = null;
subject.rent();
subject.hello("world");
}
@Test
public void myProxy()
{
Subject realSubject = new RealSubject();
Class[] intefaces = realSubject.getClass().getInterfaces();
for (Class t : intefaces)
{
System.out.println("接口:" + t + "===========");
Method[] methods = t.getMethods();
for (Method m : methods)
{
System.out.println("执行方法:" + m.getName() + "=======");
System.out.println("before====>" + m.getName());
try
{
Class[] params = m.getParameterTypes();
if (params != null && params.length > 0)
{
m.invoke(realSubject, "World");
} else
{
m.invoke(realSubject);
}
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e)
{
e.printStackTrace();
}
System.out.println("after====>" + m.getName());
}
}
}
@Test
public void myProxy2()
{
Subject realSubject = new RealSubject();
Method rent;
try
{
rent = realSubject.getClass().getMethod("rent");
System.out.println("执行方法:" + rent.getName() + "=======");
System.out.println("before====>" + rent.getName());
rent.invoke(realSubject);
System.out.println("after====>" + rent.getName());
} catch (NoSuchMethodException | SecurityException e)
{
e.printStackTrace();
} catch (IllegalAccessException e)
{
e.printStackTrace();
} catch (IllegalArgumentException e)
{
e.printStackTrace();
} catch (InvocationTargetException e)
{
e.printStackTrace();
}
}
}
mainTest方法创建了一个realSubject的动态代理实例subject,当调用subject的方法时,会自动调用handler对象里面的invoke方法,在invoke方法里面,会调用我们要代理的对象(realSubject)的方法,我们可以在调用realSubject对象的方法前后加上一些其他的逻辑,这也是Spring AOP机制的实现原理
在看动态代理机制时,我有一个疑问,就是为什么要用到动态代理,需求何在?
网上搜了很多资料,很多答案都文绉绉的,看起来不是很好懂,就我自己的理解,使用动态代理,其实就是为了方便在实现一个对象的某个方法前后,添加一些其他的逻辑,如上的myProxy2()方法,使用反射也可以达到这个目的,但是这样的实现想比动态代理而言,逻辑性比较差,而且当动态代理使用的地方有多处时,前后添加的逻辑没能聚拢到一个地方,每次都要反射拿到方法,然后在执行方法的前后再添加逻辑,这样用不好维护,如果用动态代理,虽然创建代理对象时比较麻烦,但是当代理对象创建好以后,可以直接使用例如 subject.rent(); 这样的方式,直接调用方法,前后添加的逻辑在hanlder的invoke方法里面已经实现好了
要注意的一点是,subject对象实际上不是一个Subject类或者RealSubject类,而是一个com.sun.proxy.$Proxy这样的类
在handler对象的invoke方法里面,参数Object proxy 实际上没用用到,如果试着去打印出这个参数,会报错,具体原因我也不清楚,使用该方法,实际上用的是创建该handler时传进去的realSubject对象,而使用代理对象subject的方法时,会去调用handler里面的invoker方法,所以,当我们调用代理对象subject的方法时,其实是调用了真实对象
realSubject的方法
以上都是个人见解,如果有不对的地方,恳请大家帮忙指出,感激不尽