java设计模式(五)——代理模式

1、基本概念

为其他对象提供一种代理,来控制这个对象的访问,属于结构型的模式,实现代码增强的功能。

生活场景:如婚恋介绍所,黄牛,租房

应用场景:如spring中的aop

 

2、代理类型

静态代理和动态代理

动态代理又有cglib和jdk的动态代理。

 

 

 

2.1、静态代理

案例:父亲给儿子相亲:

类图:

 

 

接口:相亲人员

public interface IblindDatePerson {

void blindDate();
}

被代理对象:儿子

public class Wangwu implements IblindDatePerson {

    @Override
    public void blindDate() {
        System.out.println("我的要求是:女的,活的");
    }

}

代理对象:父亲

public class LaoWang implements IblindDatePerson {
    private IblindDatePerson wangwu;

    public LaoWang(IblindDatePerson wangwu){
        this.wangwu = wangwu;
    }
    @Override
    public void blindDate() {
        before();
        wangwu.blindDate();
        after();

    }
    private void before() {
        System.out.println("开始替儿子王五在相亲公园寻找");
    }

    private void after() {
        System.out.println("儿子王五的相亲对象找到了");
    }
}

测试类:

public class Test {
    public static void main(String[] args) {

        IblindDatePerson iperson = new LaoWang(new Wangwu());
        iperson.blindDate();

    }
}

输出:

开始替儿子王五在相亲公园寻找
我的要求是:女的,活的
儿子王五的相亲对象找到了

从上面案例可以看到,我们代理的是同一类型的对象,即相亲对象,如果是别的人员,就无法代理,这就是静态代理。那么动态

代理,就可以代理任何的对象。

 2.2、动态代理

 动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则

1、基于JDK动态代理

被代理的类需要继承统一接口

案例:类图

 

 

 接口:

public interface IblindDatePerson {

    void  blindDate();

}

被代理类:

public class Zhangsan implements IblindDatePerson {
    @Override
    public void blindDate() {
        System.out.println("我的要求是:女的,活的");
    }
}

代理类:实现InvocationHandler 接口

public class LaoWangJdkproxy implements InvocationHandler {

    private Object target;

    public Object getProxyInstance(Object target){
        this.target = target;
        Class<?> clazz =  target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(this.target, args);
        after();
        return result;
    }

    private void before() {
        System.out.println("开始替儿子王五在相亲公园寻找");
    }

    private void after() {
        System.out.println("儿子王五的相亲对象找到了");
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        IblindDatePerson iperson  = (IblindDatePerson)new LaoWangJdkproxy().getProxyInstance(new Zhangsan());
        iperson.blindDate();
    }
}

输出:

开始替儿子王五在相亲公园寻找
我的要求是:女的,活的
儿子王五的相亲对象找到了

这里的重点就是这个代理类了,它需要实现InvocationHandler 接口

 

    private Object target;
  //对外提供一个获取代理对象的方法,target是传入被代理的类
    public Object getProxyInstance(Object target){
        this.target = target;
        Class<?> clazz =  target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
    }
生成代理类的关键方法:需要传入三个参数:target的类加载器,target的所有接口,当前对象
Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);

利用反射进行方法的调用,可以在执行目标方法前后进行增强

 @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(this.target, args);
        after();
        return result;
    }

这个是基于Jdk的动态代理。

 

2、基于cglib的动态代理

被代理的类不需要继承统一接口

它需要导入一个cglib包

 <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib-nodep</artifactId>
            <version>2.2</version>
        </dependency>

类图:

 

 代理类:实现MethodInterceptor 接口

public class LaoWangCglibProxy implements MethodInterceptor {

   public Object getProxyInstance(Class<?> clazz) throws Exception{
       Enhancer enhancer = new Enhancer();
       enhancer.setSuperclass(clazz);
       enhancer.setCallback(this);
       return  enhancer.create();
   }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        before();
        Object obj = methodProxy.invokeSuper(o,args);
        after();
        return ob;
    }

    private void before() {
        System.out.println("开始替儿子王五在相亲公园寻找");
    }

    private void after() {
        System.out.println("儿子王五的相亲对象找到了");
    }
}

以上就是两种动态代理的实现

动态代理相比静态代理的优点:

1、静态代理只能手动代理:如果我们新增一个一种情况,我们就需要新增一个代理对象,例如:

我们新增一个狗类,有个实现类二哈

public interface IDog {

    void play();
}
public class ErhaDog implements IDog {
    @Override
    public void play() {
        System.out.println("二哈在拆家。。。");
    }
}

如果静态代理就需要新增一个代理类,去处理狗相关的代理

如果是动态代理就不需要了,我们测试方法里,直接把ErhaDog对象传过去,即可生成代理对象 

结合策略模式,即可很好的进行扩展。

2、如果被代理对象新增一个方法,那么代理类就需要新增一个代理类去处理,而动态代理不需要。

3、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则

 

posted @ 2020-07-08 20:11  来一杯可乐  阅读(239)  评论(0编辑  收藏  举报