代理设计模式Proxy

代理设计模式Proxy

存在意义

  • 代理模式的一个好处就是对外部提供统一的接口方法,而代理类在接口中实现对真实类的附加操作行为,从而可以在不影响外部调用情况下,进行系统扩展。也就是说,我要修改真实角色的操作的时候,尽量不要修改他,而是在外部在“包”一层进行附加行为,即代理类.

  • 代理模式(Proxy)也可以被用来区别一个对象实例的请求和实际的访问

静态代理

  • 说明: 静态代理需要自己生成代理类
/**
 * 买房接口
 * 
 * @title
 * @description
 * @since JDK1.8
 */
public interface House {

    public void maiFang();
}
/**
 * 小明买房
 * 
 * @title
 * @description
 * @since JDK1.8
 */
public class Xiaoming implements House {

    /*
     * (非 Javadoc)
     * 
     * @see com.example.demo.proxy.House#maiFang()
     */
    @Override
    public void maiFang() {
        System.out.println("我是小明,我要买房了!!!!");

    }

}
/**
 * 静态代理需要自己生成代理类
 * 
 * @title
 * @description
 * @since JDK1.8
 */
public class StaticProxy implements House {

    private Xiaoming xiaoming;

    public StaticProxy(Xiaoming xiaoming) {
        this.xiaoming = xiaoming;
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.example.demo.proxy.House#maiFang()
     */
    @Override
    public void maiFang() {
        System.out.println("我是中介,我要开始监听了!!!!");
        xiaoming.maiFang();
        System.out.println("我是中介,我要结束监听了!!!!");

    }

    public static void main(String[] args) {
        StaticProxy staticProxy = new StaticProxy(new Xiaoming());
        staticProxy.maiFang();
    }

}

jdk自带动态代理

  • 说明: 实现InvocationHandler接口即可,代理类通过反射机制生成
/**
 * jdk自带动态代理类:代理类通过反射机制生成
 * 
 * @title
 * @description
 * @since JDK1.8
 */
public class Jdkproxy implements InvocationHandler {
    /**
     * 这个就是我们要代理的真实对象
     */
    private Object target;

    /**
     * 构造方法,给我们要代理的真实对象赋初值
     *
     * @param subject
     */
    public Jdkproxy(Object target) {
        this.target = target;
    }

    /**
     * 该方法负责集中处理动态代理类上的所有方法调用。 调用处理器根据这三个参数进行预处理或分派到委托类实例上反射执行
     *
     * @param proxy 代理类实例
     * @param method 被调用的方法对象
     * @param args 调用参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在代理真实对象前我们可以添加一些自己的操作
        System.out.println("我是房产中介,我jdk动态代理开始监听了!!!!!!!!!!");
        // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        Object in = method.invoke(target, args);
        // 在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("我是房产中介,我jdk动态代理结束监听了!!!!!!!!!!");
        return in;
    }

    public static void main(String[] args) {
        Xiaoming xm = new Xiaoming();
        Jdkproxy pro = new Jdkproxy(xm);
        /**
         * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
         */
        House house = (House) Proxy.newProxyInstance(xm.getClass().getClassLoader(), xm.getClass().getInterfaces(), pro);
        house.maiFang();
    }

}
  • 补充:通过分析代码可以看出Java 动态代理,具体有如下四步骤:
通过实现 InvocationHandler 接口创建自己的调用处理器;
通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;
通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

jdk动态代理扩展

参数说明: 
Object proxy:指被代理的对象。 
Method method:要调用的方法 
Object[] args:方法调用时所需要的参数 

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubjectProxy类: 
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法: 
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, 
InvocationHandler h) 
                               throws IllegalArgumentException 
参数说明: 
ClassLoader loader:类加载器 
Class<?>[] interfaces:得到全部的接口 
InvocationHandler h:得到InvocationHandler接口的子类实例 

Ps:类加载器 
在Proxy类中的newProxyInstance()方法中需要一个ClassLoader类的实例,ClassLoader实际上对应的是类加载器,在Java中主要有一下三种类加载器; 
Booststrap ClassLoader:此加载器采用C++编写,一般开发中是看不到的; 
Extendsion ClassLoader:用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类; 
AppClassLoader:(默认)加载classpath指定的类,是最常使用的是一种加载器。 

动态代理 
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 

Cglib动态代理

  • 说明: JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
/**
 * cglib动态代理:spring aop 用的就是这个方式
 * 
 * @title
 * @description
 * @since JDK1.8
 */
public class CglibProxy implements MethodInterceptor {

    /*
     * 回调方法 (非 Javadoc)
     * 
     * @see org.springframework.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[],
     * org.springframework.cglib.proxy.MethodProxy)
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] arg2, MethodProxy proxy) throws Throwable {
        System.out.println("我是房产中介,我使用的是cglib动态代理监听开始!!!!!!!!!!!");
        Object invoke = proxy.invokeSuper(obj, arg2);
        System.out.println("我是房产中介,我使用的是cglib动态代理监听结束!!!!!!!!!!!");
        return invoke;
    }

    public static void main(String[] args) {
        CglibProxy pro = new CglibProxy();
        Enhancer enhancer = new Enhancer();
        // 创建子类
        enhancer.setSuperclass(Xiaoming.class);
        // 回调方法
        enhancer.setCallback(pro);
        // 创建代理对象
        House house = (House) enhancer.create();
        house.maiFang();
    }

}

jdk动态代理和cglib动态代理区别:

  • dk动态代理是由Java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的.总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题).还有一点必须注意:jdk动态代理的应用前提,必须是目标基于统一的接口.如果没有上述前提,jdk动态代理不能应用.

注意:asm其实就是java字节码控制.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章