java23种设计模式-结构型模式-代理模式

一、定义

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

 代理模式分为静态代理、动态代理。动态代理又分为JDK动态代理和CGLIB动态代理。

二、优点及缺点

静态代理优点:

1、客户端不必知道实现类(委托类)的内部方法实现,只需要调用代理类即可。

缺点:

1、代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。但这样出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也要实现这个方法。这显然增加了代码的复杂度。

2、代理对象只服务于一种类型的对象,如果要服务多类型的对象,那就要对每种对象都进行代理,程序过于繁琐。

 

动态代理优点:

1、减少编程的工作量:无需为每个方法都写一个代理方法,无需为每一个类都书写一个代理类。

2、系统扩展性和维护性增强,修改方便,直接修改代理类。

 

三、代码实现:

1、静态代理

接口类:

package com.example.demo.sjms.jingtaidailimoshi;
/**
 *  @Author: caesar
 *  @Date:2020年10月15日 18:10:25
 *  @Description: 买车接口
 */
public interface ByCar {
public void payForTheCar(int money);
}

 

实现类:

package com.example.demo.sjms.jingtaidailimoshi;

import lombok.Data;

/**
 *  @Author: caesar
 *  @Date:2020年10月15日 18:10:57
 *  @Description: 买车的实现类
 */
@Data
public class Customer implements ByCar{
    private int money;
    @Override
    public void payForTheCar(int money) {
        System.out.println("使用"+money+"元,买了一辆车");
    }
}

 

代理类:

package com.example.demo.sjms.jingtaidailimoshi;

/**
 *  @Author: caesar
 *  @Date:2020年10月15日 19:10:23
 *  @Description: 代理类,需要在调用买车方法之前,首先判断这个人的钱是否够用
 */
public class CarProxy implements ByCar {
    // 最少钱数
    private final int MIN_MONEY = 100000;
    // 引入委托对象
    private Customer customer;
    public CarProxy(Customer customer){
        this.customer = customer;
    }
    // 代理方法
    @Override
    public void payForTheCar(int money) {
        if(customer.getMoney() < MIN_MONEY){
            System.out.println("钱数不够无法购买,还缺"+ (MIN_MONEY - money)+"元");
            return;
        }
        customer.payForTheCar(money);
    }

}

 

测试类:

package com.example.demo.sjms.jingtaidailimoshi;

/**
 *  @Author: caesar
 *  @Date:2020年10月15日 19:10:33
 *  @Description: 测试类
 */
public class Test {
    public static void main(String[] args) {
        CarProxy carProxy = new CarProxy(new Customer());
        carProxy.payForTheCar(1000);
    }
}

 

2、动态代理

(1)、JDK动态代理(基于实现相同的接口)

JDK动态代理是基于反射机制。通过java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象。最主要的特点就是,代理类必须和被代理类实现相同的接口,也就是说被代理类一定要有实现的接口,否则不可以使用JDK动态代理。

 

实体类和接口类不再多写和上面相同

动态代理类:

package com.example.demo.sjms.JDKdongtaidaili;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *  @Author: caesar
 *  @Date:2020年10月15日 19:10:15
 *  @Description: JDK动态代理
 */
public class JDKProxy<T>{
    private T target;
    public JDKProxy(T target){
        this.target = target;
    }
    /***
     *  @Author: caesar
     *  @Date:2020年10月15日 19:10:26
     *  @Description: 动态代理方法
     *  @Param:
     *  @Return:
     */
    public T getProxy(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("方法执行之前执行。。。。。。");
                Object object = method.invoke(target,args);
                System.out.println("方法执行之后执行。。。。。。");
                return object;
            }
        });
    }
}

测试类:

package com.example.demo.sjms.JDKdongtaidaili;


/**
 *  @Author: caesar
 *  @Date:2020年10月15日 19:10:37
 *  @Description: 测试类
 */
public class Test {
    public static void main(String[] args) {
        Person user = new User();
        JDKProxy<Person> jdkProxy = new JDKProxy<Person>(user);
        Person proxyUser = jdkProxy.getProxy();
        proxyUser.say();
    }
}

 

(2)、CGLIB动态代理类(继承)

利用ASM框架,对代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理。cglib代理的类,无需强制实现接口,其生成的代理类 是 被代理类的子类,并且重写的被代理类的方法,只需引包即可。

引入的jar包:

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

 

委派类也不再多写,和上面的相同

CGLIB代理类:

package com.example.demo.sjms.CGLIBdongtaidaili;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *  @Author: caesar
 *  @Date:2020年10月15日 19:10:15
 *  @Description: CGLIB动态代理
 */
public class CGLIBProxy<T>{
   public T getCGLIBProxy(Class<T> tClass){
       return (T) Enhancer.create(tClass, new MethodInterceptor() {
           @Override
           public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
               System.out.println("方法前执行。。。。。。");
               Object result = methodProxy.invokeSuper(o, objects);
               System.out.println("方法后执行。。。。。。");
               return result;
           }
       });
   }
}

 

测试类:

package com.example.demo.sjms.CGLIBdongtaidaili;


/**
 *  @Author: caesar
 *  @Date:2020年10月15日 19:10:37
 *  @Description: 测试类
 */
public class Test {
    public static void main(String[] args) {
        CGLIBProxy<User> cglibProxy = new CGLIBProxy<User>();
        User proxyUser = cglibProxy.getCGLIBProxy(User.class);
        proxyUser.say();
    }
}

 

四、源码级别

springAOP就是动态代理:这是本人的有关博客位置:https://www.cnblogs.com/mcjhcnblogs/category/1791152.html

五、总结

注释:原来博客中书写过有关代理模式的详解地址如下:可能代码不如这个整洁,但是总结的很详细:https://www.cnblogs.com/mcjhcnblogs/p/13174171.html

 

posted @ 2020-10-16 09:34  码在江湖  阅读(94)  评论(0编辑  收藏  举报