一、代理模式简介

代理:例如A没空,叫B去帮他完成某个事,B就是A的代理人,A就是被代理人
代理模式的作用:在不修改原代码的情况下增强一个类的功能
被代理类A:需要增强功能类 委托类
代理类B:增强代码编写的地方 A类的代理类

**
46 - 代理模式 - 图1

二、静态代理

代理类B需要程序员手动的编写,代码需要写死,静态
1、需要一个公共的接口 BankService
2、被代理类必须实现该接口 BankServiceImpl
3、需要编写代理类,代理类也必须实现公共接口,代理类中需要有一个被代理类的属性

代码:

  1. //公共的接口
  2. interface BankService{
  3. public void transfer();
  4. }
  5. //被代理类:添加事务处理的代码、功能
  6. class BankServiceImpl implements BankService{
  7. @Override
  8. public void transfer() {
  9. System.out.println("加钱sql");
  10. System.out.println("减钱sql");
  11. }
  12. }
  13. //代理类
  14. class BankServiceProxy implements BankService{
  15. //指向被代理类对象
  16. public BankService bankService;
  17. public BankServiceProxy(BankService bankService) {
  18. super();
  19. this.bankService = bankService;
  20. }
  21. @Override
  22. public void transfer() {
  23. System.out.println("====开启事务====");
  24. //原有的功能
  25. bankService.transfer();
  26. System.out.println("====提交/回滚====");
  27. }
  28. }
  29. public class TestServlet {
  30. private BankService bankService = new BankServiceProxy(new BankServiceImpl());
  31. //处理转账请求
  32. @Test
  33. public void transfer() {
  34. bankService.transfer();
  35. }
  36. }

执行效果:

====开启事务====
加钱sql
减钱sql
====提交/回滚====

缺点:维护、扩展比较麻烦

三、动态代理

代理类B不需要程序员手动的编写,是由程序自动生成的,动态
动态代理的扩展性要比静态代理强一些

3.1 JDK动态代理

JDK自带的代理方式
1、需要一个公共的接口
2、被代理类需要实现接口
3、创建一个工厂类,需要提供一个方法用来获取被代理类对象,工厂必须拥有一个指向代理对象的属性

代码:

//公共的接口
interface BankService {
    public void transfer();
}

//被代理类:添加事务处理的代码、功能
class BankServiceImpl implements BankService {
    @Override
    public void transfer() {
        System.out.println("加钱sql");
        System.out.println("减钱sql");
    }
}

//代理工厂
class JdkProxyFactory {
    // 指向被代理类对象
    private Object target;

    public JdkProxyFactory(Object target) {
        super();
        this.target = target;
    }

    // 获取代理类对象的方法
    public Object getProxyInstance() {
        // 类加载器
        ClassLoader classLoader = this.getClass().getClassLoader();
        // 被代理类实现的所有接口
        Class<?>[] interfaces = target.getClass().getInterfaces();
        // invocationHandler处理器
        InvocationHandler handler = new InvocationHandler() {
            // 参数1:JDK生成的代理类对象
            // 参数2:需要调用的方法
            // 参数3:调用该方法时的参数
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("====开启事务====");
                //
                Object result = method.invoke(target, args);
                //
                System.out.println("====提交/回滚====");
                // 返回执行结果
                return result;
            }
        };

        // 参数1:类加载器
        // 参数2:被代理类实现的所有接口
        // 参数3:invocationHandler处理器
        return Proxy.newProxyInstance(classLoader, interfaces, handler);
    }
}

public class Jdk {
    // 一步到位
//    BankService bankService = 
//            (BankService)new JdkProxyFactory(new BankServiceImpl()).getProxyInstance();

    @Test
    public void test() {
        // 创建工厂
        JdkProxyFactory factory = new JdkProxyFactory(new BankServiceImpl());
        // 获取代理类对象
        Object proxy = factory.getProxyInstance();
        // com.woniuxy.dynamic.BankServiceImpl@2b05039f 重写了toString
        System.out.println(proxy);
        // class com.woniuxy.dynamic.$Proxy4 代理类,是BankService的子类
        System.out.println(proxy.getClass());
        // instanceof 判断某个对象是否是指定类型及其子类的对象
        if (proxy instanceof BankService) {
            BankService bankService = (BankService) proxy;
            // 调用业务
            // 调用的是代理类对象的方法,只要调用这些方法就会自动调用handler中的invoke方法
            bankService.transfer();
        }
    }
}

JDK代理实现的逻辑:
在创建代理类对象时给Proxy.newProxyInstance(classLoader,interfaces,handler);传递了三个参数,其中第二参数是被代理类实现的所有接口,所以JDK代理在生成代理类时实现这些接口,所以生成的代理类就是接口(BankService)的子类,所以生成的代理类对象也就是BankService类型的对象,之后在调用代理类对象相关方法时(transfer),会自动执行handler中的invoke方法,然后传入三个参数:代理类对象、调用的方法及方法的参数,然后在invoke方法中通过Object result = method.invoke(target, args);执行被代理类对象的方法(原有功能 SQL)然后返回结果。
接口与类、类与类之间的关系:
BankService 与 代理类($Proxy4) :父子关系,BankService 是父,$Proxy0是子
BankServiceImpl 与 代理类($Proxy0) :同胞、兄弟
image.png

缺点:被代理类必须实现接口

3.2 Cglib代理

第三方的代理方式,CGLIB代理也叫做子类代理,生成的代理类是被代理类的子类
1、没有实现任何接口的被代理类
2、创建一个工厂类,需要包含一个指向被代理类对象的属性,提供一个生成代理类对象的方法

导包:

asm-3.3.1.jar
cglib-2.2.2.jar

代码:

//被代理类
class CBankServiceImpl {
    public void transfer() {
        System.out.println("加钱sql");
        System.out.println("减钱sql");
    }
}

//工厂类
class CglibProxyFactory {
    // 指向被代理类的对象
    private Object target;

    public CglibProxyFactory(Object target) {
        super();
        this.target = target;
    }

    // 获取代理类对象
    public Object getProxyInstance() {
        // 创建工具类对象:生成代理类对象
        Enhancer enhancer = new Enhancer();
        // 指定代理类的父类(被代理类)
        enhancer.setSuperclass(target.getClass());
        // 设置处理器
        enhancer.setCallback(new MethodInterceptor() {
            // 参数1:生成的代理类对象
            // 参数2:需要调用的方法
            // 参数3:调用该方法时的参数
            @Override
            public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("====开启事务====");
                // 执行原功能
                Object result = method.invoke(target, args);
                System.out.println("====提交/回滚====");
                return result;
            }
        });
        //生成代理类对象
        return enhancer.create();
    }
}

public class Cglib {
    // 一步到位
//    CBankServiceImpl cBankServiceImpl = 
//            (CBankServiceImpl) new CglibProxyFactory(new CBankServiceImpl()).getProxyInstance();

    @Test
    public void test() {
        CglibProxyFactory factory = new CglibProxyFactory(new CBankServiceImpl());
        //
        Object proxy = factory.getProxyInstance();
        // class com.woniuxy.staticproxy.CBankServiceImpl$$EnhancerByCGLIB$$271ac22b
        System.out.println(proxy.getClass());
        //
        if(proxy instanceof CBankServiceImpl) {
            CBankServiceImpl impl = (CBankServiceImpl)proxy;
            impl.transfer();
        }
    }
}

缺点:被代理类不能是final修饰的
注意:生成的代理类是被代理类的子类