iis服务器助手广告
返回顶部
首页 > 资讯 > 前端开发 > node.js >Spring aop的介绍和应用
  • 515
分享到

Spring aop的介绍和应用

2024-04-02 19:04:59 515人浏览 泡泡鱼
摘要

这篇文章主要讲解了“spring aop的介绍和应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring aop的介绍和应用”吧! 前言前几

这篇文章主要讲解了“spring aop的介绍和应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring aop的介绍和应用”吧!

 前言

前几篇文章本打算写spring  aop的,但是强忍着没有写(旁白:也有可能是没想好该怎么写?),就是为了今天整个专题,因为它是spring中最核心的技术之一,实在太重要了。

关于spring aop的文章网上一搜一大堆,但我想写点不一样的东西,尝试一种全新的写作风格,希望您会喜欢。

Spring aop的介绍和应用

从实战出发

很多文章讲spring aop的时候,一开始就整一堆概念,等我们看得差不多要晕的时候,才真正进入主题。。。

我却相反,没错,先从实战出发。

在spring aop还没出现之前,想要在目标方法之前先后加上日志打印的功能,我们一般是这样做的:

@Service public  class TestService {      public void doSomething1() {         beforeLog();         System.out.println("==doSomething1==");         afterLog();     }      public void doSomething2() {         beforeLog();         System.out.println("==doSomething1==");         afterLog();     }      public void doSomething3() {         beforeLog();         System.out.println("==doSomething1==");         afterLog();     }      public void beforeLog() {         System.out.println("打印请求日志");     }      public void afterLog() {         System.out.println("打印响应日志");     } }

如果加了新doSomethingXXX方法,就需要在新方法前后手动加beforeLog和afterLog方法。

原本相安无事的,但长此以往,总有会出现几个刺头青。

刺头青A说:每加一个新方法,都需要加两行重复的代码,是不是很麻烦?

刺头青B说:业务代码和公共代码是不是耦合在一起了?

刺头青C说:如果有几千个类中加了公共代码,而有一天我需要删除,是不是要疯了?

spring大师们说:我们提供一套spring的aop机制,你们可以闭嘴了。

下面看看用spring aop(偷偷说一句,还用了aspectj)是如何打印日志的:

@Service public  class TestService {      public void doSomething1() {         System.out.println("==doSomething1==");     }      public void doSomething2() {         System.out.println("==doSomething1==");     }      public void doSomething3() {         System.out.println("==doSomething1==");     } } @Component @Aspect public  class LogAspect {      @Pointcut("execution(public * com.sue.cache.service.*.*(..))")     public void pointcut() {     }      @Before("pointcut()")     public void beforeLog() {         System.out.println("打印请求日志");     }      @After("pointcut()")     public void afterLog() {         System.out.println("打印响应日志");     } }

增加了LogAspect类,在类上加了@Aspect注解。先在类中使用@Pointcut注解定义了pointcut方法,然后将beforeLog和afterLog方法移到这个类中,分别加上@Before和@After注解。

改造后,业务方法在TestService类中,而公共方法在LogAspect类中,是分离的。如果要新加一个业务方法,直接加就好,LogAspect类不用改任何代码,新加的业务方法就自动拥有打印日志的功能,是不是很神奇?

Spring aop的介绍和应用

spring aop其实是一种横切的思想,通过动态代理技术将公共代码织入到业务方法中。

这里出于5毛钱的友情,有必要温馨提醒一下。aop是一种思想,不是spring独有的,目前市面上比较出名的有:

  • aspectj

  • spring aop

  • jboss aop

我们现在主流的做法是将spring aop和aspectj结合使用,spring借鉴了AspectJ的切面,以提供注解驱动的AOP。

此时,一个黑影一闪而过。

刺头青D问:你说的“横切”,“动态代理”,“织入” 是什么东东?

几个重要的概念

根据上面spring aop的代码,用一张图聊聊几个重要的概念:

