Spring AOP中的代理模式

一、代理模式

类A需要完成的工作由类B去完成,类B实际上是在类A的基础上作了一层封装,类B包括原始类A的业务逻辑以及前后的扩展逻辑,实现了类A的功能扩展
类A→被代理类/代理目标类/委托类
类B→代理类

二、静态代理

手动创建代理类,代理类的实现方法中对对原始的业务逻辑进行了扩展,两个要点:

  1. 代理类、委托类需要实现相同的接口
  2. 代理类中持有委托类的对象

特点:

  1. 每进行一次功能扩展,就要对委托类手动创建至少一个相对应的代理类
  2. 原理简单,但是程序过于繁琐与臃肿

定义一个接口,

package com.imooc.spring.aop.service;

public interface UserService {
    public void createUser();
}

委托类,

package com.imooc.spring.aop.service;

public class UserServiceImpl implements UserService{
    public void createUser() {
        System.out.println("执行创建用户业务逻辑");
    }
}

代理类,

package com.imooc.spring.aop.service;

import java.text.SimpleDateFormat;
import java.util.Date;
//静态代理是指必须手动创建代理类的代理模式使用方式
public class UserServiceProxy implements UserService{
    //持有委托类的对象
    private UserService userService ;
    public UserServiceProxy(UserService userService){
        this.userService = userService;
    }

    public void createUser() {
        //添加其他的逻辑,实现功能扩展
        System.out.println("========静态代理前置扩展功能======");
        userService.createUser();
        System.out.println("========静态代理后置扩展功能======");
    }
}

测试入口类,

package com.imooc.spring.aop;

import com.imooc.spring.aop.service.UserService;
import com.imooc.spring.aop.service.UserServiceImpl;
import com.imooc.spring.aop.service.UserServiceProxy;
import com.imooc.spring.aop.service.UserServiceProxy1;

public class Application {
    public static void main(String[] args) {
        UserService userService = new UserServiceProxy(new UserServiceImpl());
        userService.createUser();
    }
}

测试结果,

========静态代理前置扩展功能======
执行创建用户业务逻辑
========静态代理后置扩展功能======

三、动态代理

动态代理分为JDK动态代理、CGLib动态代理

JDK动态代理

接口、委托类沿用上面的Userservice、UserserviceImpl,JDK动态代理需要实现InvocationHandler接口,重写invoke方法 ,

package com.imooc.spring.aop.service;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * InvocationHandler是JDK提供的反射类,用于在JDK动态代理中对目标方法进行增强
 * InvocationHandler实现类与切面类的环绕通知类似
 */
public class ProxyInvocationHandler implements InvocationHandler {
    private Object target;//目标对象,对所有类生效,所以目标对象类型选择Object
    public ProxyInvocationHandler(Object target){
        this.target = target;
    }
    /**
     * 在invoke()方法对目标方法进行增强
     * @param proxy 代理类对象
     * @param method 目标方法对象
     * @param args 目标方法实参
     * @return 目标方法运行后返回值
     * @throws Throwable 目标方法抛出的异常
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("========JDK动态代理前置扩展功能======");
        Object ret = method.invoke(target, args);//调用目标方法,类似环绕通知中的ProceedingJoinPoint.proceed()
        System.out.println("========JDK动态代理后置扩展功能======");
        return ret;
    }

}

测试入口类,

package com.imooc.spring.aop;

import com.imooc.spring.aop.service.*;

import java.lang.reflect.Proxy;

public class Application {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(userService);
        //动态创建代理类
        //Proxy.newProxyInstance 根据已经存在的接口,实现其相对应的代理类
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
                userService.getClass().getInterfaces(),
                invocationHandler);
        userServiceProxy.createUser();

        
    }
}

测试结果,

========JDK动态代理前置扩展功能======
执行创建用户业务逻辑
========JDK动态代理后置扩展功能======

JDK动态代理逻辑框图

JDK动态代理主要包括两个步骤:
1.UserService userServiceProxy =Proxy.newProxyInstance();//创建代理类,newProxyInstance()根据已有的接口,生成对应的代理类
2.userServiceProxy.createUser(); //代理类与委托类实现了相同的接口,代理类实现接口中的业务逻辑

1.Proxy.newProxyInstance()在执行步骤:

  1. 在本地硬盘上创建$Proxy0.class代理类的class文件
  2. 确定代理类的包名:com.sun.proxy
  3. 确定代理类的类名:com.sun.proxy.$Proxy0
  4. ProxyGenerator.generateProxyClass生成代理类的代码,具体可参考图中的伪代码
  5. defineclass0将硬盘中的.Class字节码文件通过被代理类的classLoder(类加载器),载入到当前JVM的方法区中,并通过new $Proxy0实例化对象,$Proxy0对象中包含UserServiceImpl对象的引用
  6. 第5步得到代理类的对象userServiceProxy ,至此完成了Proxy.newProxyInstance()的所有工作

动态生成的代理类$Proxy0与委托类UserServiceImpl实现了相同的接口UserService

代理类$Proxy0中包含委托类的对象的引用:targetObject

实现接口中的方法:具体实现代码来自InvocationHandler实现类中的invoke方法

2.调用userServiceProxy.createUser();实现委托类的功能扩展,createUser()中的代码对应伪代码中方法中的业务逻辑

CGLib动态代理

委托类实现了接口,可以通过JDK动态代理实现功能扩展,委托类没有接口,则通过CGLib第三方组件实现功能扩展
CGLib第三方组件继承需要增强的类,产生一个子类,并重写父类中的方法,实现功能扩展

参考文献

1.https://www.cnblogs.com/teach/p/10763845.html

扩展阅读

1.类加载机制 https://www.cnblogs.com/insist-bin/p/11223876.html

原文地址:https://www.cnblogs.com/little-mao2020/p/14235065.html