Spring_AOP1

Spring_AOP1<Proxy Pattern 代理模式>

 

代理模式(Proxy)

 

Spring框架的核心是IOCAOP

 

IOC(Inversion Of Control)

很好理解,就是控制反转的意思,通俗的讲就是将控制权反转,打个比方,以前你是我的老板,你指挥(控制)我,现在我奋斗成了你的老板了,该由我来指挥(控制)你了,指挥(控制)权的倒转了。比如说以前我们没有应用Spring容器或其他的IOC容器,那么我们要手动在应用程序中指定好组件的具体实现类的对象,如:

private UserDao userDao =new UserJdbcDaoImpl();//程序自己指定

不然将会出现空指针异常,这个控制权是有应用程序自己控制的,而非外部控制,那么这就造成了耦合度比较高了,且灵活性不好,扩展性也不强,那么用了IOC容器,像Spring,就将这个控制权交给了Spring容器,在应用程序中不用指定组件的具体对象,而让Spring容器指定,如:

private UserDao userDao;//程序不用自己指定,只需定义一个接口

<bean id="userJdbcDao"class="com.spring.dao.impl.UserJdbcDaoImpl"/>
<bean id="userBiz"class="com.spring.biz.impl.UserBizImpl">
    <!—Spring容器负责注入一个实现类 -->
    <property name="userDao"ref="userHibernateDao"/>
</bean>


 

Spring通过配置文件动态指定后进行装配(注入机制),有Spring来维护这些组件的生命周期,应用程序内部只需依赖抽象接口,降低了耦合性,这样就提高了灵活性和扩展性等,总之面向对象要求的扩展性,灵活性,复用性和可维护性都有改善,所以Spring单纯从降低程序之间的耦合性来讲也是很优秀的,当然Spring的强大功能远非这些,有待深入学习。关于IOC的一些运用,前面两篇文章都有入门的讲解。

 

AOP(AspectOrientedProgramming):

面向切面编程,这个可是一个好东西。比较一下OOP,通常OOP关注的是垂直的编程,即程序按照一定的流程从上往下走,多线程不过是多了几条往下走得流程,这种程序对垂直切切面的关注度很高,而对横向切面的关注度很难实现。OOP能很好的处理业务流程,却不能将系统 一些替丁的重复性的行为封装在一个模块中,比如说在很多业务中要记录日志,结果我们不得不在诸多业务流程种嵌入大量的日志记录代码,这种大量重复性的代码造成了系统难以维护等诸多不好的影响,那么AOP弥补了这一缺陷,它能够将这些重复性的代码封装在一个模块中,并转化成组件,动态加入到需要记录日志的业务流程中,好比在众多的业务流程中,横向切了一刀,在切开的口子塞入记录日志的代码,而不影响原来的业务流程,当然除了记录日志,还有比如权限设置,还有比如在操作数据库的前后开启事务和提交事务等等,用这种切面的思想,大大提高了程序的扩展性和灵活性。

 

啰嗦了一堆,其实结合生活,在大学宿舍中,很多同学在打牌,但学校又不允许打牌,定期检查,抓到的要处罚,所以爱玩牌的人不愿意被抓,又想玩,这是那帮家伙想了一个主意,雇一个小弟放哨,一旦老师来检查(多方向同时启动检查),就及时通知,那么在没有手机的时代,有好几个宿舍在不同的楼里,那么这个小弟就得一个一个楼的跑,这样显然来不及了,后来那帮家伙就每一栋楼雇一个小弟,这样就可以满足了,当然这样小弟多了,不好管理,也不好调度,而且佣金很高。那么这是手机这个东西被发明了,就一个小弟可以满足了,一旦检查开始,一条短信就可以搞定,而且需要通知的楼的数量可以任意的加了,无非就是多发几条短信。当然这要保证两方的通信要畅通的。

 

举了个不太恰当的例子,回到Spring中来,在说Spring的AOP前,先说一个设计模式中的代理模式,为什么要将这个,因为Spring的AOP就是通过代理实现的。这里的设计模式代码用Java实现的:

 

Proxy

就以刚才那个打牌为例子,这里要做一些改变,显然不是每一间宿舍都有小弟通知的,开始那帮家伙在一件没有小弟的宿舍打牌,被抓几次后,有个同学建议换一件宿舍,这件宿舍有小弟通知,就是有一个小弟定向定点服务,相当于后面的宿舍是前面宿舍的一个代理,在这个代理中,多了一个小弟的放哨通知。

 

