首页 > 代码库 > 模糊的概念(2)

模糊的概念(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代理, 其生成的动态代理对象是目标类的子类。

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

模糊的概念(2)