1. 简单介绍
- 通过代理类可以用来控制对象的访问,虽然我在 反射.那一章已经了解了以下静态和动态代理,但是还是在这里重新记录一下吧;
代理模式的理解:就是指某个类(被代理类)可以有很多的方法(理解为可以通过这些方法实现某个功能),然后就是在这些方法中很多的方法都是重复的,只有部分方法是需要改变的(必须按某种顺序才能实现某个功能,大部分为流程重复,只有少部分核心方法需要修改),这时就可以创建一个代理类,将所有的重复流程全部在代理类中完成,而被代理类就只是需要完成它自己的核心业务就可以了;
- 代理角色:抽象角色(拥有代理和真实角色的共有方法)、真实角色(实现抽象角色,含有真正的核心业务,核心业务就是指只有它有)、代理角色(实现抽象角色,真实角色的代理,在实现真实方法的同时,可以附带自己的方法);总的流程控制还是在代理模式中执行;
2. 静态代理
- 就比如你要租房子,但是不一定非要你去找,你可以找中介,而你最后要做的也不过就是了解了,然后签合同;这次就以这个为核心编写一个简单的静态代理代码;
第一步:先创建一个接口(含有两个实现类共有的抽象方法)
//定义一个接口;
public interface ProxyClass {
//一个找房子的方法;
void find();
//一个签合同的方法;
void signContract();
}
第二步:创建一个实体类(被代理类)
//创建一个客户类作为被代理类
public class Client implements ProxyClass{
//这里都是用户也可以执行的方法;
@Override
public void find() {
System.out.println("用户自己寻找房子");
}
@Override
public void signContract() {
System.out.println("用户自己签合同");
}
}
第三步:创建一个代理类
//创建一个类似中介的类(代理类),这个类要实现代理接口
public class Intermediary implements ProxyClass{
//由于需要用到被代理类中的方法,自然就需要被代理类的对象
private ProxyClass proxyClass;
//通过构造方法的形式将被代理类对象传进来
public Intermediary(ProxyClass proxyClass) {
this.proxyClass = proxyClass;
}
@Override
public void find() {
System.out.println("由中介找房");
}
/*这个方法是代理类特有的方法,也就是说,其实代理类除了拥有和被代理类
一样的方法,也会拥有它自己的方法;
*/
public void compare() {
System.out.println("由中介比较");
}
@Override
public void signContract() {
//这里就可以调用被代理类中的同名核心方法了;
proxyClass.signContract();
}
}
测试类:
class Test{
public static void main(String[] args) {
Intermediary intermediary = new Intermediary(new Client());
intermediary.find();
intermediary.compare();
intermediary.signContract();
}
}
测试结果:
3. 动态代理(dynamic proxy)
- 生成动态代理的方式:JDK自带的动态代理,javaassist字节码操作库,CGLIB,ASM;
- 使用JDK自带的动态代理,有个必须使用的类是java.lang.reflect.Proxy,这个类可以动态生成代理类和对象;还有一个必须使用的接口是java.lang.reflect.InvocationHandler(处理器接口),使用invoke对放射得到的方法直接进行代理,在放射那一节我也使用过;
还是使用静态代理的例子,只是稍加修改;虽然有些步骤重复,但是为了接下来更方便了解,还是重新添加一遍;
第一步:先创建一个接口(含有两个实现类共有的抽象方法)
//定义一个接口;
public interface ProxyClass {
//一个找房子的方法;
void find();
//一个签合同的方法;
void signContract();
}
第二步:创建一个实体类(被代理类)
//创建一个客户类作为被代理类
public class Client implements ProxyClass{
//这里都是用户也可以执行的方法;
@Override
public void find() {
System.out.println("用户自己寻找房子");
}
@Override
public void signContract() {
System.out.println("用户自己签合同");
}
}
** 第三步:不再是创建一个静态的代理类**
//创建一个类,用于动态处理被代理类;
public class ClientHandler implements InvocationHandler{
// 首先这个类中,肯定是和我们的被代理类相关,因为需要调用被代理类中的方法;
private ProxyClass proxyClass;//用多态放置对象;
//创建一个构造方法,将上面的对象传进来;
public ClientHandler(ProxyClass proxyClass) {
this.proxyClass = proxyClass;
}
// 在这个类中可以创建一些类似于代理类的方法;
public void compare() {
System.out.println("由中介比较");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(proxyClass, args);//使用上面传进来的真实类对象即可调用其中的方法;
return null;
}
}
测试类:需要注意的方法是,Proxy.newProxyInstance(当前类的加载,真实类的实现接口,实现接口InvocationHandler的类的对象)
class Test{
public static void main(String[] args) {
//定义一个被代理类的对象;
Client client = new Client();
ClientHandler handler = new ClientHandler(client);
ProxyClass procyclient = (ProxyClass) Proxy.newProxyInstance(Test.class.getClassLoader(), client.getClass().getInterfaces(), handler);
procyclient.find();
handler.compare();//一样可以在这个类中创建一些可能被代理类不存在的操作;
procyclient.signContract();//调用被代理类的方法;
}
}
测试结果:
从上面的测试结果可以知道这个动态代理类一样可以创建代理类里面需要的方法,在我看来,动态代理的最大优势就是可以代理不同的真实类;比如:有一个实现了Star接口的真实类realStar类,那么只需要在Test的时候修改一下真实类的实现参数接口,就可以了,万一又忘了就照这个模式实践;