代理就好比我们的代购,比如我们想要在美国的商家买一双球鞋,但是我们不能够直接去美国买,于是我就可以向代购买,代购将从美国买回来的鞋子卖给我们,并且获得利益.
在java中就是类A想要调用类C的方法,但是没有权限来访问类C,但是B有权限访问类C,我们就可以通过调用类B的方法来访问类C,那么类B就是我们所说的代理类.
代理模式的作用就是:
1.控制访问 即类B有权限访问类C, 例子中就是代购可以去美国买球鞋,但是我们不能
2.增强功能 即类B调用了类C的方法,在此基础之上还能增加自己想要的功能,例子中就是代购买了球鞋,可以增加球鞋的价格
来卖给我们,进而获取利益
定义业务接口 ShoeSell(目标接口),其中含有抽象方法 sell(int amount), sell 是目标方法
代码如下(示例):
package jmu.czx.service;
public interface ShoeShell {
//定义方法 参数 amount:表示一次购买的数量,暂时不用
//返回值表示一双球鞋的价格。
float sell(int amount);
}
代码如下(示例):
package jmu.czx.factory;
import jmu.czx.service.ShoeShell;
public class USAFactory implements ShoeShell {
@Override
public float sell(int amount) {
//可以根据 购买的数量 amount有其他优惠
return 1000;
}
}
创建A代购
package jmu.czx.daigou;
import jmu.czx.factory.USAFactory;
import jmu.czx.service.ShoeShell;
public class A implements ShoeShell {
private USAFactory usaFactory=new USAFactory();
@Override
public float sell(int amount) {
float price = usaFactory.sell(amount);
//在单价之上增加100元作为利润
return price+100;
}
}
创建B代购
package jmu.czx.daigou;
import jmu.czx.factory.USAFactory;
import jmu.czx.service.ShoeShell;
public class B implements ShoeShell {
private USAFactory usaFactory=new USAFactory();
@Override
public float sell(int amount) {
float price=usaFactory.sell(amount);
//在单价之上增加80元作为利润
return price+80;
}
}
package jmu.czx;
import jmu.czx.daigou.A;
import jmu.czx.daigou.B;
public class Test {
public static void main(String[] args) {
float price=0.0f;
A a=new A();
price=a.sell(1);
System.out.println("A代购的price为:"+price);
System.out.println("===========================");
B b=new B();
price=b.sell(1);
System.out.println("B代购的price为:"+price);
}
}
(1) 代码复杂,难于管理
代理类和目标类实现了相同的接口,每个代理都需要实现目标类的方法,这样就出现了大量的代码重复。如果接口增加一个方法,除了所有目标类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
(2) 代理类依赖目标类,代理类过多代理类只服务于一种类型的目标类,如果要服务多个类型。势要为每一种目标类都进行代理,静态代理在程序规模稍大时就无法胜任了,代理类数量过多。
所以这时候就需要我们用到动态代理。
动态代理是指代理类对象在程序运行时由 JVM 根据反射机制动态生成的。动态代理不需要定义代理类的.java 源文件。动态代理其实就是 jdk 运行期间,动态创建 class 字节码并加载到 JVM。动态代理的实现方式常用的有两种:使用 JDK 代理代理,与通过 CGLIB 动态代理。
而本文主要讲的是JDK动态代理,需要用到 InvocationHandler 接口 ,Method 类 ,
Proxy 类
接下来对静态代理进行改写,来实现动态代理,可以先记住语法,背下来也行,以后再慢慢理解
(1) InvocationHandler 接口
InvocationHandler 接口叫做调用处理器,负责完调用目标方法,并增强功能。通 过 代 理 对 象 执 行 目 标 接 口 中 的 方 法 , 会 把 方 法 的 调 用 分 派 给 调 用 处 理 器 (InvocationHandler)的实现类,执行实现类中的 invoke()方法,我们需要把功能代理写在 invoke()方法中
接口中只有一个方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy:代表生成的代理对象
method:代表目标方法
args:代表目标方法的参数
(2) Method 类
invoke()方法的第二个参数为 Method 类对象,该类有一个方法也叫 invoke(),可以调用
目标方法。这两个 invoke()方法,虽然同名,但无关。
public Object invoke ( Object obj, Object... args)
obj:表示目标对象
args:表示目标方法参数,就是其上一层 invoke 方法的第三个参数
该方法的作用是:调用执行 obj 对象所属类的方法,这个方法由其调用者 Method 对
象确定。
在代码中,一般的写法为
method.invoke(target, args);
其中,method 为上一层 invoke 方法的第二个参数。这样,即可调用了目标类的目标
方法
(3) Proxy 类
通 过 JDK 的 java.lang.reflect.Proxy 类 实 现 动 态 代 理 , 会 使 用 其 静 态 方 法
newProxyInstance(),依据目标对象、业务接口及调用处理器三者,自动生成一个动态代理对
象
public static newProxyInstance ( ClassLoader loader, Class<?>[] interfaces,
InvocationHandler handler)
loader:目标类的类加载器,通过目标对象的反射可获取
interfaces:目标类实现的接口数组,通过目标对象的反射可获取
handler:调用处理器。
jdk 动态代理是代理模式的一种实现方式,其只能代理接口。
实现步骤
1、新建一个接口,作为目标接口
2、为接口创建一个实现类,是目标类 (到这边都和之前的代码步骤是一样的)
3、创建类实现 java.lang.reflect.InvocationHandler 接口,调用目标方法并增加其他功能代码
package jmu.czx.daigou;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MySellHandler implements InvocationHandler {
private Object target=null; //定义目标对象
public MySellHandler(Object target) {
//使用构造方法传入目标对象,给目标对象提供代理功能
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object res = null;
res = method.invoke(target,args); //执行目标方法,进行访问控制
if(res!=null)
{
float price =(float)res;
res=price+25; //在目标方法执行之后,增强功能,即提高价格
}
return res;
}
}
4、创建动态代理对象,使用 Proxy.newProxyInstance()方法,并把返回值强制转为接口类型
package jmu.czx;
import com.bjpowernode.service.UsbSell;
import jmu.czx.daigou.A;
import jmu.czx.daigou.B;
import jmu.czx.daigou.MySellHandler;
import jmu.czx.factory.USAFactory;
import jmu.czx.service.ShoeShell;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
// float price=0.0f;
// A a=new A();
// price=a.sell(1);
// System.out.println("A代购的price为:"+price);
// System.out.println("===========================");
// B b=new B();
// price=b.sell(1);
// System.out.println("B代购的price为:"+price);
//创建代理
ShoeShell target= new USAFactory();
//创建调用处理器
InvocationHandler handler= new MySellHandler(target);
//创建jdk动态代理
ShoeShell usa=(ShoeShell) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),handler);
//通过代理对象执行业务方法,实现利润增加
float price=usa.sell(1);
System.out.println("A代购的price为:"+price);
}
}
动态代理在spring,mybatis等框架中都会用到需要好好掌握
我的第一篇博客,有很多不足的地方,希望大家能够提意见进行改进。