设计模式系列三-代理模式

代理模式主要有两个目的:

1、保护被代理对象

2、增加被代理对象

静态代理:

静态代理就是利用代理对象持有被代理对象

举个栗子:

public interface Animal {
    void dosomething();
}
public class Bird implements Animal {

    @Override
    public void dosomething(){
        System.out.println("bird fly");
    }
}

 

public class StaticProxy {

    private Animal animal;
    public StaticProxy(Animal animal){
        this.animal = animal;
    }
    public void dosomething(){
        System.out.println("静态代理");
        animal.dosomething();
    }

}

 

public class Test2 {
    public static void main(String[] args) {
        Bird bird = new Bird();
        // 静态代理
        StaticProxy staticProxy = new StaticProxy(bird);
        staticProxy.dosomething();

    }
}

动态代理

jdk动态代理

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

public class JDKProxy implements InvocationHandler {
    private Bird bird;

    public Object getInstance(Bird bird){
        //生成$Proxy0的class文件,也就是代理类的字节码文件
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        this.bird = bird;
        Class<? extends Bird> clazz = bird.getClass();
        // 这里生成代理对象
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("jdk动态代理");
        before();
        Object invoke = method.invoke(bird, args);
        after();
        return invoke;
    }
    private void before(){
        System.out.println("jdk before");
    }
    private void after(){
        System.out.println("jdk after");
    }

}

 

public class Test2 {
    public static void main(String[] args) {
        Bird bird = new Bird();
        // jdk动态代理
        Animal proxy = (Animal) new JDKProxy().getInstance(bird);
        proxy.dosomething();
    }
}

 

代理方法:

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

newProxyInstance,方法有三个参数:

loader: 用哪个类加载器去加载代理对象,就是产生的代理类会是这个类的实现类

interfaces:动态代理类需要实现的接口,会把这里传入的所有方法都增强,都会调用invoke方法

h:动态代理方法在执行时,会调用h里面的invoke方法去执行,也就是InvocationHandler的实现类,用内部类的方式也行

Animal proxyDog = (Animal)Proxy.newProxyInstance(target.getClass().getClassLoader(), 
                target.getClass().getInterfaces(),new InvocationHandler() {
                    
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("jdk动态代理....");
                        method.invoke(target, args);
                        return null;
                    }
                });

 

cglib动态代理

需要引入cglib包

<dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>2.2.2</version>
</dependency>
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {

    public Animal getInstance(Class<?> clazz){
        // 输出生成的代理类 方便理解原理
        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "c:/");
        // 创建 增强器  类似JDK的proxy类
        Enhancer enhancer = new Enhancer();
        // 设置目标类
        enhancer.setSuperclass(clazz);
        // 设置回调函数  也就是实现了MethodInterceptor接口的类
        enhancer.setCallback(this);
        // 创建代理类
        Animal o = (Animal) enhancer.create();
        return o;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib动态代理");
        before();
        Object o1 = methodProxy.invokeSuper(o, objects);
        after();
        return o1;
    }

    private void before(){
        System.out.println("cglib Proxy before method.");
    }
    private void after(){
        System.out.println("cglib Proxy after method.");
    }
}
public class Test2 {
    public static void main(String[] args) {
        // cglib动态代理
        Animal instance = new CglibProxy().getInstance(Bird.class);
        instance.dosomething();
    }
}

 

也可以仿造jdk、cglib的方式自己实现动态代理模式,思路都是动态生成java代理类然后动态加载

Cglib 采用了 FastClass 机制,它的原理简单来说就是:为代理类和被代理类各生成一个 Class,这个 Class 会为代理类或被代理类的方法分配一个 index(int 类型)。这个 index 当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比 JDK动态代理通过反射调用高

 CGLib 和 JDK 动态代理对比

1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。
2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。
3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法,CGLib 执行效率更高。

静态代理和动态的本质区别

1、静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步新增,违背开闭原则。
2、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。
3、若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码。

代理模式的优缺点

使用代理模式具有以下几个优点:

1、代理模式能将代理对象与真实被调用的目标对象分离。
2、一定程度上降低了系统的耦合度,扩展性好。
3、可以起到保护目标对象的作用。
4、可以对目标对象的功能增强。

当然,代理模式也是有缺点的:

1、代理模式会造成系统设计中类的数量增加。
2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
3、增加了系统的复杂度

 Spring中的代理模式 Proxy开头的类,AOP实现

 

posted @ 2020-05-13 14:59  link_ed  阅读(131)  评论(0编辑  收藏  举报