模糊的概念(2)

这种概念的模糊,还是因为当时在看书或者学习某一个知识点的时候,没有能够把这个知识变为自己的东西,停留在比较浅层次的理解的基础上面,没有能够真正的运用上面,就像那些笑话中所说的一样,“这些道理臣妾都明白,可就是过不好日子”。道理光是明白肯定是过不好日子的,明白了,理解了,最重要的是想办法去应用,把学到的知识最终归到自己的知识体系里面,这样才算是真正的明白,才有过好日子的可能。

继续说设计模式:代理的设计模式,以前的理解,比较的高效,认为代理就是请求来临的时候,代理对象首先执行,然后在去执行被代理对象的方法。如果按照这种大而化之的理解,那么组合类里面的任何一个调用都是代理模式了。

还是首先是简单的UML:

latex-table

真正的对象和代理对象都会实现这个接口,然后在调用的时候,调用的是代理的对象,然后代理的对象再去调用真正的对象。

// 抽象角色:
abstract public class Subject {
    abstract public void  request();
}

// 真实角色:实现了Subject的request()方法
public class  RealSubject  extends  Subject  {
  public  RealSubject()  { }

  public void  request()  {
     System.out.println( " From real subject. " );
    }
}

// 代理角色:
public class  ProxySubject  extends  Subject  {
  // 以真实角色作为代理角色的属性
  private  Subject realSubject;

  public  ProxySubject(Subject realSubject)  {this.realSubject = realSubject }

  // 该方法封装了真实对象的request方法
  public void  request()  {
     preRequest();
     realSubject.request();  // 此处执行真实对象的request方法
     postRequest();
  }
  ...
}

// 客户端调用:
RealSubject real = new RealSubject();
Subject sub = new  ProxySubject(real);
Sub.request();

还有一种方式是继承的方式:

image

核心的代码是:

//dosomething before
    super.doOperation()  
   //dosomething after

  1. 采用父类的调用,不用接口的这种方式。

一般的情况下,真是的对象应该增加访问的限制,例如:不能够在外部的访问。

说到了代理模式,JDK实现了一个动态代理的模式,为什么会有这个动态代理,因为上面虽然实现了代理,但是每一个类一个代理的话,代码呈现臃肿,并且也不符合同一个功能对应一块或者一个类,或者说抽象封装的设计理念,所以就有了JDK的动态代理,其UML是:

image

具体的代码:

package regularExpression.current;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface ISubject {
    public void showName(String name);
}

class RealSubject implements ISubject {

    @Override
    public void showName(String name) {
        System.out.println(name+"闪亮登场");
    }

}

class LogHandler implements InvocationHandler {

    Object target=null;
    
    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result=null;
        //调用目标对象方法前的逻辑
        System.out.println("下面有一个大人物要出现");
        //调用目标对象的方法,这句代码将代理与目标类联系了起来
        method.invoke(target, args);
        //调用目标对象方法后的逻辑
        System.out.println("大家鼓掌欢迎");
        return result;
                
    }

}
public class Client {
    /**
     * @param args
     */
    public static void main(String[] args) {
        
        LogHandler logHandler=new LogHandler();
        logHandler.setTarget(new RealSubject());
        //创建代理对象
        ISubject proxySubject=(ISubject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), logHandler);
        System.out.println("-------JDK Proxy-------------");
        proxySubject.showName("委座");

    }

}

看到这个方法:java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class<?>[], InvocationHandler) 应该能够推出来:

JDK的动态代理,必须的要实现了接口的类才能够有动态代理,不然的话,在类Proxy的方法:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException

无法建立代理的实例,就无法代理了,但是cglib可以,具体的UML为:

image

可以看到的是RealSubject 不需要实现一个接口,

class LogIntercept implements MethodInterceptor {
    Object target=null;
    
    public Object getTarget() {
        return target;
    }

    public void setTarget(Object target) {
        this.target = target;
    }
    
    @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2,
            MethodProxy arg3) throws Throwable {
        
        Object result=null;
        //调用目标对象方法前的逻辑
        System.out.println("下面有一个大人物要出现");
        //调用目标对象的方法,这句代码将代理与目标类联系了起来
        arg3.invoke(target, arg2);
        //调用目标对象方法后的逻辑
        System.out.println("大家鼓掌欢迎");
        return result;
    }

}

调用的方式:

LogIntercept logIntercept=new LogIntercept();  
        logIntercept.setTarget(new RealSubject());        
        RealSubject proxySubject1=(RealSubject )Enhancer.create(RealSubject.class, logIntercept); 
        System.out.println("-------CBLIB-------------");  
        proxySubject1.showName("委座");

这也就能够理解spring提供两种代理方式的原因:

目标对象有没有实现接口Spring都会选择使用CGLIB代理。所以在默认情况下,如果一个目标对象如果实现了接口,Spring则会选择JDK动态代理策略动态的创建一个接口实现类(动态代理类)来代理目标对象,可以通俗的理解这个动态代理类是目标对象的另外一个版本,所以这两者之间在强制转换的时候会抛出j ava.lang.ClassCastException。而所以在默认情况下,如果目标对象没有实现任何接口,Spring会选择CGLIB代理, 其生成的动态代理对象是目标类的子类。

代理模式这样算是到一个阶段,这样才能够穿起来,理清一个点。

原文地址:https://www.cnblogs.com/zhailzh/p/4163150.html