Spring aop的介绍和应用
  • 连接点(Joinpoint) 程序执行的某个特定位置,如某个方法调用前,调用后,方法抛出异常后,这些代码中的特定点称为连接点。

  • 切点(Pointcut) 每个程序的连接点有多个,如何定位到某个感兴趣的连接点,就需要通过切点来定位。

  • 通知(Advice) 增强是织入到目标类连接点上的一段程序代码。

  • 切面(Aspect)  切面由切点和通知组成,它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是将切面所定义的横切逻辑织入到切面所制定的连接点中。

  • 目标对象(Target) 需要被增强的业务对象

  • 代理类(Proxy) 一个类被AOP织入增强后,就产生了一个代理类。

  • 织入(Weaving) 织入就是将增强添加到对目标类具体连接点上的过程。

还是那个刺头青D说(旁边:这位仁兄比较好学):spring  aop概念弄明白了,挺简单的。@Pointcut注解的execution表达式刚刚看得我一脸懵逼,可以再说说吗,我请你吃饭?

切入点表达式

@Pointcut注解的execution切入点表达,看似简单,里面还是有些内容的。为了更直观一些,还是用张图来总结一下:

Spring aop的介绍和应用

该表达式的含义是:匹配访问权限是public,任意返回值,包名为:com.sue.cache.service,下面的所有类所有方法和所有参数类型。图中所有用*表示,比如图中类名用.*表示的是所有类。如果具体匹配某个类,比如:TestService,则表达式可以换成:

@Pointcut("execution(public * com.sue.cache.service.TestService.*(..))")

其实spring支持9种表达式,execution只是其中一种。

Spring aop的介绍和应用

有哪些入口?

先说说我为什么会问这样一个问题?

spring aop有哪些入口?说人话就是在问:spring中有哪些场景需要调用aop生成代理对象,难道你不好奇吗?

入口1

AbstractAutowireCapableBeanFactory类的createBean方法中,有这样一段代码:

Spring aop的介绍和应用

它通过BeanPostProcessor提供了一个生成代理对象的机会。具体逻辑在AbstractAutoProxyCreator类的postProcessBeforeInstantiation方法中:

Spring aop的介绍和应用

说白了,需要实现TargetSource才有可能会生成代理对象。该接口是对Target目标对象的封装,通过该接口可以获取到目标对象的实例。

不出意外,这时,又会冒出一个黑影。

刺头青F说:这里生成代理对象有什么用呢?

有时我们想自己控制bean的创建和初始化,而不需要通过spring容器,这时就可以通过实现TargetSource满足要求。只是创建单纯的实例还好,如果我们想使用代理该怎么办呢?这时候,入口1的作用就体现出来了。

入口2

AbstractAutowireCapableBeanFactory类的doCreateBean方法中,有这样一段代码:

Spring aop的介绍和应用

它主要作用是为了解决对象的循环依赖问题,核心思路是提前暴露singletonFactory到缓存中。

通过getEarlyBeanReference方法生成代理对象:

Spring aop的介绍和应用

它又会调用wrapifNecessary方法:

Spring aop的介绍和应用

这里有你想看到的生成代理的逻辑。

这时。。。。,你猜错了,黑影去吃饭了。。。

入口3

AbstractAutowireCapableBeanFactory类的initializeBean方法中,有这样一段代码:

Spring aop的介绍和应用

它会调用到AbstractAutoProxyCreator类postProcessAfterInitialization方法:

Spring aop的介绍和应用

该方法中能看到我们熟悉的面孔:wrapIfNecessary方法。从上面得知该方法里面包含了真正生成代理对象的逻辑。

这个入口,是为了给普通bean能够生成代理用的,是spring最常见并且使用最多的入口。

下面为了加深印象,用一张图总结一下:

Spring aop的介绍和应用

jdk动态代理 vs cglib

我猜你们对jdk动态代理和cglib是知道的(即使猜错了也不会少块肉?),但为了照顾一下新朋友,还是有必要把这两种生成代理的方式拿出来说说。

jdk动态代理

jdk动态代理是通过反射技术实现的,生成代理的代码如下:

public  interface IUser {     void add(); }  public  class User implements IUser{     @Override     public void add() {         System.out.println("===add===");     } }  public  class JdkProxy implements InvocationHandler {      private Object target;      public Object getProxy(Object target) {         this.target = target;         return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);     }      @Override     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {         before();         Object result = method.invoke(target,args);         after();         return result;     }      private void before() {         System.out.println("===before===");     }      private void after() {         System.out.println("===after===");     } }  public  class Test {     public static void main(String[] args) {         User user = new User();         JdkProxy jdkProxy = new JdkProxy();         IUser proxy = (IUser)jdkProxy.getProxy(user);         proxy.add();     } }

