代理模式:即通过代理对象访问目标对象,实现目标对象的方法。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,实现对目标功能的扩展。
这涉及到一个编程思想:不要随意去修改别人已经写好的代码或者方法(有坑)。如果需要修改,可以通过代理模式实现。
代理模式通常有三种实现写法:静态代理、动态代理、Cglib代理。
我们依次说下这三种代理模式:
我们现有 AnimalsDao接口和其实现AnimalsDaoImpl实现类,有两个方法,run和eat。
public interface AnimalsDao {
//提供两个方法
void run();
void eat();
}
public class AnimalsDaoImpl implements AnimalsDao{
@Override
public void run() {
System.out.println("run");
}
@Override
public void eat() {
System.out.println("eat");
}
}
现在我们想在run或者eat方法里之前做一些操作。
1.静态代理
public class StaticProxy implements AnimalsDao{
@Override
public void run() {
System.out.println("StaticProxy--------->");
dao.run();
}
@Override
public void eat() {
System.out.println("StaticProxy--------->");
dao.eat();
}
private AnimalsDao dao;
public StaticProxy(AnimalsDao dao){
this.dao=dao;
}
}
说明:静态代理通过实现目标对象接口,然后调用相同方法来实现代理。这种方式的缺点显而易见,当目标对象接口方法变动时,直接影响到代理类,需要对代理类进行修改,十分不方便。而且如果目标对象接口方法较多时,代理类也十分臃肿,不便维护。
2.动态代理
public class DynamicProxy {
//要代理的对象
private Object obj;
public DynamicProxy(Object obj){
this.obj=obj;
}
public Object getObjProxyIntance(){
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//执行目标对象方法
System.out.println("DynamicProxy--------->");
return method.invoke(obj,args);
}
});
}
}
说明:动态代理模式主要借助JDK代理对象API java.lang.reflect.Proxy来实现的,所以也称作JDK代理。我们看一下JDK这个类,其中重要的一个方法如下:
这个方法的三个参数:
ClassLoader loader 目标对象类加载器
Class>[] interfaces 目标对象接口类型
InvocationHandler h 事物处理,在这里面可以实现自己想要的逻辑
根据以上,可以看出动态代理实现要求目标对象必须有实现接口。代理类不必实现接口。
3.Cglib代理
要实现Cglib代理,必须引入cglib.jar 包,由于Spring-core包中已经包含了cglib功能,且大部分Java项目均引入了spring 相关jar包,这边使用spring的cglib来讲解。(他俩实现方式都是一样的)
public class CglibProxy implements MethodInterceptor {
//目标对象
private Object obj;
public CglibProxy(Object obj){
this.obj=obj;
}
//给目标对象创建一个代理对象
public Object getProxyInstance(){
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(obj.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CglibProxy--------->");
return method.invoke(obj,objects);
}
}
说明:可以看出,Cglib代理模式实现不需要目标对象一定实现接口,故目标对象如果没有实现接口,可以使用cglib代理模式。其实Spring的代理模式也是这么实现的。
Spring的代理模式:如果容器目标对象有接口,使用JDK动态代理,如果没有接口,使用cglib动态代理。
1.https://www.cnblogs.com/cenyu/p/6289209.html
2.Spring 4.0 源代码
https://github.com/JavaZWT/designPatterns