一、代理的基本简介
首先,在什么时候使用代理:
在面向方面编程过程中,当需要对所有类进行某种操作(如,安全性检查,记录操作日志)时,考虑到OCP原则,我们不能在所有实现类中直接添加某些相关方法,这样一旦需求改变将引起很多麻烦和大量修改性的工作。又考虑到我们所要进行的对于所有类的操作与实现类的具体实现存在正交关系(即二者完全不相关,在功能上不存在“相互”依赖关系)。因此提供代理类,对目标类(接口的真正实现类)进行代理,并在代理类中添加相关附加操作。
其次:代理模式的角色:
抽象角色 :声明真实对象和代理对象的共同接口。
代理角色 :代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口 以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作前后,附加其他的操作,相当于对真实对象进行封装 一些额外的服务。
真实角色 :代理角色所代表的真实对象,是代理最终要引用的对象。
最后:AOP中的代理:
aspect oriented programming 面向切面编程是将一个功能做成一个切面类,要用的时候,动态的置入到目标中的过程。 Spring的代理有两种,分别为动态代理和静态代理。首先看一下关于AOP的相关术语:
1,Cross Cutting Concern:是一种独立服务,它会遍布在系统的处理流程之中
2,Aspect:对横切性关注点的模块化
3,Advice:对横切性关注点的具体实现
4,Pointcut:它定义了Advice应用到哪些JoinPoint上,对Spring来说是方法调用
5,JoinPoint:Advice在应用程序上执行的点或时机,Spring只支持方法的JoinPoint,这个点也可以使属性修改,如:Aspecj可以支持
6,Weave:将Advice应用到Target Object上的过程叫织入,Spring支持的是动态织入
7,Target Object:Advice被应用的对象
8,Proxy:Spring AOP默认使用JDK的动态代理,它的代理是运行时创建,也可以使用CGLIB代理
spring实现的代理是动态代理,但在介绍动态代理之前,先了解一下静态代理。因为动态代理是为了解决静态代理的遗留问题诞生的。
二、实例解析静态代理
一个客户不想或者不能直接引用 或者说在引用目标对象前后要进行一些额外的工作 时候,代理对象可以在客户端和目标对象之间起到中介的作用。比如,给一个方法加日志,判断这个方法是否正确执行结束!
2.1,不用代理
实现类User:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.spring; public class User implements IUser { @Override public void addUser() { System.out.println("Angel: addUser()"); System.out.println("------------Angel:addUser()_End successful------------------"); } }</span>测试类:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.spring; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; import junit.framework.TestCase; public class TestUser extends TestCase { public void testAdd() { // 读取配置文件 BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml"); User user=(User)factory.getBean("user"); user.addUser(); } }</span>配置文件略
从上面的例子,可以发现的是,当我们需要记录每个方法的执行记录时,不得不为每个类的每个方法添加System.out.println("------------Angel:addUser()_End successful------------------");这样就加重了实现类的负担,这时候,我们引入一个代理类,让代理去帮助我们实现检测方法是否成功:
2.2,加入代理
加入代理类,让它跟user同时实现一个借口IUser,然后客户端通过代理,去访问user类。
IUser接口:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.spring; public interface IUser { public void addUser(); } </span>user实现类:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.spring; public class User implements IUser { @Override public void addUser() { System.out.println("Angel: addUser()"); } }</span>user代理类:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.spring; public class UserProxy implements IUser { private User user; public void setUser(User user){ this.user=user; } @Override public void addUser() { user.addUser(); this.isSuccess(); } public void isSuccess(){ System.out.println("------------Angel:addUser()_End successful------------------"); } } </span>applicationContext配置文件:
<span style="font-family:KaiTi_GB2312;font-size:18px;"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"> <bean id="user" class="com.angel.spring.User"/> <bean id="userProxy" class="com.angel.spring.UserProxy"> <property name="user" ref="user"/> </bean> </beans> </span>测试类:
<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.spring; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; import junit.framework.TestCase; public class TestUser extends TestCase { public void testAdd() { // 读取配置文件 BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml"); UserProxy userProxy=(UserProxy)factory.getBean("userProxy"); userProxy.addUser(); } } </span>
三、总结
在使用了代理类后,我们在实现检验方法是否成功时,就不用去修改我们的具体实现类,而是通过中介代理去是实现,从而也就满足了开闭原则。但是,如果有100个实现类,甚至更多呢?如果我们仍坚持采用静态代理的方法,那么,我们必将为这100个实现类,甚至更多建立代理类。显然,这也是一个麻烦,怎样解决呢?下一篇博客,将介绍AOP的代理实现方式:动态代理!