设计模式-代理模式
代理模式类型优点缺点静态代理简单直观类型安全代码重复每个接口都要写代理类JDK动态代理无需每个接口写代理类只能代理接口CGLIB动态代理可以代理类需要第三方库性能略低SpringAop声名式零入侵只能代理public方法代码第一部分普通例子静态代理编译期绑定核心痛点为了给每个方法加日志你必须手动创建一个实现相同接口的代理类代码冗余且难以维护。// 1. 定义业务接口publicinterfaceUserService{voidsaveUser(Stringname);StringfindUser(Longid);}// 2. 真实业务实现只关心核心逻辑publicclassUserServiceImplimplementsUserService{OverridepublicvoidsaveUser(Stringname){System.out.println(核心业务保存用户 name);}OverridepublicStringfindUser(Longid){System.out.println(核心业务查询用户 id);returnUser_id;}}// 3. 静态代理类必须实现同一接口并持有真实对象引用publicclassUserServiceStaticProxyimplementsUserService{privatefinalUserServicetarget;// 目标对象publicUserServiceStaticProxy(UserServicetarget){this.targettarget;}OverridepublicvoidsaveUser(Stringname){System.out.println([静态代理] 开始保存...);longstartSystem.currentTimeMillis();target.saveUser(name);// 调用真实逻辑System.out.println([静态代理] 保存结束耗时: (System.currentTimeMillis()-start)ms);}OverridepublicStringfindUser(Longid){System.out.println([静态代理] 开始查询...);longstartSystem.currentTimeMillis();Stringresulttarget.findUser(id);System.out.println([静态代理] 查询结束耗时: (System.currentTimeMillis()-start)ms);returnresult;}}// 4. 客户端调用必须显式创建代理对象publicclassClient{publicstaticvoidmain(String[]args){// 真实对象UserServicerealServicenewUserServiceImpl();// 手动包装成代理UserServiceproxynewUserServiceStaticProxy(realService);proxy.saveUser(张三);// 输出开始保存... - 核心业务... - 结束耗时...proxy.findUser(1L);}}静态代理的致命伤如果我有 OrderService、ProductService 等几十个接口就得写几十个代理类且每个方法都要重复写日志代码完全违背 DRY 原则。第二部分Spring中的例子动态代理 AOP运行时绑定在Spring中你完全不需要手动创建 UserServiceStaticProxy 类。Spring 会在容器启动时利用 JDK动态代理 或 CGLIB 自动生成代理对象并将横切逻辑织入。// 1. 业务代码保持纯净无任何侵入Service// 交给Spring管理publicclassUserServiceImplimplementsUserService{OverridepublicvoidsaveUser(Stringname){System.out.println(核心业务保存用户 name);}OverridepublicStringfindUser(Longid){System.out.println(核心业务查询用户 id);returnUser_id;}}// 2. 定义一个切面类拦截所有Service层的public方法AspectComponentpublicclassLoggingAspect{// 切点表达式拦截 service 包下所有类的所有方法Around(execution(* com.example.service.*.*(..)))publicObjectlogExecutionTime(ProceedingJoinPointjoinPoint)throwsThrowable{StringmethodNamejoinPoint.getSignature().getName();System.out.println([Spring AOP] 开始执行: methodName);longstartSystem.currentTimeMillis();try{// 重点这里执行目标对象的真实方法相当于静态代理里的 target.saveUser()ObjectresultjoinPoint.proceed();returnresult;}finally{longdurationSystem.currentTimeMillis()-start;System.out.println([Spring AOP] 执行结束耗时: durationms);}}}// 3. 业务调用完全无感知直接从容器拿BeanRestControllerpublicclassUserController{AutowiredprivateUserServiceuserService;// 注意Spring注入的其实是代理对象GetMapping(/save)publicvoidtest(){userService.saveUser(李四);// 实际输出Spring AOP 开始 - 核心业务 - Spring AOP 结束}}

相关新闻