关于代理模式

Java代理模式  核心思想 :我不行就找别人 不勉强自己

Java中典型的代理模式:SpringAOP  HIbernate数据查询  

代理模式分类:静态代理和动态代理

静态代理:

聚合方式:将目标类作为代理类的成员变量 使用构造器将目标类注入  要求代理类和目标类实现相同接口

 




//公共接口
package com.briup.Proxy.Static;

public interface car {
    public void drive();
}

//目标类(被代理了)

package com.briup.Proxy.Static;

public class OrdinaryCar implements  car {
    @Override
    public void drive() {
        System.out.println("开车");
    }
}


//代理类
package com.briup.Proxy.Static;

public class ProxyCar implements car {
//引用目标对象
    private car c;

    public ProxyCar(car c) {
        this.c = c;
    }
    @Override
    public void drive() {
//目标对象的操作
          c.drive();
//对代理类额外做的操作(对目标类功能的扩展)
        System.out.println("边开车边唱歌");
    }

}



//测试类代码
public class Test {
    public static void main(String[] args) {
        car ordinaryCar = new OrdinaryCar();
        car proxyCar = new ProxyCar(ordinaryCar);
        proxyCar.drive();
    }
}

继承方式: 通过子类继承父类的方式进行功能的扩展(不建议使用)

//子类实现
package com.briup.Proxy.Static;

public class ProxyCar_2 extends OrdinaryCar {

    
    @Override
    public void drive() {
        System.out.println("开车前不喝酒");
        super.drive();
        System.out.println("边开车边喝酒");
    }

}
//测试类

package com.briup.Proxy.Static;

public class Test {
    public static void main(String[] args) {
        ProxyCar_2 proxyCar_2 = new ProxyCar_2();
        proxyCar_2.drive();
    }
}

动态代理

jdk动态代理:代理类和目标类需要实现同一接口(是SpringAOP的优先选择)使用JDK提供的类实现代理模式主要的类有Proxy InvoktionHandler


//接口:
package com.briup.Proxy.dynamic.JDK;

public interface Update {
    public void one();
    public void two();
}


//目标类

package com.briup.Proxy.dynamic.JDK;

public class UpdateImp implements  Update{
    @Override
    public void one() {
        System.out.println("one");

    }

    @Override
    public void two() {
        System.out.println("two");
    }
}

//JDK动态代理类

package com.briup.Proxy.dynamic.JDK;

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

public class ProxyJDK implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
        System.out.println("开车之前先考驾照");
        Object invoke = method.invoke(target, objects);
        System.out.println("开车之后喝点小酒");
        return invoke;
    }
}

//测试类
public class Test {
    public static void main(String[] args) {
        car ordinaryCar = new OrdinaryCar();
           car car= (com.briup.Proxy.Static.car) Proxy.newProxyInstance(Test.class.getClassLoader(),
                        new Class[]{car.class}, new ProxyJDK(ordinaryCar));
     car.drive();
        UpdateImp updateImp = new UpdateImp();
        Update up= (Update) Proxy.newProxyInstance(Test.class.getClassLoader(),
                new Class[]{Update.class},new ProxyJDK(updateImp));
        up.one();
        up.two();

    }
}

Cglib动态代理  :代理类和目标类不需要实现相同接口  

       Cglib代理是功能最为强大的一种代理方式,因为其不仅解决了静态代理需要创建多个代理类的问题,还解决了jdk代理需要被代理对象实现某个接口的问题。对于需要代理的类,如果能为其创建一个子类,并且在子类中编写相关的代理逻辑,因为“子类 instanceof 父类”,因而在进行调用时直接调用子类对象的实例,也可以达到代理的效果。Cglib代理的原理实际上是动态生成被代理类的子类字节码,由于其字节码都是按照jvm编译后的class文件的规范编写的,因而其可以被jvm正常加载并运行。这也就是Cglib代理为什么不需要为每个被代理类编写代理逻辑的原因。这里需要注意的是,根据Cglib实现原理,由于其是通过创建子类字节码的形式来实现代理的,如果被代理类的方法被声明final类型,那么Cglib代理是无法正常工作的,因为final类型方法不能被重写

 

依赖导入:

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


代码实现:




//目标类沿用JDK代理的例子

//Cglib代理类
package com.briup.Proxy.dynamic.Cglib;


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

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理之前");
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("代理之后");
        return o1;
    }
}

//测试类
package com.briup.Proxy.dynamic.Cglib;

import com.briup.Proxy.dynamic.JDK.UpdateImp;
import net.sf.cglib.proxy.Enhancer;

public class Test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UpdateImp.class);
        enhancer.setCallback(new CglibProxy());
        UpdateImp up= (UpdateImp) enhancer.create();
        up.one();

    }
}

代理模式的优缺点:

优点:

  • 可以在保证开闭原则的前提下 对目标进行功能扩展 
  • 协调了调用者和被调用者 降低了耦合性
  • 在客户端和目标对象间添加代理对象  起到了保护目标对象的作用

缺点:

  • 在调用目标对象方法前 先调用代理类的方法   提高了代码非复杂性  增加程序运行时间
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值