静态代理
说动态代理之前咱看看静态代理是啥吧,毕竟各个关于动态代理的文章都会提到静态代理。
我理解的静态代理就是:
比如我有一个类A,然后现在需要给A添加一些操作,但是又不想去修改A本来的代码,那么咱可以写一个A的代理类AProxy,在代理类中注入A的对象,再对A的操作进行维护。
听上去还是挺有用的哈,但是如果使用很多很多静态代理的话,系统中的类会非常多,不便于维护。那咋办呢,所以才要有动态代理嘛。
动态代理
第一次听说这个词呢还是力哥给我讲项目的时候提到的,然后介绍了下在我们项目中应用的场景:
Mybatis中,我们想要获取sqlsession之后,只执行一次mapper就关闭sqlsession,于是去动态代理了MapperProxy,在其自带的功能上,附加上了自动关闭sqlsession的功能。
与静态代理相比,功能其实都是为现有的类添加功能,但是也有区别:
静态代理的类是程序运行前就存在的,动态代理是在运行时,通过反射去实现的。
动态代理做了啥呢:
比如我们有一个obj1,动态代理其实就是要在obj1的基础上生成一个obj2对象,obj2与obj1具有相同的类型,但obj2对象可以在其invoke方法里面对obj1的方法进行进一步的操作。
以下给出一个动态代理的例子:
// 一个接口
public interface Sister {
void getName();
void speak();
}
//一个接口实现类
public class XinYi implements Sister {
@Override
public void getName() {
System.out.println("心怡妹妹");
}
@Override
public void speak() {
System.out.println("不要天天早上都迟到!!!");
}
}
//一个动态代理类
public class SisterProxy implements InvocationHandler {
Object obj1;
public SisterProxy(Object obj1){
this.obj1=obj1;
}
/**
* @param proxy 被代理后的对象,而不是代理之前的对象,这里就是指的obj2对象
* @param method 被代理obj1的方法
* @param args 被代理的obj1方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object cc= method.invoke(this.obj1, args);
System.out.println("这里是代理");
return cc;
}
}
//测试类
public class TestSister {
public static void main(String[] args) {
Sister xinyi = new XinYi();
Sister sister =
(Sister)Proxy.newProxyInstance(SisterProxy.class.getClassLoader(), new Class[]{Sister.class}, new SisterProxy(xinyi));
sister.getName();
sister.speak();
}
}
输出结果:
心怡妹妹
这里是代理
不要天天早上都迟到!!!
这里是代理
可以看到上面使用了 Proxy.newProxyInstance创建了一个sister对象,而本来的xinyi对象运行输出应该只有两句话,而经过动态代理之后,输出有了四句话,多出来的“这里是代理”就是在代理类的invoke方法中添加的。
Proxy.newProxyInstance的三个参数分别是,类加载器,接口列表,动态代理类,以下分别介绍:
1. 类加载器:一般使用应用类加载器,这里使用的当前类的加载器,结果都是一样的
2. 接口列表:被代理的类所继承的接口列表,Class[]类型,注意一定是接口,不能是类,不然得用CGLIB去代理,当前咱这样是JDK代理。Proxy会通过反射去找到对应的方法,进行代理。
3. 动态代理类:也就是实现InvocationHandler的对象,代理的时候会去只行其中的invoke方法。
以上就是今天学的动态代理内容(其实学了很多次了,没总结就会忘。。),内容多来自力哥博客:https://www.jianshu.com/p/2b442b818b16
还有我没看完但是感觉很详细的对newProxyInstance的剖析:https://my.oschina.net/u/2264912/blog/1592613
然后今天为什么会想到学动态代理呢,是因为在学设计模式的时候,那个pdf里面的抽象工厂模式,举的例子为Redis集群,各个集群的操作redis的方法不一样,通过设计了响应的适配类(继承自同一个接口),来实现方法调用的统一。然后最后测试在选择调用哪个类型的时候,使用的是动态代理去获取的具体对象。
当时看着好牛逼,就回头来学动态代理,结果学完发现好像是在脱了裤子放屁,都把适配类写好了,动态代理类里面也啥都没干,就是用来创建对象了。(后边怀疑是模仿Redis集群的真实环境,需要用动态代理里面的反射去创建不同地方的对象?)
结果又一看,好像抽象工厂模式和pdf里面讲的根本不一样,好家伙,我直接好家伙。。。