Java代理模式(1)一静态代理
Java代理模式(2)一动态代理
Java代理模式(3)一CGLib代理
之前Java代理模式(1)已经介绍了Java的静态模式,其缺点也已经说明。为此引出了Java的动态代理。
静态代理:
动态代理:
java.lang.reflect.InvocationHandler
与java.lang.reflect.Proxy
)既然动态代理提到了反射,那么就不得不说与动态代理有关的这两个Java API
:
java.lang.reflect.InvocationHandler
InvocationHandler
的invoke
方法中invoke
方法完成代理,在代理过程中invoke
会根据传入的代理对象、方法名称以及参数决定调用代理的哪个方法。
public interface InvocationHandler {
//Object proxy:需要被代理的对象
//Method method:被代理对象委托的方法
//Object[] args:方法调用时所需要参数
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
java.lang.reflect.Proxy
代理类是通过Proxy.newProxyInstance()
来生成的,
ClassLoader loader
: 定义代理类的类加载器 Class>[] interfaces
:代理类要实现的接口列表InvocationHandler h
: 指派方法调用的调用处理程序,即实现InvocationHandler
接口的调用处理程序public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
利用之前(1)中所举例的例子完成一个完成的动态代理例子:
(1)目标对象实现的接口:ProblemInterface
:
public interface ProblemInterface {
void resolve();//解决问题
}
(2)目标对象:RealSubject
public class RealSubject implements ProblemInterface{
@Override
public void resolve() {
System.out.println("There is an fatal bug in xxx project, It mainly includes...");
}
}
(3)DynamicProxyHandler
:实现InvocationHandler
接口的调用处理类,用来生成代理对象、
public class DynamicProxyHandler implements InvocationHandler{
//1.目标委托类即RealSubject
private Object targetObject;
/**
* 2.委托类与代理类绑定关系:根据传入的目标对象返回一个代理对象
* @param targetObject
* @return proxyObject
*/
public Object getProxyInstance(Object targetObject){
this.targetObject=targetObject;
//targetObject.getClass().getClassLoader():指定产生代理对象的类加载器(需要将其指定为和目标对象同一个类加载器 )
//targetObject.getClass().getInterfaces():目标对象委托类的所有实现的接口(代理类要实现的接口序列是与目标对象是相同的)
//this:指派方法调用的调用处理程序,即实现InvocationHandler接口的调用处理程序
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
/**
* 3.调用处理器根据这三个参数决定调用代理的哪个方法
*/
//Object proxy:需要被代理的对象
//Method method:被代理对象委托的方法
//Object[] args:方法调用时所需要参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=method.invoke(targetObject, args);//通过反射调用真实业务对象的业务方法,并且返回
return result;
}
}
(4)客户端测试类:DynamicClient
public class DynamicClient {
public static void main(String[] args) {
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
//传入目标对象new RealSubject()之后获得动态代理对象
ProblemInterface proxy = (ProblemInterface)dynamicProxyHandler.getProxyInstance(new RealSubject());
//代理目标对象的业务
proxy.resolve();
}
}
输出结果为如下,RealSubject
目标对象的resolve()
方法得到了代理
There is an fatal bug in xxx project, It mainly includes…
之后我们在ProblemInterface
中随便增加add()
方法来更加深入理解静态代理与动态代理的的区别
public interface ProblemInterface {
void resolve();//解决问题
void add();
}
真实对象RealSubject
必须实现add()
方法:
public class RealSubject implements ProblemInterface{
@Override
public void resolve() {
System.out.println("There is an fatal bug in xxx project, It mainly includes...");
}
public void add() {
System.out.println("This is add() method");
}
}
Java静态代理:Proxy
必须还要实现add()
方法,才能代理成功
public class Proxy implements ProblemInterface{
private ProblemInterface problemInterface = new RealSubject();//小李的问题已经得到反映
@Override
public void resolve() {
System.out.println("I'm preparing for it");//领导A先准备好材料
problemInterface.resolve();//开始与经理B沟通反映
System.out.println("In a word, I think the problem...");//结束后领导A做了总结
}
@Override
public void add() {
problemInterface.add();//增加的方法
}
}
而在动态代理中,只需要需要委托的目标对象实现add()
方法之后,再增加一个方法调用proxy.add()
即可
public class DynamicClient {
public static void main(String[] args) {
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
//传入目标对象new RealSubject()之后获得动态代理对象
ProblemInterface proxy = (ProblemInterface)dynamicProxyHandler.getProxyInstance(new RealSubject());
//代理目标对象的业务
proxy.resolve();
//增加方法
proxy.add();
}
}
再比如我们再需要代理另外一个目标对象RealSubject2
的业务:
public class RealSubject2 implements ProblemInterface{
@Override
public void resolve() {
System.out.println("I am RealSubject2");
}
public void add() {
System.out.println("This is add() method");
}
}
如果是静态代理还得像Java代理模式(1)一样再创建一个Poxy2
代理类代理RealSubject2
,这样会很麻烦,代码量自然会增加。而使用动态代理方式后,只需要再创建调用处理类然后再传入需要代理的RealSubject2
目标对象即可。
public class DynamicClient {
public static void main(String[] args) {
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler();
DynamicProxyHandler dynamicProxyHandler2 = new DynamicProxyHandler();
//传入目标对象new RealSubject()之后获得动态代理对象
ProblemInterface proxy = (ProblemInterface)dynamicProxyHandler.getProxyInstance(new RealSubject());
//再代理new RealSubject2()
ProblemInterface proxy2 = (ProblemInterface)dynamicProxyHandler2.getProxyInstance(new RealSubject2());
//RealSubject的需要代理的业务
proxy.resolve();
proxy.add();
//RealSubject2的需要代理的业务
proxy2.resolve();
proxy2.add();
}
}
最后的代理结果:
There is an fatal bug in xxx project, It mainly includes...
This is add() method
I am RealSubject2
This is add() method
虽然JDK的动态代理已经基本满足代理要求,但只是局限于实现接口的被代理类,而在大多数的业务情况下如果遇到需要代理并没有实现接口类的目标对象时,应该使用CGLib
动态代理(Java代理模式(3)一CGLib代理)。典型框架Spring AOP
就运用了JDK动态代理与CGLib
动态代理两者的结合。