1、代理模式

原理

使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

代理模式是Java开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。

使用场景

说明: untitle.png

静态代理

代码举例

public interface Work {
    void doWork();
}
//被代理类
public class NetWork implements Work{
    @Override
    public void doWork() {
        System.out.println("run NetWork");
    }
}
//代理类
public class WorkProxy implements Work{

    private Work work;

    public WorkProxy(Work work){
        this.work = work;
    }

    @Override
    public void doWork() {
        System.out.println("run WorkProxy");
        work.doWork();
    }
}
public static void main(String[] args) {
    NetWork netWork = new NetWork();
    WorkProxy workProxy = new WorkProxy(netWork);
    workProxy.doWork();
    //run WorkProxy
    //run do Work
}

静态代理的缺点

① 代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。

② 每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。

动态代理

动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。

动态代理使用的场合

1、调试

2、远程方法调用

需要解决的问题

问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。

通过Proxy.newProxyInstance()实现

问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。

(通过InvocationHandler接口的实现类及其方法invoke())

相较静态代理的优点

抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。

两种方式生成动态代理

方式一:java.lang.reflect.Proxy

Proxy.newProxyInstance(目标对象的类加载器,目标对象的接口,InvocationHandler调用代理对象时做的事情 )

代码举例
public interface Work {
    void doWork();
}
public class NetWork implements Work{
    @Override
    public void doWork() {
        System.out.println("run NetWork");
    }
}
public static void main(String[] args) {
    NetWork netWork = new NetWork();
    Work proxy =  proxy(netWork);
    proxy.doWork();
    //run Proxy
    //run NetWork
}

//进行Proxy动态代理,返回代理对象
public static<T> T proxy(T obj){
    Class clazz = obj.getClass();
	//newProxyInstance方法,返回的就是代理对象
    T proxtObj = (T)Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
        //proxy代理对象
        //method调用的方法
        //args方法的参数
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("run Proxy");
            return method.invoke(obj, args);
        }
    });

    return proxtObj;
}

方式二:Cglib,子类代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理

使用方法

1、引入cglib的jar文件和asm的jar文件到工程

2、引入功能包后,就可以在内存中动态的创建子类

3、被代理类不可以使用final,否则报错

4、被代理的方法,不可以使用final或static修饰

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.10</version>
</dependency>
工厂类
public static void main(String[] args) {
    NetWork netWork = new NetWork();
    NetWork cglibProxy = cglib(netWork);
    cglibProxy.doWork();
    //run Cglib Proxy
    //run NetWork
}

public static<T> T cglib(T obj){
    //创建一个增强器
    Enhancer enhancer = new Enhancer();
    //设置父类,也就是被代理类
    enhancer.setSuperclass(obj.getClass());
    //设置方法的处理扩展
    enhancer.setCallback(new MethodInterceptor() {
        //o代理对象本身
        //method被代理对象的方法
        //objects方法的参数
        //methodProxy方法的代理
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("run Cglib Proxy");
            return method.invoke(obj,objects);
        }
    });
    //获取一个代理对象
    return (T) enhancer.create();
}