Spring之代理设计模式原理与代码展示

来源:互联网 发布:企业专利数据库 编辑:程序博客网 时间:2024/05/24 05:53
1.代理设计模式
1.代理设计模式
  代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
  - GoF95  一共定义了23种设计模式.代理设计模式是非常重要模式之一.
  - 作用:
   - 对目标对象访问进行控制.在访问目标前,后进行功能的扩展.
  - 可以进行功能扩展的技术:
    - 过滤器
    - 拦截器
    - 代理
    - …
2- 代理方式:
    - 静态代理:只能代理一种类型的对象.代理类需要自定义开发.
    - 动态代理:可以代理所有的类型对象.代理类由代理工具类动态生成.
        -JDK动态代理
           - 基于接口进行代理.
            - 目标对象必须实现相关的接口,才能使用这种代理方式.
            - 代理类和目标类实现了共同的接口.
            - InvocationHandler
       - Cglib/Javassist
            - 基于继承方式进行代理的.
            - 代理类是目标类的子类.
3- 代理流程:
    - 使用代理前代码结构:
        - A(客户端) -> D(目标程序(业务代码+非业务代码(日志,事务,权限,校验…)))
    - 使用代理后代码结构:
        - A(客户端) ->B(代理对象) ->C(调用处理器(非业务代码(日志,事务,权限,校验…))-> D(目标程序(业务代码))
4- 代理可以解决系统中哪些问题?
    - 日志打印,事务处理,权限控制,数据校验…
2.代理设计模式的使用案例
1.定义目标类接口
public interface MathCalculator {
int add(int i,int j);
int sub(int i,int j);
int mul(int i, int j);
int div(int i,int j);
}
2.定义目标类
//如何增加日志扩展
//如果在已有的业务代码中增加日志扩展代码,不好:
//业务代码和非业务代码进行耦合.不利于维护.日志代码 属于重复性代码.
//目标类
public class EazyImpl implements MathCalculator{
 
@Override
public int add(int i, int j) {
 
int result = i + j;
 
System.out.println("方法内部打印:result="+result);
 
return result;
}
 
@Override
public int sub(int i, int j) {
 
int result = i - j;
 
System.out.println("方法内部打印:result="+result);
 
return result;
}
@Override
public int mul(int i, int j) {
 
int result = i * j;
 
System.out.println("方法内部打印:result="+result);
 
return result;
}
 
@Override
public int div(int i, int j) {
int result = i / j; 
System.out.println("方法内部打印:result="+result); 
return result;
}
 
}
3.定义工具类
//工具类:用于动态生成代理对象.
public class ProxyProvider {
 
private Object targetObject ;
 
public ProxyProvider(Object targetObject){
this.targetObject = targetObject ;
} 
//动态创建代理对象.
public Object getProxy(){
/**
 * ClassLoader loader : 类加载器
 *                 用于加载代理类到JVM中运行.一般传递目标对象的类加载器就可以了.
 * Class<?>[] interfaces : 接口类型数组
 *                 JDK动态代理,基于接口的. 目标类和代理类实现共同的接口.需要通过目标对象来获取接口类型
 * InvocationHandler h : 调用处理器
 *代理类是在内存中动态生成的.无法将扩展代码写在代理类中.所以,需要通过InvocationHandler接口编写实现类,来完成功能扩展.
 */
returnProxy.newProxyInstance(
targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),
newInvocationHandler(){
/**
 * Object proxy : 代理对象
 * Method method : 调用目标方法对象
 * Object[] args : 调用目标方法的参数
 */
@Override
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
Object result = null ;
try {//扩展日志
System.out.println("[日志]["+method.getName()+"方法开始][参数值:
                                                       "+(args==null?"":Arrays.asList(args))+"]");
 
//执行目标
result = method.invoke(targetObject, args);
 
//扩展日志
System.out.println("[日志]["+method.getName()+"方法结束][返回值:"+result+"]");
} catch (Exception e) {
//扩展日志
e.printStackTrace();
Throwable cause = e.getCause();
if(cause!=null){
System.out.println("[日志]["+method.getName()+"方法异常了][异常消息:"+cause.getMessage()+"]");                                                                
}
} finally{
//扩展日志
System.out.println("[日志]["+method.getName()+"方法最终结束了]");
}
 
return result;
}
});
}
}
4.定义测试类
public static void main(String[] args) {
 
MathCalculator calculator = new EazyImpl(); //目标对象
calculator.add(10, 5);
calculator.sub(10, 5);
calculator.mul(10, 5);
calculator.div(10, 5); 
System.out.println("------------------------------");
 
//通过工具类来创建代理对象
//代理对象的类名:$Proxy + 数字
Object proxyObject = new ProxyProvider(calculator).getProxy();
 
//A(客户端) -> B(代理程序) -> C(InvocationHandler(日志打印)) -> D(目标程序)
MathCalculator proxy = (MathCalculator)proxyObject;
proxy.add(10, 5);
proxy.sub(10, 5);
proxy.mul(10, 5);
proxy.div(10, 0);
}
原创粉丝点击