什么是代理模式

代理模式为另一个对象提供一个替身或占位符以控制对这个对象的访问。
代理模式可以在不改变源码的情况下,实现对目标对象的扩展。

Java的三种代理模式

1、静态代理

创建服务类接口和实现服务类接口

public interface Singer {
     void sing();
}

public class MaleSinger implements Singer {
    public void sing() {
    	System.out.println("男歌手唱一首歌");
	}
}

设置代理类

public class SingerProxy implements Singer{
    private Singer target;
    
    public SingerProxy(Singer target){
        this.target=target;
    }
    // 对目标对象的sing方法进行功能扩展
    public void sing() {
        System.out.println("向观众问好");
        target.sing();
        System.out.println("谢谢大家");
    }
}

我们测试一下

public class Test {
    public static void main(String[] args) {
        //目标对象
        Singer target = new MaleSinger();
        //代理对象
        Singer proxy = new SingerProxy(target);
        //执行的是代理的方法
        proxy.sing();
    }
}

执行结果

向观众问好
男歌手唱一首歌
谢谢大家

代理模式最主要的就是有一个公共接口(Singer),一个具体的类(MaleSinger),一个代理类(SingerProxy)。再执行具体类的方法时,可以由操作代理类实现,并且可以额外做一些代码增强功能。

2、动态代理(JDK代理)

创建服务类接口和实现服务类接口

public interface Singer {
     void sing();
}

public class MaleSinger implements Singer {
    public void sing() {
    	System.out.println("男歌手唱一首歌");
	}
}

调用Proxy类的静态方法newProxyInstance即可,该方法会返回代理类对象

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

接收的三个参数依次为:

  • ClassLoader loader:指定当前目标对象使用类加载器,写法固定
  • Class<?>[] interfaces:目标对象实现的接口的类型,写法固定
  • InvocationHandler h:事件处理接口,需传入一个实现类,一般直接使用匿名内部类
public class Test{
    public static void main(String[] args) {
	  	Singer target = new Singer();
        ISinger proxy  = (ISinger) 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("向观众问好dynamic");
                        //执行目标对象方法
                        Object returnValue = method.invoke(target, args);
                        System.out.println("谢谢大家dynamic");
                        return returnValue;
                    }
                });
        proxy.sing();
    }
}

执行结果

向观众问好dynamic
男歌手唱一首歌
谢谢大家dynamic

动态代理包括一个公共接口(Singer),一个被代理类(MaleSinger),一个代理类(SingerProxy),还有一个中介类(InvocationHandler代理功能实现类)。
动态代理由于内部生成机制,被代理类必须是继承自接口的。动态代理有灵活功能强大,对目标类无侵入等明显的优点。

3、CGLIB代理

前提条件:

  • 需要引入cglib的jar文件,由于Spring的核心包中已经包括了Cglib功能,所以也可以直接引入spring-core-3.2.5.jar
  • 目标类不能为final
  • 目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法
/**
 * Cglib子类代理工厂
 */
public class ProxyFactory implements MethodInterceptor{
    // 维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    // 给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("向观众问好");
        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);
        System.out.println("谢谢大家");
        return returnValue;
    }
}