对上面一段话首先做面向对象分析:

 

1.提取对象和分析职责:

a.<Informer>显然要有通知者,即小弟,当然通知者还可以是别的,比如说来,

这样就一定会被抓了,呵呵,所以通知者是一个抽象类或接口,提供一个通知的方法。

b.<Room>还要有一个房间提供打牌的场所,这个房间也设计成抽象类多接口,

有一个提供条件的行为,在这里为了说明代理模式,就不增加打牌的人了,

只是在这个方法中加入一段代码,就是很多大学生在打牌。

 

2.分析类之间的交互。

 这里很简单了,在代理中要加一个通知者,用了组合,在代理的方法中加入通知者通知 的方法,

被代理目标就是一间没有小弟的宿舍,当然需要代理和被代理目标同时实现

  Room接口。

 

3.开始UML建模了,简单生成了一个关系图:

 Spring_AOP1<Proxy Pattern 署理模式&gt

解释一下:虚线空心箭头表示实现接口,实现空心箭头表示继承,实现箭头表示关联关系,

很多书写的不一致这里表示ProxyDormitory中组合了Dormitory为了简化问题,

省略了name的getter方法,用构造方法设置,至于通知者对于代理来说不是必须的,

可以用一行代码代替。

 

具体代码:

IRoom接口:

public interface IRoom {
    /**
     * 提供一个场所
     */
    public void providePlace();
}


Dormitory类:

public class Dormitory implements IRoom {
    private String name;
    public Dormitory(Stringname) {
       this.name = name;
    }
    @Override
    public void providePlace() {
       //用一句话代表了
        System.out.println(this.name +"宿舍中几个大学生打牌火热进行中...");
    }
}

显然上面的家伙打牌很危险,就换弄了个代理,加了个小弟。

 

通知者抽象类:

public abstract classInformer {
 
    public abstract void inform();
}

XiaoDi类,具体通知者:

public class XiaoDiextends Informer {
    @Override
    public void inform() {
        System.out.println("大家伙注意了,老师随时会检查,但请放心,只要我在,确保你们安全...");
    }
}

代理类:

public classProxyDormitory implements IRoom {
    private Dormitorydormitory;
    private IInformerinformer;
  
    public ProxyDormitory(String name) {
       dormitory =new Dormitory(name);
       informer =new XiaoDi();
    }
 
    @Override
    public void providePlace() {
       //在代理中加入了小弟放哨通知的方法
       informer.inform();
       dormitory.providePlace();
    }
}
 

客户端调用:

public class Test {
 
    public static void main(String[]args) {
       IRoom iRoom = newProxyDormitory("319宿舍");
       //此时打牌是安全的...
       iRoom.providePlace();
    }
}

输出:

大家伙注意了,老师随时会检查,但请放心,只要我在,确保你们安全...

319宿舍宿舍中几个大学生打牌火热进行中...

 

代理模式总结:

   代理模式是对一个对象提供一种代理以控制对这个对象的访问。

    代理模式中的代理和被代理目标实现相同的接口,在代理中加入了一些额外的业务逻辑,还有一种是生成被代理目标的子类,这种不推荐,因为继承有时候带来的问题比组合要大,能用组合的就尽量不用继承。

 

代理模式在实际运用:

1. 远程代理:即为一个对象在不同的地址空间提供局部的代表,这样可以隐藏一个对象存在于不同地址空间的事实,如在Tomcate中加入一个web应用,引用一个Web应用,此生在项目中会生成一个代理的文件夹。

2. 虚拟代理:根据需要创建开销很到的对象,通过它来存放实例化需要很长时间的真是对象,如在加载网页是,我们能很快看到所有的文字,但是图片却是一张一张的下载的,那些未打开的图片框,就是通过虚拟代理来代替了真是的图片,代理存储了真实图片的路径和尺寸。

3. 安全代理:用来控制对真是对象的访问时的权限。

4. 智能指引:当调用真是对象时,代理处理了另外一些事,上面的例子。就属于这种

 

代理模式的应用很广,在Spring中就是一个典型的例子,但Spring使用的是动态代理,就更灵活了,后面继续学习。