AOP实现原理 CGLib与JDK动态代理
Spring AOP实现原理
Spring基于代理模式实现功能动态扩展,包含两种形式:
1.目标类拥有接口,通过JDK动态代理实现功能扩展。
2.目标类没有接口,通过CGLib组件实现功能扩展
代理模式
代理模式通过 代理对象 对 原对象的实现功能 进行拓展
静态代理
静态代理实现功能拓展,实现目标方法执行前打印时间这一功能
package com.spring.aop.service;
public interface UserService {
public void createUser();
}
package com.spring.aop.service;
public class UserServiceImpl implements UserService{
@Override
public void createUser() {
System.out.println("执行创建用户业务逻辑");
}
}
package com.spring.aop.service;
import java.text.SimpleDateFormat;
import java.util.Date;
public class UserServiceProxy implements UserService{
//代理类特点:持有委托类的对象
private UserService userService;
//在创建代理对象UserServiceProxy时,通过外部传入的参数UserService实现类,为内部委托类赋值
public UserServiceProxy(UserService userService){
this.userService = userService;
}
@Override
public void createUser() {
//功能的拓展,在执行目标方法之前打印时间
System.out.println("=====" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()) + "=====");
userService.createUser();
}
}
package com.spring.aop;
import com.spring.aop.service.UserService;
import com.spring.aop.service.UserServiceImpl;
import com.spring.aop.service.UserServiceProxy;
public class Application {
public static void main(String[] args) {
UserService userService = new UserServiceProxy(new UserServiceImpl());
userService.createUser();
}
}
代理模式可以嵌套使用
在上述代理模式上增加一个代理类UserServiceProxy1实现后置通知功能
package com.spring.aop.service;
public class UserServiceProxy1 implements UserService{
private UserService userService;
public UserServiceProxy1(UserService userService){
this.userService = userService;
}
@Override
public void createUser() {
userService.createUser();
System.out.println("========后置通知==========");
}
}
package com.spring.aop;
import com.spring.aop.service.UserService;
import com.spring.aop.service.UserServiceImpl;
import com.spring.aop.service.UserServiceProxy;
import com.spring.aop.service.UserServiceProxy1;
public class Application {
public static void main(String[] args) {
UserService userService = new UserServiceProxy1(new UserServiceProxy(new UserServiceImpl()));
userService.createUser();
}
}
静态代理中,每进行一次功能拓展都需要手动创建一个代理类,随着大型项目的功能不断完善,每一个业务实现类都要至少拥有一个代理类,当业务实现类数量极高时,是否还需要给每一个实现类增加对应的代理类?
动态代理
反射机制可以根据要实现的接口结构,自动生成相应的代理类,完成目标方法的扩展工作,这个过程中代理类是通过反射在运行时自动生成的。静态代理需要手写代理类,动态代理根据接口结构在运行时自动地动态生成
基于JDK动态代理完成对UserServiceImpl实现类的功能扩展
package com.spring.aop.service;
public interface UserService {
public void createUser();
}
package com.spring.aop.service;
public class UserServiceImpl implements UserService{
@Override
public void createUser() {
System.out.println("执行创建用户业务逻辑");
}
}
package com.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;//目标对象
private ProxyInvocationHandler(Object target){
this.target = target;
}
/**
* 在invoke()方法对目标进行增强
* @param proxy 代理类对象
* @param method 目标方法对象
* @param args 目标方法实参
* @return 目标方法运行后返回值
* @throws Throwable 目标方法抛出的异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("=====" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()) + "=====");
Object ret = method.invoke(target, args);//调用目标方法,对应环绕通知中ProceedingJoinPoint.proceed()
return ret;
}
public static void main(String[] args) {
//动态代理必须实现接口才可以运行
UserService userService = new UserServiceImpl();
ProxyInvocationHandler invocationHandler = new ProxyInvocationHandler(userService);
//动态创建代理类
//Proxy.newProxyInstance方法用于基于接口创建指定代理类
// 三个参数: 类加载器,userService要实现的接口对象,invocationHandler对象
UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),
userService.getClass().getInterfaces(),
invocationHandler);
userServiceProxy.createUser();
}
}
CGLib 运行时字节码增强技术
Spring AOP拓展无接口类使用CGLib,当目标类无实现接口,AOP会运行时生成 目标继承类字节码 的方式进行行为拓展。CGLib的实现原理是,在原始目标类的基础上进行继承,然后重写每一个方法进行增强
当UserService实现了某个接口时,Spring AOP会优先选择动态代理实现功能增强
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!