代理模式是指为其他对象提供一个代理以控制该对象的访问。代理类主要负责为委托预处理消息、过滤消息、传递消息给委托类,代理类不实现具体服务,而是利用委托类来完成服务,并执行结果封装处理。

       其实就是代理类为被代理类预处理消息,过滤消息并在此之后将小心转发给被代理类,之后还能进行消息的后置处理。使用代理对象,是为了在不修改目标对象的基础上,增强主业务。

实现代理的方式:

1,静态代理:

  • 代理类是自己手工实现的,自己创建一个java类,表示代理类。
  • 同时你所要代理的目标类也是确定的。

2,动态代理:动态代理可以避免静态代理的缺点。动态代理中目标类即使很多,代理类对象可以很少,当修改了接口中的方法时,不会影响代理类。

静态代理

       创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时也实现该接口。在代理类中持有一个被代理对象的引用,而在代理类方法中调用该对象的方法。

接口:

//租房接口
public interface RentHouse {
    void rent();
}

被代理类

//客户租房
public class Customer implements RentHouse {
    @Override
    public void rent() {
        System.out.println("我要租房");
    }
}

代理类

//中介
public class HouseProxy implements RentHouse {

    private RentHouse rentHouse=new Customer();

    @Override
    public void rent() {
        System.out.println("带租户看房");
        rentHouse.rent();
        System.out.println("签订合同");
    }
}

代理类调用

被代理类被传递给了代理类,代理类在执行具体方法时通过所持有的被代理类完成代理。

    public static void main(String[] args) {
        HouseProxy houseProxy=new HouseProxy();
        houseProxy.rent();
    }

使用静态代理很容易就完成了对一个类的代理操作。但是静态代理的缺点也暴露出来:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。

代理类完成的功能:

  • 目标类中方法的调用
  • 功能增强

动态代理

     动态代理是指代理类对象在程序运行时由JVM根据反射机制动态生成的。动态代理不需要定义代理类的.java文件。

动态代理的实现方式:

  1. JDK动态代理
  2. CGLIB动态代理

JDK动态代理:

使用java反射包中的类和接口实现动态代理的功能。反射包中java.lang.reflect,里面有三个类:InvocationHandler,Method,Proxy。

1,InvocationHandler接口:就一个方法invoke()方法。表示代理对象要执行的功能代码。

/**方法原型:
参数:
Object proxy:jdk创建的代理对象,无需赋值
Method method:目标类中的方法,jdk提供method对象
Object[] args:目标类中方法的参数,jdk提供

**/
public Object invoke(Object proxy, Method method, Object[] args)

Invocation接口:表示代理对象要执行的功能。创建类实现接口InvocationHandler,重写invoke()方法。

2,Method类:表示方法的,确切的说就是目标类中的方法。

通过执行Method可以执行某个目标类的方法,Method.invoke()

3,Proxy类:核心对象,创建代理对象。

使用静态方法newProxyInstance()方法,创建代理对象。

/**
ClassLoader loader:类加载器,负责向内存中加载对象的。使用反射获取目标对象的ClassLoader。
Class<?>[] interfaces:接口,目标对象实现的接口,也是反射获取的。
InvocationHandler h:代理类要完成的功能
返回值就是代理对象
**/
public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

实现动态代理的步骤:

  1. 创建接口,定义目标类要完成的功能。
  2. 创建目标类实现接口。
  3. 创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能(调用目标方法;增强功能)
  4. 使用Proxy类的静态方法,创建代理对象,并把返回值转换为接口类型。

目标接口

public interface UsbSell {
    float sell(int amount);
}

目标类

public class UsbFactory implements UsbSell {
    @Override
    public float sell(int amount) {
        //目标方法
        System.out.println("目标类中,执行sell目标方法");
        return 80.0f;
    }
}

InvocationHandler对象

public class MyHandler implements InvocationHandler {
    //目标对象
    private Object target;
    //动态代理:目标对象是活动的,不是固定的,需要传入进来
    public MyHandler(Object target){
        //给目标对象赋值
        this.target=target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //执行目标类中的目标方法
        Object object = method.invoke(target, args);
        //执行增强方法
        if(object!=null){
            Float price=(Float)object;
            price=price+20;
            object=price
        }
        System.out.println("商家返回一个红包");
        return object;
    }
}

测试类

public class Solution {
    public static void main(String[] args) {
        //1,创建目标类对象
        UsbFactory usbFactory = new UsbFactory();
        //2,创建InvocationHandler对象
        MyHandler myHandler = new MyHandler(usbFactory);
        //3,创建代理对象
        UsbSell usbSell = (UsbSell) Proxy.newProxyInstance(usbFactory.getClass().getClassLoader(), usbFactory.getClass().getInterfaces(), myHandler);
        //4,通过代理执行方法
        float sell = usbSell.sell(2);
        System.out.println("通过代理执行的结果:"+sell);
    }
}

cgLib动态代理:

cglib动态代理的原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。所以使用cglib生成动态代理,要求目标类能够被继承,即不能是final的类。

 代理类继承目标类,每次嗲用代理类的方法都会被方法拦截器拦截,在拦截器中才是调用目标类中的方法。

1,导入cglib的依赖

<dependency>
   <groupId>cglib</groupId>
   <artifactId>cglib</artifactId>
   <version>2.2.2</version>
</dependency>

2,创建目标类

public class Dog {
    public final void run(String name){
        System.out.println("狗 "+name+" 跑");
    }

    public void eat(){
        System.out.println("狗 ----eat");
    }
}

3,方法拦截器

public class MyMethodInceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("这里是对方法的增强");
        //这里的方法调用不是反射
        Object object = methodProxy.invokeSuper(o, objects);
        return object;
    }
}

4,测试类

public class CGTest {
    public static void main(String[] args) {
        MyMethodInceptor myMethodInceptor = new MyMethodInceptor();
        //创建Enhance对象,类似于JDK动态代理的Proxy类
        Enhancer enhancer = new Enhancer();
        //设置目标类的字节码文件
        enhancer.setSuperclass(Dog.class);
        //设置回调函数
        enhancer.setCallback(myMethodInceptor);
        //创建代理类对象
        Dog dog =(Dog) enhancer.create();
        //调用代理类中的方法
        dog.eat();
    }
}

cglib动态代理主要调用步骤:

1)是经过一系列操作实例化Enhance对象,并设置了所需要的参数然后enhancer.create()创建代理对象。

2)调用代理对象的eat()方法,会进入到方法拦截器的intercept()方法,在这个方法中会调用proxy.invokeSuper(obj,args)方法。

3)invokeSuper中,通过FastClass机制调用目标类的方法。

 

 posted on 2020-10-28 20:57  会飞的金鱼  阅读(122)  评论(0)    收藏  举报