首先要定义一个接口IUser,然后定义接口实现类User,再定义类JdkProxy实现InvocationHandler接口,重写invoke方法,该方法中实现额外的逻辑。当然,别忘了在getProxy方法中,用Proxy.newProxyInstance方法创建一个代理对象。

jdk动态代理三个要素:

  • 定义一个接口

  • 实现InvocationHandler接口

  • 使用Proxy创建代理对象

cglib

cglib底层是通过asm字节码技术实现的,生成代理的代码如下:

public  class User {     public void add() {         System.out.println("===add===");     } }  public  class CglibProxy implements MethodInterceptor {      private Object target;      public Object getProxy(Object target) {         this.target = target;         Enhancer enhancer = new Enhancer();         enhancer.setSuperclass(target.getClass());         enhancer.setCallback(this);         return enhancer.create();     }      @Override     public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {         before();         Object result = method.invoke(target,objects);         after();         return result;     }      private void before() {         System.out.println("===before===");     }      private void after() {         System.out.println("===after===");     } }  public  class Test {     public static void main(String[] args) {         User user = new User();         CglibProxy cglibProxy = new CglibProxy();         IUser proxy = (IUser)cglibProxy.getProxy(user);         proxy.add();     } }

这里不需要定义接口,直接定义目标类User,然后实现MethodInterceptor接口,重写intercept方法,该方法中实现额外的逻辑。当然,别忘了在getProxy方法中,通过Enhancer创建代理对象。

cglib两个要素:

  • 实现MethodInterceptor接口

  • 使用Enhancer创建代理对象

spring中如何用的?

DefaultAopProxyFactory类的createAopProxy方法中,有这样一段代码:

Spring aop的介绍和应用

它里面包含:

  • JdkDynamicAopProxy jdk动态代理生成类

  • ObjenesisCglibAopProxy cglib代理生成类

JdkDynamicAopProxy类的invoke方法生成的代理对象。而ObjenesisCglibAopProxy类的父类:CglibAopProxy,它的getProxy方法生成的代理对象。

哪个更好?

我猜,不是刺头青,是你,可能会来自灵魂深处的一问:jdk动态代理和cglib哪个更好?

其实这个问题没有标准答案,要看具体的业务场景:

没有定义接口,只能使用cglib,不说它好不行。

定义了接口,需要创建单例或少量对象,调用多次时,可以使用jdk动态代理,因为它创建时更耗时,但调用时速度更快。

定义了接口,需要创建多个对象时,可以使用cglib,因为它创建速度更快。

  • 随着jdk版本不断迭代更新,jdk动态代理创建耗时不断被优化,8以上的版本中,跟cglib已经差不多。所以spring官方默认推荐使用jdk动态代理,因为它调用速度更快。

出于人道主义关怀,免费赠送一条有用经验:如果要强制使用cglib,可以通过以下两种方式:

  • spring.aop.proxy-target-class=true

  • @EnableAspectJAutoProxy(proxyTargetClass = true)

五种通知

spring默认提供了五种通知:

Spring aop的介绍和应用

按照国际惯例,不,按照我个人习惯,先看看他们是怎么用的。

前置通知

该通知在方法执行之前执行,只需在公共方法上加@Before注解,就能定义前置通知:

@Before("pointcut()") public void beforeLog(JoinPoint joinPoint) {     System.out.println("打印请求日志"); }

后置通知

该通知在方法执行之后执行,只需在公共方法上加@After注解,就能定义后置通知:

@After("pointcut()") public void afterLog(JoinPoint joinPoint) {     System.out.println("打印响应日志"); }

环绕通知

该通知在方法执行前后执行,只需在公共方法上加@Round注解,就能定义环绕通知:

