Spring(十)代理模式和jdk动态代理的例子
代理模式是一种常用的设计模式,主要是为了解耦合度和增加类的功能。
我们给出以下场景,我们写了一个类,并且已经运行几个月了,这个时候我们想要增强一下它的功能,并且不破坏原代码,就需要代理模式了。
代理模式有三个类 接口 目标类 代理类 代理类和目标类都要实现接口的方法,并且代理类要调哟目标类的方法,依次可以解耦合并且提供代码的复用性。
给出类子如下
首先我们给出一个接口 Role,并且有三个方法
public interface Role {
public void address();
public void skill();
public void name();
}
这就是接口
然后我们写一个类来实现接口,并且给出返回的方法
public class Huiliyi implements Role {
@Override
public void address() {
System.out.println("东京");
}
@Override
public void skill() {
System.out.println("审判");
}
@Override
public void name() {
System.out.println("绘梨衣");
}
}
并且通过程序运行一下
public class main {
public static void main(String[] args) {
Role hui = new Huiliyi();
hui.name();
hui.address();
hui.skill();
}
}
结果如下
绘梨衣
东京
审判
那么此时,我们想要增强一下这个类的方法,那么我们就可以这样做
public void address() { System.out.print("增强这个方法"); System.out.println("东京"); }
结果如下 增强这个方法东京
但问题是这样就违反了OCP原则,修改了源码,那么我们可以新建一个类继承这个类,在新建的类中完成代码增强:如下
public class zengqiang extends Huiliyi {
public void name() {
System.out.print("最温暖的");
System.out.println("绘梨衣");
}
}
public class main {
public static void main(String[] args) {
Role hui = new zengqiang();
hui.name();
}
}
但问题是这样会导致 类爆炸 ,并且代码的复用性比较低一下 。因此我们可以新写一个类,通过属性的方式来增强
public class zengqiang implements Role {
private Huiliyi huiliyi;
public zengqiang(Huiliyi huiliyi) {
this.huiliyi = huiliyi;
}
@Override
public void address() {
System.out.print("天空树");
huiliyi.address();
}
@Override
public void skill() {
System.out.print("无情的");
huiliyi.skill();
}
@Override
public void name() {
System.out.print("温暖的");
huiliyi.name();
}
}
那么我们的测试类应该是
public class main {
public static void main(String[] args) {
Huiliyi huiliyi = new Huiliyi();
Role zengqiang = new zengqiang(huiliyi);
zengqiang.skill();
zengqiang.name();
zengqiang.address();
}
}
并且可以输出对应的结果。
这就是静态代理,通过低耦合的方式来增强原有的类,但是静态代理会导致类爆炸,如果类多的话我们需要重写大量的方法,并且保存在硬盘上。
所幸,我们有动态代理技术,并不需要我们在手写多余的步骤,我们只需要写一下 增强代码部分
接下来还是上面的例子来介绍一下动态代理
动态代理是由jdk完成(我们只介绍jdk方式,当然还有别的jar包提供,但我不在记录)
在程序运行时在内存中动态生成代理类的字节码,然后执行,并不会在硬盘上留下痕迹
public class main {
public static void main(String[] args) {
// 创建目标对象
Role hui = new Huiliyi();
// 创建代理对象 类加载器 代理类要实现的接口 调用处理器
/* new Proxy.newProxyInstance ---->创建代理类对象
* 我们要在代理类中使用 目标类的方法,必须创建出目标类,那么就必须需要获得原来的类加载器,创建对象
* 代理类要实现的接口其实就是接口类,面向接口编程可以降低耦合度
* 调用处理器是我们增强的代码部分
* */
zengqiang zengqiang = new zengqiang();
Role proxy = (Role) Proxy.newProxyInstance(hui.getClass().getClassLoader(), hui.getClass().getInterfaces(), zengqiang);
// 调用代理方法
proxy.name();
proxy.address();
}
}
public class zengqiang implements InvocationHandler {
/*
* 用来写增强代码
* 当代理对象调用代理方法的时候,注册在代理处理器中的invoke会被调用,自动调用
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("温柔的");
return null;
}
}
只要代理类调用代理方法,就会调用invokef方法,但是这样只会调用invoke方法,不会调用目标类的目标方法。
java会自动调用实现接口的代理类的代理方法 ----->需要在代理类中完成目标方法的使用 ,看一看invoke的三个参数
完善的代理类如下
/*
* 用来写增强代码
* 当代理对象调用代理方法的时候,注册在代理处理器中的invoke会被调用,自动调用
* Object proxy 代理类
* Method method 目标方法
* Object[] args 目标方法上的实参
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("温柔的");
Object r = method.invoke(target,args);
return null;
}
我们先要有一个目标对象 ,然后 调用目标对象的方法,完成使用目标对象。
总结一下代理类的全部过程。
首先我们有个类,需要动态代理增强方法,首先要创建代理类对象,调用jdk的
Proxy.newProxyInstance();
分别传入 目标类加载器 接口方法 代理器
然后我们需要写代理器实现InvocationHandler接口 重写invoke方法,在调用代理类的代理方法的时候会自动调用invoke ,同时为了使用目标类的目标方法,需要创建目标类 并且进行赋值,最后完成动态代理。
因篇幅问题不能全部显示,请点此查看更多更全内容