从代理设计模式到Spring AOP

例子场景:打架
如:
桃花岛比武抢亲之战 —— 郭靖与欧阳克
华山论剑正邪之战 —— 北丐洪七公和西毒欧阳峰
小朋友梦想之战 —— 奥特曼与铠甲勇士

这些战斗之中,都要打架,但是打架之前需要有一些前期准备,打架(实战)工作由目标对象实现,而前期的准备(练功)工作则由代理对象实现。

静态代理实现方式一

真实打架行为接口:

public interface IRealFight{
    void fight();
}

抢亲之战:

public class QiangQinFightImpl implements IRealFight{

    @Override
    public void fight(){
        System.out.println("郭靖和欧阳克战斗!");
    }
}

正邪之战:

public class GoodEvilFightImpl implements IRealFight{

    @Override
    public void fight(){
        System.out.println("北丐洪七公和西毒欧阳锋战斗!");
    }
}

梦想之战

public class DreamFightImpl implements IRealFight{

    @Override
    public void fight(){
        System.out.println("奥特曼和铠甲勇士战斗!");
    }
}

真实战斗代理类
以上的战斗都需要提前练功,练功的准备由代理类实现

public class ProxyVirtualFight implements IRealFight{

    //需要给我一个目标对象
    private IRealFight targetFigth;

    //给了我一个目标对象
    public ProxyVirtualFight(IRealFight targetFight){
        this.targetFight = targetFight;
    }

    /**
    * 我来负责全程打架,包括前期练功和实际战斗
    */
    @Override
    public void fight(){
        //前期练功
        System.out.println("战斗双方正在练功,请不要打扰我们!!!");
        //实际战斗开始
        targetFigth.fight();
        //战斗结束
        System.out.println("这场战斗结束了.");
    }
}

观众需求:
观众想要看他们自己想要的任意一场战斗

public class Client{

    public static void main(String[] args){
        //=====广场大妈,我们想要看【抢亲之战】=====
        //1.战斗对象准备好了
        QiangQinFightImpl qiangQin = new QiangQinFightImpl();
        //2.代理对象也准备好了
        ProxyVirtualFight proxy1 = new ProxyVirtualFight(qiangQin);
        //3.开始战斗
        proxy1.fight();

        //=====二B青年,我们想要看【正邪之战】=====
        //1.战斗对象准备好了
        GoodEvilFightImpl goodEvil = new GoodEvilFightImpl();
        //2.代理对象也准备好了
        ProxyVirtualFight proxy2 = new ProxyVirtualFight(goodEvil);
        //3.开始战斗
        proxy2.fight();     

        //=====祖国花朵,我们想要看【梦想之战】=====
        //1.战斗对象准备好了
        DreamFightImpl dream = new DreamFightImpl();
        //2.代理对象也准备好了
        ProxyVirtualFight proxy3 = new ProxyVirtualFight(dream);
        //3.开始战斗
        proxy3.fight(); 
    }
}

静态代理实现方式二

结合简单工厂模式
有观众骂起来了,要自己去创建各种战斗对象,好烦啊。

建个工厂类,给你们(观众)创建战斗对象

public class FightFactory{
    //亲爱观众,你们自己实现吧,简单工厂、工厂方法、抽象工厂,自己用去。。
    //算了,还是帮你们创建吧(简单工厂)
    public static IRealFight createFight(String fightName){
        if("QiangQin".equals(fightName)){
            return new QiangQinFightImpl();
        }else if("GoodEvil".equals(fightName)){
            return new GoodEvilFightImpl();
        }else if("Dream".equals(fightName)){
            return new DreamFightImpl();
        }
    }
}

现在的观众:

public class Client{

    public static void main(String[] args){
        //=====广场大妈,我们想要看【抢亲之战】=====
        //1.战斗对象准备好了
        IRealFight qiangQin = FightFactory.createFight("QiangQin");
        //2.代理对象也准备好了
        ProxyVirtualFight proxy1 = new ProxyVirtualFight(qiangQin);
        //3.开始战斗
        proxy1.fight();

        //=====二B青年,我们想要看【正邪之战】=====
        //1.战斗对象准备好了
        IRealFight goodEvil = FightFactory.createFight("GoodEvil");
        //2.代理对象也准备好了
        ProxyVirtualFight proxy2 = new ProxyVirtualFight(goodEvil);
        //3.开始战斗
        proxy2.fight();     

        //=====祖国花朵,我们想要看【梦想之战】=====
        //1.战斗对象准备好了
        IRealFight dream = FightFactory.createFight("Dream");
        //2.代理对象也准备好了
        ProxyVirtualFight proxy3 = new ProxyVirtualFight(dream);
        //3.开始战斗
        proxy3.fight();             
    }
}

