博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

java设计模式之代理模式

java代理模式是一种常见的设计模式。

一、概念:为其他对象提供一种代理以控制对这个对象的访问。代理对象起到中介作用,可去掉功能服务或增加额外的服务。

二、常见的代理模式有哪些?

  1. 远程代理:为不同地理的对象,提供局域网代表对象。
  2. 虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建。
  3. 保护代理:控制对一个对象访问的权限。
  4. 智能引用代理:提供对目标对象额外的服务。

三、代理模式的两种实现方式

  1. 静态代理:代理和被代理对象在代理之前是确定的,他们都实现相同的接口或者继承相同的抽象类。
  2. 动态代理

四、示例

1.通过继承实现静态代理

首先,先写一个接口

public interface Moveable {
    
    void move();
    
}

然后写接口的实现类

public class Car implements Moveable {

    @Override
    public void move() {    
        //实现开车
        try {
            Thread.sleep(new Random().nextInt(1000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

接着是继承类,在继承类中,我们实现了父类中的方法,并增加了一些额外的功能,从而实现静态代理

public class Car2 extends Car{
    
    @Override
    public void move(){
        long starttime = System.currentTimeMillis();
        System.out.println("汽车开始行驶.......");
     //调用父类中的方法,实现该方法
super.move(); long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶......"); System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!"); } }

测试方法

public class Test{
    public static void main(String[] args) {
        //使用继承方式实现
        Moveable m = new Car2();
        m.move();
    }
}

2.通过聚合实现静态代理

编写聚合类(通过将参数传递进来,然后我们使用传递进来的参数,调用其方法,实现静态代理)

public class Car3 implements Moveable{

    private Car car;    
    public Car3(Car car) {
        super();
        this.car = car;
    }

    @Override
    public void move() {
        long starttime = System.currentTimeMillis();
        System.out.println("汽车开始行驶.......");
     //通过构造方法将car传进来,然后通过car调用方法 car.move();
long endtime = System.currentTimeMillis(); System.out.println("汽车结束行驶......"); System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!"); } }

测试方法

public class Test {
    public static void main(String[] args) {
        //使用聚合方式实现
        Car car = new Car();
        Moveable m = new Car3(car);
        m.move();
        }
}    

使用继承实现静态代理,会让我们的代理类无限制的膨胀下去,所以推荐使用聚合实现静态代理。

五、JDK动态代理

1.定义

在代理类和被代理类之间加上一个事务处理器,将我们需要处理的具体功能放在其中进行处理。

InvocationHandler接口(事务处理器)中仅定义了一个方法public object invoke(Object obj,Method method,Object[] args),在实际使用中,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组,这个抽象方法在代理类中动态实现。

Proxy:该类即为动态代理类,通过newProxyInstance方法可以返回代理类的一个实例,返回后的代理类可以当做被代理类使用(可使用被代理类的在接口中声明过的方法)。

2.实现步骤

  1. 创建一个实现接口InvocationHandler的类,它必须实现invoke方法,在invoke方法中添加具体的业务逻辑。
  2. 创建被代理的类和接口。
  3. 调用Proxy的静态方法newProxyInstance,动态创建一个代理类。
  4. 通过代理调用方法。

3.示例

public class TimeHandler implements InvocationHandler{    
    private Object target;
    public TimeHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        long starttime = System.currentTimeMillis();
        System.out.println("汽车开始行驶.......");
        method.invoke(target);
        long endtime = System.currentTimeMillis();
        System.out.println("汽车结束行驶......");
        System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!");        
        return null;
    }
}
public class TestProxy {
    public static void main(String[] args) {
        Car car  = new Car();
        InvocationHandler h = new TimeHandler(car);
        Class<?> cls = car.getClass();
        /**
         * loader 类加载器
         * interfaces 实现接口
         * h InvocationHandler 
         * */
        Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),
                cls.getInterfaces(), h);
        m.move();
    }
}

六、CGLIB动态代理

 示例:

首先需引入cglib的jar包

对应的实体类

public class Train {
    public void move(){
        System.out.println("火车行驶中.........");
    }
}
public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    //创建代理类
    public Object getProxy(Class clazz){
        //设置创建子类的类,为每个类产生代理类
        enhancer.setSuperclass(clazz);
        //设置回调
        enhancer.setCallback(this);
        //创建子类的实例并返回
        return enhancer.create();
    }
    /**
     * 拦截所有目标类方法的调用
     * obj 目标类的实例
     * m 目标方法的反射对象
     * args 方法的参数
     * proxy 代理类的实例
     * */
    @Override
    public Object intercept(Object obj, Method m, Object[] args,
            MethodProxy proxy) throws Throwable {
        System.out.println("日志开始......");
        //代理类调用父类的方法
        proxy.invokeSuper(obj, args);
        System.out.println("日志结束......");
        return null;
    }
}
public class Test {
    public static void main(String[] args) {
        //创建返回代理类对象
        CglibProxy proxy = new CglibProxy();
        //为trian返回代理类对象
        Train t = (Train) proxy.getProxy(Train.class);
        //调用方法
        t.move();
    }
}

JDK动态代理和CGLIB动态代理的区别

JDK动态代理:

  1. 只能代理实现了接口的类。
  2. 没有实现接口的类不能实现JDK的动态代理。

CGLIB动态代理:

  1. 针对类来实现代理。
  2. 对指定目标类产生一个子类,通过方法拦截技术拦截所有父类方法的调用。

动态代理的典型应用:spring AOP:同时用到了JDK动态代理和CGLIB动态代理。

posted @ 2018-09-03 15:46  疯狂打码  阅读(3660)  评论(0编辑  收藏  举报