设计模式之禅学习笔记09--代理模式(动态代理)

1.动态代理

    动态代理还是属于设计模式--代理模式的一种,代理类在程序运行时创建的代理方式被成为动态代理。动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。相对来说,自己写代理类的方式就是静态代理。现在有一个非常流行的名称叫做面向横切面编程,也就是AOP(Aspect Oriented Programming),其核心就是采用了动态代理机制。

 类图:

                            

   

很简单,两条独立发展的线路。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。通知Advice从另一个切面切入,最终在高层模块也就是Client进行耦合,完成逻辑的封装任务。

 2.举个例子

     两条线,首先创建业务逻辑这条线,创建一个抽象主题类

package com.wx.dynamicproxy.base;
/*
 抽象主题
 */
public interface Subject {
    public void doSomething(String string);
}

   创建具体的主题类,实现抽象主题接口

package com.wx.dynamicproxy.imp;
import com.wx.dynamicproxy.base.Subject;
/*
真实主题
 */
public class RealSubject implements Subject {
    /*
      业务操作
     */
    @Override
    public void doSomething(String string) {
        System.out.println("真实主题的业务操作"+string);
    }
}

 第二条线,动态代理实现代理的职责。

 创建动态代理类:DynamicProxy,这个类中使用JDK提供的Proxy类来动态创建对象,这里也是动态代理和静态代理的区别,静态代理这个Proxy需要自己写。需要传入一下三个参数

  loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
  interfaces:目标对象实现的接口的类型(所以目标对象如果不实现接口就无法使用动态代理),使用泛型方式确认类型
  InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的

package com.wx.dynamicproxy.imp;

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

/*
 动态代理类
 方法作为参数传入
 */
public class DynamicProxy<T> {
    public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h){
        //执行目标,并返回结果,
        return (T)Proxy.newProxyInstance(loader,interfaces, h);
    }
}

 代理类的三个参数中,只有InvocationHandler 需要自己写,所以创建动态代理的动态代理的MyInvocationHandler类。实现接口InvocationHandler,这个类中持有一个被代理对象的实例target,并且所有通过动态代理实现的方法全部通过invoke方法调用。

package com.wx.dynamicproxy.imp;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/*
   动态代理的MyInvocationHandler类,
 */
public class MyInvocationHandler implements InvocationHandler {
    //这个类中持有一个被代理对象的实例target
    private Object target=null;
    //通过构造函数传递一个对象
    public MyInvocationHandler(Object o)
    {
        this.target=o;
    }
    //代理方法,非常简单,所有通过动态代理实现的方法全部通过invoke方法调用。
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //执行被代理的方法
        return method.invoke(target,args);
    }
}

 

 测试:代理的过程是没有问题的了

package com.wx.dynamicproxy.test;

import com.wx.dynamicproxy.base.Subject;
import com.wx.dynamicproxy.imp.DynamicProxy;
import com.wx.dynamicproxy.imp.MyInvocationHandler;
import com.wx.dynamicproxy.imp.RealSubject;
import com.wx.dynamicproxy.imp.SubjectDynamicProxy;
public class Client {
    public static void main(String[] agrs)
    {
        //定义一个主题
        Subject subject=new RealSubject();
        //定义一个Handler
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(subject);
        //定义主题的代理
        Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),subject.getClass().getInterfaces(),myInvocationHandler);
        /*Subject proxyInstance = SubjectDynamicProxy.newProxyInstance(subject);*/
        proxy.doSomething("hello");
    }
}

 

 实现了一个简单的横切面编程,我们来看通知Advice,也就是我们要切入的类。

  创建一个通知接口IAdvice

package com.wx.dynamicproxy.base;
public interface IAdvice {
    //通知只有一个方法,执行即可
    public void exec();
}

  实现这个接口:

package com.wx.dynamicproxy.imp;
import com.wx.dynamicproxy.base.IAdvice;
public class BeforeAdvice implements IAdvice {
    @Override
    public void exec() {
        System.out.println("我是前置通知,我被执行了");
    }
}

 在动态代理类中把它切进去

package com.wx.dynamicproxy.imp;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/*
 动态代理类
  loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的
  interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
  InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
 */
public class DynamicProxy<T> {
    public static <T> T newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h){
        //寻找JoinPoint连接点,AOP框架使用元数据
        if(true){
            //执行一个前置通知
            (new BeforeAdvice()).exec();
        }
        //执行目标,并返回结果,
        return (T)Proxy.newProxyInstance(loader,interfaces, h);
    }
}

 测试:

  

                          

代理模式应用得非常广泛,大到一个系统框架、企业平台,小到代码片段、事务处理,稍不留意就用到代理模式。可能该模式是大家接触最多的模式,而且有了AOP大家写代理就更加简单了,有类似Spring AOP和AspectJ这样非常优秀的工具,拿来主义可!不过,大家可以看看源代码,特别是调试时,只要看到类似$Proxy0这样的结构,你就应该知道这是一个动态代理了。
友情提醒,在学习AOP框架时,弄清楚几个名词就成:切面(Aspect)、切入点(JoinPoint)、通知(Advice)、织入(Weave)就足够了,理解了这几个名词,应用时你就可以游刃有余了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时空恋旅人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值