静态代理实现方式三

结合工厂方法模式
有观众第二次开始骂起来了,我们哪里记得那么多的名称啊,好烦啊。

建另外一种工厂类,给你们(观众)创建战斗对象

public class FightFactory{

    //工厂方法
    public static IRealFight createQiangQin(){
        return new QiangQinFightImpl();
    }

    public static IRealFight createGoodEvil(){
        return new GoodEvilFightImpl();
    }

    public static IRealFight createDream(){
        return new DreamFightImpl();
    }
}

现在的观众:

public class Client{

    public static void main(String[] args){
        //=====广场大妈,我们想要看【抢亲之战】=====
        //1.战斗对象准备好了
        QiangQinFightImpl qiangQin = FightFactory.createQiangQin();
        //2.代理对象也准备好了
        ProxyVirtualFight proxy1 = new ProxyVirtualFight(qiangQin);
        //3.开始战斗
        proxy1.fight();

        //=====二B青年,我们想要看【正邪之战】=====
        //1.战斗对象准备好了
        GoodEvilFightImpl goodEvil = FightFactory.createGoodEvil();
        //2.代理对象也准备好了
        ProxyVirtualFight proxy2 = new ProxyVirtualFight(goodEvil);
        //3.开始战斗
        proxy2.fight();     

        //=====祖国花朵,我们想要看【梦想之战】=====
        //1.战斗对象准备好了
        DreamFightImpl dream = FightFactory.createDream();
        //2.代理对象也准备好了
        ProxyVirtualFight proxy3 = new ProxyVirtualFight(dream);
        //3.开始战斗
        proxy3.fight();             
    }
}

静态代理实现方式四

结合抽象工厂模式
有观众第三次又开始骂起来了,这实现跟之前的差不了多少,神经病啊。

建另外一种工厂类

public class FightFactory{

    //工厂方法
    public static IRealFight createQiangQin(){
        return new QiangQinFightImpl();
    }

    public static IRealFight createGoodEvil(){
        return new GoodEvilFightImpl();
    }

    public static IRealFight createDream(){
        return new DreamFightImpl();
    }
}

现在的观众:

public class Client{

    public static void main(String[] args){
        //=====广场大妈,我们想要看【抢亲之战】=====
        //1.战斗对象准备好了
        QiangQinFightImpl qiangQin = FightFactory.createQiangQin();
        //2.代理对象也准备好了
        ProxyVirtualFight proxy1 = new ProxyVirtualFight(qiangQin);
        //3.开始战斗
        proxy1.fight();

        //=====二B青年,我们想要看【正邪之战】=====
        //1.战斗对象准备好了
        GoodEvilFightImpl goodEvil = FightFactory.createGoodEvil();
        //2.代理对象也准备好了
        ProxyVirtualFight proxy2 = new ProxyVirtualFight(goodEvil);
        //3.开始战斗
        proxy2.fight();     

        //=====祖国花朵,我们想要看【梦想之战】=====
        //1.战斗对象准备好了
        DreamFightImpl dream = FightFactory.createDream();
        //2.代理对象也准备好了
        ProxyVirtualFight proxy3 = new ProxyVirtualFight(dream);
        //3.开始战斗
        proxy3.fight();             
    }
}

//客户是上帝,但是观众不是可不是上帝。。。离主题有点远了。。。回归代理了。

哇哈哈哈,打架不仅是真实的打架,还有虚拟的打架哦。虚拟打架也要有相同的练功前期工作哦
如:
拳皇
魂斗罗

虚拟打架接口

public interface IVirtualFight{
    void fight();
}

拳皇

public class QuanHuangFight implements IVirtualFight{

    @Override
    public void fight(){
        System.out.println("拳皇二阶堂红丸打草薙京");
    }
}

魂斗罗

public class HunDouLuoFight implements IVirtualFight{

    @Override
    public void fight(){
        System.out.println("魂斗罗打啊打啊打啊。。");
    }
}

这虚拟打架前也需要练功吗???虽然不练功,但是也有前奏,额外的工作由代理对象来完成。根据前面的方法,也需要有相应代理类

虚拟打架代理类

public class ProxyVirtualFight implements IVirtualFight{

    //给我一个虚拟打架对象
    private IVirtualFight virtualFight;

