JAVA设计模式之代理模式

代理模式

1、通过代理对象访问目标对象,可在目标对象实现的基础上,增加额外的功能操作

2、被代理的对象是远程对象创建开销大或需要安全控制的对象

3、三种不同形式

  • 静态代理
  • 动态代理(JDK代理、接口代理)
  • Cglib代理(内存动态创建对象,无需实现接口)

静态代理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lxE5Wc4S-1606654950317)(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\image-20201129173032811.png)]

接口

public interface ITeacherDao {
    public void study();
}

目标对象(被代理对象)

public class TeacherDao implements ITeacherDao {
    @Override
    public void Teach() {
        System.out.println("我开始学习了!");
    }
}

代理类(Proxy)

public class TeacherDaoProxy implements ITeacherDao {
    TeacherDao target;
    public TeacherDaoProxy(TeacherDao target) {
        this.target = target;
    }
    @Override
    public void Teach() {
        System.out.println("吃鸡蛋!");
        target.Teach();
        System.out.println("吃米饭");
    }
}

实现

public class Client {
    public static void main(String[] args) {
        ITeacherDao proxy = new TeacherDaoProxy(new TeacherDao());
        proxy.study();
    }
}

结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TFkMgBir-1606654950323)(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\image-20201129205129717.png)]

缺点

1、目标对象与代理对象必须同时实现相同接口

2、每次接口方法更新,代理对象和目标对象都要更新

3、代理对象需要传入指定目标对象

动态代理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GFLC2lMS-1606654950327)(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\image-20201129174911948.png)]

特点:

1、目标对象(被代理类)需要实现接口方法,代理对象无需实现接口

2、代理对象使用Object类型来接收传入的对象

3、代理对象使用java.lang.reflect包下的Proxy类的newProxyInstance()方法来返回目标对象的代理对象

4、无需在代理对象中创建目标对象,而是动态的在内存中创建目标对象的代理对象

newProxyInstance()参数说明:

 public static studyDao newProxyInstance(ClassLoader loader,  
                                         Class<?>[] interfaces,
                                         InvocationHandler h)
  • ClassLoader loader:目标对象的类加载器

  • Class<?>[] interface:目标对象实现的所有接口方法,用泛型来接收

  • InvocationHandler h:事件处理,当目标对象执行时会触发事件处理器,会将目标对象以参数形式传入处理

    •  new InvocationHandler() {
                  @Override			
                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {               
                      Object invoke = method.invoke(target, args);
                      return invoke;
             	    }
      
      • proxy:返回的代理对象
      • method:当前目标对象使用的方法
      • args:当前目标对象使用的方法参数

接口

public interface ITeacherDao 
{ 
    public void study();
}

目标对象

public class TeacherDao implements ITeacherDao {
    @Override
    public void Teach() {
        System.out.println("我开始学习了!");
    }
}

代理对象

public class ProxyFactory {
    
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        /**
         *    public static studyDao newProxyInstance(ClassLoader loader, 
         *                                           Class<?>[] interfaces,
         *                                           InvocationHandler h)
         */
        return 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 invoke = method.invoke(target, args);
                System.out.println("动态代理结束了");
                return invoke;
            }
        });
    }
}

实现

public class Client {
    public static void main(String[] args) {
        ITeacherDao teacherdao = new TeacherDao();
        ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(teacherdao).getProxyInstance();
        proxyInstance.study("小明");
    }
}

结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wDx3nFbr-1606654950331)(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\image-20201129204946904.png)]

CGLIB代理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Jyict5U-1606654950336)(C:\Users\acer\AppData\Roaming\Typora\typora-user-images\image-20201129185041046.png)]

特点:

1、目标对象与代理对象无需再实现任何接口

2、在内存中构建一个子类来实现对目标对象的代理

3、代理对象需要实现MethodInterceptor重写intercept()方法

依赖

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

目标对象

public class TeacherDao {
    public void Teach(String name) {
        System.out.println(name+"开始学习...");
    }
}

代理对象

public class ProxyFactory implements MethodInterceptor {
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        //创建一个工具类
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建子类对象、即代理对象
        return enhancer.create();
    }
							//返回的代理对象    当前方法      方法参数
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("CGLIB动态代理开始");
        Object resultValue = method.invoke(target, args);
        System.out.println("CGLIB动态代理结束");
        return resultValue;
    }
}

说明

1、getProxyInstance():给目标对象tagert创建一个代理对象

2、重写intercept()方法来实现目标对象方法的调用

动态代理再说明

Spring AOP 底层使用了动态代理
AOP编程如何选择代理模式:
目标对象需要实现接口:JDK代理
目标对象不需要实现接口:CDLIB代理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值