了解Spring中常见的设计模式-------------------代理模式

拜拜、爱过 提交于 2020-01-28 05:25:29

代理模式(Proxy Pattern)

指为其他对象提供一种代理,以控制对这个对象的访问。

代理对象在客服端和目标对象之间起到中介作用

属于结构型设计模式。

 

适用场景:保护目标对象,增强目标对象

静态代理:显示声明被代理对象

动态代理:动态配置和替换被代理对象

                 无法代理final修饰的方法

 

静态代理

代理类与被代理类属于(1:1)一对一的关系,被代理类新增了某个方法,代理类也需要进行相应的修改,不符合开闭原则。

public interface Person {
    void saleHouse();

    void getName();
}



public class HousHolder implements Person {
    @Override
    public void saleHouse() {
        System.out.println("houseHolder sale house");
    }

    @Override
    public void getName() {
        System.out.println("the name of house");
    }
}



public class HouseSaler implements Person {

    private HousHolder housHolder;

    public HouseSaler(HousHolder housHolder) {
        this.housHolder = housHolder;
    }

    @Override
    public void saleHouse() {
        System.out.println("HouseSaler sale house for houseHolder!===begin");
        this.housHolder.saleHouse();
        System.out.println("HouseSaler sale house for houseHolder!===end");

    }

    @Override
    public void getName() {
        System.out.println("the name of house saled by HouseSaler!===begin");
        this.housHolder.getName();
        System.out.println("the name of house saled by HouseSaler!===end");
    }
}



public class HouseTest {

    public static void main(String[] args) {
        HouseSaler houseSaler = new HouseSaler(new HousHolder());
        houseSaler.saleHouse();
        houseSaler.getName();
    }
}


结果输出为:
HouseSaler sale house for houseHolder!===begin
houseHolder sale house
HouseSaler sale house for houseHolder!===end
the name of house saled by HouseSaler!===begin
the name of house
the name of house saled by HouseSaler!===end

 

 

动态代理

实现原理:

1、拿到被代理类的引用,并获取它的所有的接口(反射获取)。

2、JDK Proxy 类重新生成一个新的类,实现了被代理类所有的接口的方法。

3、动态代理生成Java代理,把增强逻辑加入到新生成的代码中。

4、编译生成新的Java代码的class文件。

5、加载并重新运行新的class,得到的类就是全新的类。

 

优点:能将代理对象与真实被调用的目标对象分开;降低了系统的耦合程度,易于扩展;保护了目标对象;增强了目标对象的职责;

缺点:会增加系统设计中类的数目;在客户端与被代理对象之间增加了一个代理对象,会造成请求处理速度变慢;增加系统的复杂度;

用途:动态代理用于实现AOP编程,可以在不修改类源码,在类方法执行的前后添加其他的操作,如:拦截处理,日志打印....

 

JDK Proxy示例

注意:被代理的类必须实现接口,用于JDK Proxy 重新生成的类实现其接口的所有方法

public interface Person {
    void saleHouse();

    void getName();
}

public class HouseHolder implements Person {


    public HouseHolder() {
    }

    public void saleHouse() {
        System.out.println("房屋持有者卖房");
    }

    @Override
    public void getName() {
        System.out.println("get houser name");
    }
}


public class SalerMedia<T> implements InvocationHandler {

    private T person;

    public Object getInstance(T person) {
        this.person = person;
        Class<?> clazz = person.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(person, args);
    }
}


public class HouseSaleTest {

    public static void main(String[] args) {
        Person person = (Person)new SalerMedia().getInstance(new HouseHolder());
        person.saleHouse();

        byte[] bytes = ProxyGenerator.generateProxyClass("$Proxy0", new Class[] {Person.class});
        try {
            FileOutputStream outputStream = new FileOutputStream("D:\\personPackage\\gupao\\$Proxy0.class");
            outputStream.write(bytes);
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


测试输出结果为:
房屋持有者卖房

HouseHolder 为被代理对象,实现了接口类(Person);

SalerMedia 为代理类,实现了InvocationHandler 接口,通过调用getInstance(T object)方法,JDK动态生成代理类$Proxy0,

调用$Proxy0.saleHouse(),会执行代理类SalerMedia的invoke(.....)方法,实现代理。

 

反编译生成的$proxy.class 文件:

public final class $Proxy0 extends Proxy
    implements Person
{

    public $Proxy0(InvocationHandler invocationhandler)
    {
        super(invocationhandler);
    }

    public final boolean equals(Object obj)
    {
        try
        {
            return ((Boolean)super.h.invoke(this, m1, new Object[] {
                obj
            })).booleanValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void getName()
    {
        try
        {
            super.h.invoke(this, m3, null);
            return;
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString()
    {
        try
        {
            return (String)super.h.invoke(this, m2, null);
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void saleHouse()
    {
        try
        {
            super.h.invoke(this, m4, null);
            return;
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode()
    {
        try
        {
            return ((Integer)super.h.invoke(this, m0, null)).intValue();
        }
        catch(Error _ex) { }
        catch(Throwable throwable)
        {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m4;
    private static Method m0;

    static 
    {
        try
        {
            m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
                Class.forName("java.lang.Object")
            });
            m3 = Class.forName("com.tealala.pattern.proxy.Person").getMethod("getName", new Class[0]);
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m4 = Class.forName("com.tealala.pattern.proxy.Person").getMethod("saleHouse", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
        }
        catch(NoSuchMethodException nosuchmethodexception)
        {
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());
        }
        catch(ClassNotFoundException classnotfoundexception)
        {
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());
        }
    }
}

 

CGLib动态代理

通过生成被代理类的【子类】实现代理,所以 Cglib是无法代理final修饰的方法或类

public interface Person {
    void saleHouse();

    void getName();
}


public class HouseHolder implements Person {
    @Override
    public void saleHouse() {
        System.out.println("CGLib houseHolder sale house");
    }

    @Override
    public void getName() {
        System.out.println("CGLib the name of house");
    }
}


public class HouseSaler implements MethodInterceptor {
    //相当于Proxy,代理的工具类
    Enhancer enhancer = new Enhancer();

    public Object getInstance(Class<?> clazz) {
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object o1 = methodProxy.invokeSuper(o, objects);
        after();
        return o1;
    }

    public void before() {
        System.out.println("CGLib begin");
    }

    public void after() {
        System.out.println("CGLib end");
    }
}


public class CGLibTest {

    public static void main(String[] args) {

        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\personPackage\\gupao");
        Person person = (Person)new HouseSaler().getInstance(HouseHolder.class);
        person.getName();
        person.saleHouse();
    }
}


执行结果:
CGLIB debugging enabled, writing to 'D:\personPackage\gupao'
CGLib begin
CGLib the name of house
CGLib end
CGLib begin
CGLib houseHolder sale house
CGLib end



 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!