    //给了一个虚拟对象
    public ProxyVirtualFight(IVirtualFight virtualFight){
        this.virtualFight = virtualFight;
    }

    @Override
    public void fight(){
        前期练功
        System.out.println("战斗双方正在练功,请不要打扰我们!!!");
        //战斗
        virtualFight.fight();
        //虚拟战斗结束
        System.out.println("这场战斗结束了.");
    }
}

问题来了没啊。。默默的又多了一个代理类,而且这个代理类的代理业务逻辑和之前的代理类是一样的。好啰嗦啊。。。

我想要的是只要一个代理类来完成真实打架和虚拟打架中前期练功的工作就好!!!!!!

传说中的动态代理可以帮你完成的哦。瞧瞧以下的办法

动态代理

jdk实现动态代理

用jdk实现动态代理,需要继承一个接口InvocationHandler

代理处理类

public class ProxyFight implements InvocationHandler{

    //给我一个目标对象(是真实打架或者虚拟打架对象)
    private Object target;

    //给了你一个目标对象了
    public ProxyFight(Object target){
        this.target = target;
    }

    //绑定委托对象并返回一个代理类
    public Object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass.getClassLoader(),target.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable{
        前期练功
        System.out.println("战斗双方正在练功,请不要打扰我们!!!");
        //战斗
        method.invoke(target,args);
        //虚拟战斗结束
        System.out.println("这场战斗结束了.");
    }

}

观众要来了,战斗越来越多,现在有真实战斗如:抢亲之战、正邪之战、梦想之战;还有虚拟战斗游戏如:魂斗罗、拳皇。。。哈哈哈,有意思。

public class Client{

    public static void main(String[] args){
        //广场大妈想看【抢亲之战】
        ProxyFight proxy = new ProxyFight();

        IRealFight real = (IRealFight)proxy.bind(new QiangQinFightImpl());

        real.fight();

    }
}

看看jdk动态代理实现过程有点傻眼,一脸懵逼样子,不知道啥跟啥个啥。。。

Dynamic Proxy机制:可以为指定的接口在系统运行期间动态的生成代理对象。
需要一个接口和一个类,java.lang.reflect.Proxy类和java.lang.reflection.InvocationHandler接口。动态代理虽好,但是不能满足所有的需求。因为动态代理机制只能实现了相应接口的类使用。

Proxy.newProxyInstance(target.getClass.getClassLoader(),target.getClass().getInterfaces(),this)
这个实例化了一个代理类,好屌的样子,这里面的第二个参数,目标类实现的接口类,即我的目标类必须要继承xxx接口,不然就没法创建对象了哦。

如果目标类没有实现一个接口,那怎么办了?

那就看看不知道哪位大师搞出来的CGLIB动态代理了吧。

CGLIB实现动态代理

CGLIB是开源的动态字节码生成类库,为目标对象生成动态的代理对象实例。

大师对它的原理是这么说的:
对目标对象进行继承扩展,为其生成相应的子类,而子类可以通过覆写来扩展父类的行为,只要将横切逻辑的实现放到子类中,然后然系统使用扩展后的目标对象的子类,就可以达到与代理模式相同的效果了。
SubClass instanceof SuperClass == true.

需要的材料

net.sf.cglib.proxy.Callback

net.sf.cglib.proxy.MethodInterceptor(继承了Callback)

从新准备一下代码喽

抢亲之战

public class QiangQinFightImpl{
    public void fight(){
        System.out.println("郭靖和欧阳克战斗!");
    }
}

正邪之战

public class GoodEvilFightImpl{
    public void fight(){
        System.out.println("北丐洪七公和西毒欧阳锋战斗!");
    }
}

这两种战斗,前期都要练功,都有相同的准备工作,交给代理对象来做,代理对象在哪?代理对象怎么完成?

public class FightCallback implements MethodInterceptor{
    public Object intercept(Object object,Method method,Object[] args,MethodProxy proxy) throws Throwable{
        //前期练功
        System.out.println("战斗双方正在练功,请不要打扰我们!!!");
        return proxy.invokeSuper(object,args);
    }
}

观众又来了,打架在哪里啊

public class Client{
    public static void main(String[] args){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(QiangQinFightImpl.class);
        enhancer.setCallback(new RequestCtrlCallback());
        QiangQinFightImpl fight = (QiangQinFightImpl)enhancer.create();
        fight.fight();
    }
}

看到这,好像更傻了。。。嘿嘿嘿。

你可能感兴趣的:(JAVA,代理模式,aop,jdk,cglib)