@Around("pointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable {     System.out.println("打印请求日志");     Object result = joinPoint.proceed();     System.out.println("打印响应日志");     return result; }

结果通知

该通知在方法结束后执行,能够获取方法返回结果,只需在公共方法上加@AfterReturning注解,就能定义结果通知:

@AfterReturning(pointcut = "pointcut()",returning = "retVal") public void afterReturning(JoinPoint joinPoint, Object retVal) {     System.out.println("获取结果:"+retVal); }

异常通知

该通知在方法抛出异常之后执行,只需在公共方法上加@AfterThrowing注解,就能定义异常通知:

@AfterThrowing(pointcut = "pointcut()", throwing = "e") public void afterThrowing(JoinPoint joinPoint, Throwable e) {     System.out.println("异常:"+e); }

spring  aop给这五种通知,分别分配了一个xxxAdvice类。在ReflectiveAspectJAdvisorFactory类的getAdvice方法中可以看得到:

Spring aop的介绍和应用

下面用一张图总结一下对应关系:

Spring aop的介绍和应用

这五种xxxAdvice类都实现了Advice接口,但是有些差异。

下面三个xxxAdvice类实现了MethodInterceptor接口:

Spring aop的介绍和应用

而另外两个类:AspectJMethodBeforeAdvice 和 AspectJAfterReturningAdvice  没有实现上面的接口,这是为什么?

(这里留点悬念,后面的文章会揭晓谜题,敬请期待。)

一个猝不及防,依然是那个刺头青D,放下碗冲过来问了句:这五种通知的执行顺序是怎么样的?

单个切面正常情况

Spring aop的介绍和应用

单个切面异常情况

Spring aop的介绍和应用

多个切面正常情况

Spring aop的介绍和应用

多个切面异常情况

Spring aop的介绍和应用
  • 当有多有切面时,按照可以通过@Order(n)指定执行顺序,n值越小越先执行。

为什么使用链式调用?

这个问题没人问,是我自己想聊聊(旁白:因为我长得帅,有点自恋了)。

先看看spring是如何使用链式调用的,在ReflectiveMethodInvocation的proceed方法中,有这样一段代码:

Spring aop的介绍和应用

下面用一张图捋一捋上面的逻辑:

Spring aop的介绍和应用

图中包含了一个递归的链式调用,为什么要这样设计呢?

假如不这样设计,我们代码中是不是需要写很多if...else,根据不同的切面和通知单独处理?

而spring巧妙的使用责任链模式消除了原本需要大量的if...else判断,让代码的扩展性更好,很好的体现了开闭原则:对扩展开放,对修改关闭。

缓存中存的原始还是代理对象?

我们知道spring中为了性能考虑是有缓存的,通常说包含了三级缓存:

Spring aop的介绍和应用

说时迟那时快,刺头青D的兄弟,刺头青F忍不住赶过来问了句:缓存中存的原始还是代理对象?

我竟然被问得一时语塞,仔细捋了捋,要从三个方面回答:

singletonFactories(三级缓存)

AbstractAutowireCapableBeanFactory类的doCreateBean方法中,有这样一段代码:

Spring aop的介绍和应用

其实之前已经说过,它是为了解决循环依赖问题。这次要说的是addSingletonFactory方法:

Spring aop的介绍和应用

它里面保存的是singletonFactory对象,所以是原始对象。

earlySingletonObjects(二级缓存)

AbstractBeanFactory类的doGetBean方法中,有这样一段代码:

Spring aop的介绍和应用

在调用getBean方法获取bean实例时,会调用getSingleton尝试先从缓存中看能否获取到,如果能获取到则直接返回。

Spring aop的介绍和应用

这段代码会先从一级缓存中获取bean,如果没有再从二级缓存中获取,如果还是没有则从三级缓存中获取singletonFactory,通过getObject方法获取实例,将该实例放入到二级缓存中。

答案的谜底就聚焦在getObject方法中,而这个方法又是在哪来定义的呢?

其实就是上面的getEarlyBeanReference方法,我们知道这个方法生成的是代理对象,所以二级缓存中存的是代理对象。

singletonObjects(一级缓存)

DefaultSingletonBeanReGIStry类的getSingleton方法中,有这样一段代码:

Spring aop的介绍和应用

此时的bean创建、注入和初始化完成了,判断是如果新的单例对象,则会加入到一级缓存中,具体代码如下:

Spring aop的介绍和应用

出于一块钱的友谊,有必要温馨提醒一下:这里是DefaultSingletonBeanRegistry类的getSingleton方法,跟上面说的AbstractBeanFactory类getSingleton方法不一样。

几个常见的坑

我是一个乐于分享的人,虽说有时话比较少(旁边:属于人狠话不多的角色,别惹我)。为了表现我的share精神,给大家总结几个我之前使用spring  aop遇过的坑。

我们几乎每天都在用spring aop。

“什么?我怎么不知道?” 你可能会问。

如果你每天在用spring事务的话,就是每天在用spring aop,因为spring事务的底层就用到了spring aop。

坑1:直接方法调用

使用spring事务时,直接方法调用:

@Service public  class UserService {      @Autowired     private UserMapper userMapper;      public void add(UserModel userModel) {         userMapper.queryUser(userModel);         save(userModel);     }      @Transactional     public void save(UserModel userModel) {         System.out.println("保存数据");     } }

这种情况直接方法调用spring aop无法生成代理对象,事务会失效。这个问题的解决办法有很多:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. 使用TransactionTemplate手动开启事务

  3. 将事务方法save放到新加的类UserSaveService中,通过userSaveService.save调用事务方法。

  4. UserService类中@Autowired注入自己的实例userService,通过userService.save调用事务方法。

  5. 通过AopContext类获取代理对象:((UserService)AopContext.currentProxy()).save(user);

坑2:访问权限错误

@Service public  class UserService {     @Autowired     private UserService userService;     @Autowired     private UserMapper userMapper;      public void add(UserModel userModel) {         userMapper.queryUser(userModel);         userService.save(userModel);     }      @Transactional     private void save(UserModel userModel) {         System.out.println("保存数据");     } }

上面用 UserService类中@Autowired注入自己的实例userService的方式解决事务失效问题,如果不出意外的话,是可以的。

但是恰恰出现了意外,save方法被定义成了private的,这时也无法生成代理对象,事务同样会失效。

所以,我们应该拿个小本本记一下,目标方法一定不能定义成private的。

坑3:目标类用final修饰

@Service public  class UserService {     @Autowired     private UserService userService;     @Autowired     private UserMapper userMapper;      public void add(UserModel userModel) {         userMapper.queryUser(userModel);         userService.save(userModel);     }      @Transactional     public final void save(UserModel userModel) {         System.out.println("保存数据");     } }

这种情况spring aop生成代理对象,重写save方法时,发现的final的,重写不了,也会导致事务失效。

小本本需要再加一条,目标方法一定不能定义成final的。

坑4:循环依赖问题

在使用@Async注解开启异步功能的场景,它会通过AOP自动生成代理对象。

@Service public  class TestService1 {      @Autowired     private TestService2 testService2;      @Async     public void test1() {     } }  @Service public  class TestService2 {      @Autowired     private TestService1 testService1;      public void test2() {     } }

启动服务会报错:

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'testService1': Bean with name 'testService1' has been injected into other beans [testService2] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.

感谢各位的阅读,以上就是“Spring aop的介绍和应用”的内容了,经过本文的学习后,相信大家对Spring aop的介绍和应用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Spring aop的介绍和应用

本文链接: https://www.lsjlt.com/news/67192.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring aop的介绍和应用
    这篇文章主要讲解了“Spring aop的介绍和应用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring aop的介绍和应用”吧! 前言前几...
    99+
    2024-04-02
  • spring aop Pointcut execution规则介绍
    目录spring aop Pointcut execution规则切面注解@Pointcut(“execution()“)写法spring aop Pointcut executio...
    99+
    2024-04-02
  • Spring基础之AOP的概念介绍
    目录前言Spring的AOP的功能和目标代理方式@AspectJ的支持启用@AspectJ通过Java注解启用AspectJ注解支持:通过XML配置启用AspectJ注解定义一个切面...
    99+
    2024-04-02
  • JavaWeb中ServletContext的介绍和应用
    本篇内容主要讲解“JavaWeb中ServletContext的介绍和应用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaWeb中ServletContext的介绍和应用”吧!目录获取we...
    99+
    2023-06-20
  • Spring中的AOP编程怎么应用
    本文小编为大家详细介绍“Spring中的AOP编程怎么应用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Spring中的AOP编程怎么应用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。AOP 概述AOP 为 A...
    99+
    2023-07-05
  • Spring BOOT AOP基础应用教程
    目录面试课题 Spring boot AOPSpring boot 动态代理AOP 切面基本知识自定义注解自定义注解如何在AOP引用面试课题 Spring boot AOP Spri...
    99+
    2024-04-02
  • React组件的应用介绍
    目录1. 介绍2. 组件的创建方式2.1 函数创建组件2.2 类组件3. 父子组件传值3.1 函数组件3.2 类组件1. 介绍 组件允许你将 UI 拆分为独立可复用的代码片段,并对每...
    99+
    2024-04-02
  • Spring事务的详细介绍
    本篇内容介绍了“Spring事务的详细介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!前言Spring事务管理我相信大家都用得很多,但可能...
    99+
    2023-06-04
  • Spring中的bean概念介绍
    目录1 定义2 控制反转(IoC)2.1 私有属性保存依赖2.2 让Spring控制类构建过程2.3 这就是IoC3 Bean?Bean是Spring框架中最核心的两个概念之一(另一...
    99+
    2024-04-02
  • Spring的工作原理介绍
    本篇内容主要讲解“Spring的工作原理介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Spring的工作原理介绍”吧!spring原理内部最核心的就是IOC了,动态注入,让一个对象的创建不用...
    99+
    2023-05-30
    spring
  • PHP8简要介绍:新特性和应用
    PHP8的新特性和用途简介 近年来,PHP语言一直在持续发展和更新,为了满足不断变化的开发需求和提高效率,PHP8版本带来了一系列令人期待的新特性。本文将对PHP8的新特性进行简要介绍,并给出相应的代码示例,以帮助读者更好地了解...
    99+
    2024-01-13
  • Spring-Task定时任务的使用介绍
    目录一、基本使用二、@Scheduled属性详解1. cron2. zone3. fixedDelay4. fixedDelayString5. fixedRate6. fixedR...
    99+
    2022-11-13
    Spring Task定时任务使用 Spring Task 定时任务 Spring Task
  • Java的Spring AOP怎么用
    这篇文章主要介绍Java的Spring AOP怎么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!什么是AOP&作用AOP 为 Aspect Oriented Programming 的缩写,意思为...
    99+
    2023-06-29
  • spring的aop有什么用
    Spring的AOP(面向切面编程)提供了一种以非侵入的方式将横切关注点(例如日志记录、事务管理、安全性检查等)与业务逻辑代码进行分...
    99+
    2023-08-09
    spring aop
  • Python Ast介绍及应用
    Abstract Syntax Trees即抽象语法树。Ast是python源码到字节码的一种中间产物,借助ast模块可以从语法树的角度分析源码结构。此外,我们不仅可以修改和执行语法树,还可以将Source生成的语法树unparse成py...
    99+
    2023-01-30
    Python Ast
  • SpringCache框架应用介绍
    目录介绍常用注解实际测试介绍 Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。 Spring Cache提供了一层抽象,底层可...
    99+
    2024-04-02
  • LangChain:Prompt Templates介绍及应用
    ❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️ 👉有问题欢迎大家加关注私戳或者评论(包括但...
    99+
    2023-09-15
    人工智能 python 开发语言 chatgpt transformer
  • HTML5+CSS3的应用实例介绍
    本篇内容主要讲解“HTML5+CSS3的应用实例介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“HTML5+CSS3的应用实例介绍”吧!Web设计师可以使用H...
    99+
    2024-04-02
  • Golang函数的锁类型介绍和应用方法
    Golang 函数的锁类型介绍和应用方法Go 编程语言是一种高效、可扩展、并发安全的语言,而并发安全正是 Golang 的一大亮点。我们通常会在开发过程中使用锁来确保线程安全,Golang 的标准库提供了多种类型的锁,用于不同的场景。在本文...
    99+
    2023-05-18
    Golang 应用方法 函数锁
  • SVN介绍和使用
    文章目录 SVN的介绍SVN是什么作用 安装包下载SVN的使用检出提交显示日志更新 patch的使用创建使用 SVN的介绍 SVN是什么 SVN是subversion的缩写,是一个开放源代码的版本控制系统,通过采用分...
    99+
    2023-08-19
    svn
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作