三,Spring AOP

news2025/1/21 0:48:17

Spring AOP

1 代理设计模式

1.1 解决的问题

在这里插入图片描述

Service层中除了核心代码(调用dao+逻辑判断)外,还有事务控制这种额外的增强功能。现在我们将核心业务代码和事务控制增强编码在一起直接定义在service层,日后还可能会新增其它的额外功能要求,比如:日志记录、性能分析。那么Service层就会变得特别臃肿,更致命的是添加新的增强功能,就要修改原有代码。

那么,到底要不要在Service中添加额外功能?

  • 软件设计者:不要,定义额外功能代码后会造成代码的频繁修改,不利于维护。

  • 功能调用方(Controller): 要,调用者需要使用到这些额外功能。

有没有同时调和2者矛盾的解决方案呢?答案就是代理设计模式。

1.2 代理模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pEL5E0zF-1673610277408)(Spring day03.assets/image-20210617091501403.png)]

生活中房东有房源,提供租房的核心功能,但是房东不愿意提供 广告、带看房 等功能,因为麻烦。而房客必须要使用 广告、随时看房 的功能。

矛盾的解决方案:中介

中介代理房东的出租方法,同时提供额外功能。租客不再和房东打交道,而是和中介打交道。这样不需要房东直接提供额外服务,而租客也能享受到租房该有的额外服务。

1.3 静态代理模式

Service和Controller的矛盾,也可以通过添加一个中介类(代理类)解决。代理类代理Service的原始方法,同时提供额外功能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jAyw7s9U-1673610277408)(Spring day03.assets/image-20210617093257583.png)]

通过代理类为原始类添加额外功能,好处:避免原始类因为额外功能而频繁修改,提高程序的可维护性。

示例:

接口:

public interface UserService {
    public boolean login(String username, String password);

    public void removeUser(Integer id);
}

原始类:

public class UserServiceImpl implements UserService {
    @Override
    public boolean login(String username, String password) {
        System.out.println("username = [" + username + "], password = [" + password + "]");
        System.out.println("登录成功");
        return false;
    }

    @Override
    public void removeUser(Integer id) {
        System.out.println("删除成功:id="+id);
    }

}

代理类:

public class UserServiceProxy implements UserService {
    private UserService service ;
    public UserServiceProxy(UserService service){
        this.service = service;
    }
    @Override
    public boolean login(String username, String password) {
        System.out.println("记录日志");


        return service.login(username,password);
    }

    @Override
    public void removeUser(Integer id) {
        System.out.println("记录日志");

        service.removeUser(id);
    }
}

Controller:

public class RemoveUserController extends HttpServlet {
   
  	public void service(HttpServletRequest req,HttpServletResponse resp){
        //收参
        String idStr = req.getParameter("id");
        Integer id = Integer.parseInt(idStr);
        
        //调用业务层
        UserService userService = new UserServiceProxy(new UserServiceImpl());
        userService.removeUser(id);
        
        //跳转
        ...
    }
   
}

名词(术语)解释:

  1. 原始类(目标类):提供核心功能的类
  2. 原始方法(目标方法):提供核心功能的方法,原始类中定义的方法
  3. 额外功能(增强处理):用于增强原始方法功能的代码

4个注意点:

  1. 代理类和原始类要实现相同接口
  2. 代理类提供额外功能
  3. 代理类中调用目标方法
  4. 调用者只和代理类打交道,不再和原始类型直接建立联系

2 Spring 动态代理【重点】

静态代理的问题:

  1. 随着额外功能的增多,代理类数量过多,不利于管理
  2. 代理类存在冗余,会出现多个代理类为不同的原始类提供同1个功能。

开发时:静态代理没有价值,不会使用。

解决方案:Spring的动态代理

Spring动态代理:代理类不需要程序员手动编码,由Spring框架动态生成增强功能的代理类。
好处:提高开发效率,降低额外功能的冗余。

2.1 开发步骤

准备工作:项目中导入spring-aop aspectjweaver

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
  1. 创建原始对象

    <bean id="userService" class="com.bz.service.impl.UserServiceImpl"/>
    
  2. 定义额外功能:定义增强类,实现Spring内置的接口

    public class MyBeforeAdvice implements MethodBeforeAdvice {
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("记录日志");
        }
    }
    
  3. 配置自定义的增强类

     <!-- 配置增强类:将额外功能交由Spring管理-->
    <bean id="beforeAdvice" class="com.bz.advice.MyBeforeAdvice"/>
    
  4. 定义切入点(pointcut):决定了额外功能的添加位置

  5. 组装

    <aop:config>
        <!-- 定义切入点:额外功能添加的位置 -->
        <aop:pointcut id="servicePointCut" expression="execution(* com.bz.service..*.*(..))"/>
        <!-- 组装 -->
        <aop:advisor advice-ref="beforeAdvice" pointcut-ref="servicePointCut"/>
    </aop:config>
    
  6. 此时,通过id:userService获取到就是有增强方法的对象。

2.2 实现的设计原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xuoy9HCt-1673610277409)(Spring day03.assets/image-20200401120411953.png)]

3 增强(advice)

Advice(通知、增强):为目标方法添加的额外功能。根据增强(额外功能)添加的位置可以分成:前置增强、后置增强、异常增强以及环绕增强。

3.1 前置增强

前置增强:增强是在目标方法前执行,实现MethodBeforeAdvice.

public class MyBeforeAdvice implements MethodBeforeAdvice {
    @Override
    /**
     * method: 原始方法(目标方法)
     * args:原始方法执行时实参列表
     * target:原始对象
     */
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("method = " + method);
        System.out.println("args = " + args);
        System.out.println("target = " + target);
        System.out.println("记录日志");
    }
}

3.2 后置增强

后置增强:增强在目标方法后执行,必须实现AfterReturningAdvice

public class MyAfterReturningAdvice implements AfterReturningAdvice {
    @Override
    /**
     * returnValue: 目标方法的返回值
     * method: 目标方法
     * args:调用目标方法的实参列表
     * target: 原始对象
     */
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("后置增强");
    }
    
}

3.3 异常增强

异常增强:增强在目标方法发生异常时执行,必须实现ThrowsAdvice。

注意:ThrowsAdvice是一个标记接口,实现的方法要从源码中copy

/* <p>Some examples of valid methods would be:
* <pre class="code">public void afterThrowing(Exception ex)</pre>
* <pre class="code">public void afterThrowing(RemoteException)</pre>
* <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, Exception ex)</pre>
* <pre class="code">public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)</pre>
*/
public class MyThrowsAdvice implements ThrowsAdvice {
    /**
     *
     * @param method 目标方法
     * @param args  目标方法调用时的实参列表
     * @param target 原始对象
     * @param ex 目标方法执行时的异常
     */
    public void afterThrowing(Method method, Object[] args, Object target, Exception ex){
        System.out.println("异常增强");
    }

}

3.4 环绕增强【重点】

环绕增强:在目标方法前、后以及发生异常时执行的增强,必须实现org.aopalliance.intercept.MethodInterceptor。

注意:接口所在的包。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7c8Nq2DJ-1673610277409)(Spring day03.assets/image-20210617095403812.png)]

public class MyMethodInterceptor implements MethodInterceptor {
    @Override
    /*
        MethodInvocation: 方法调用者
     */
    public Object invoke(MethodInvocation invocation) throws Throwable {

        System.out.println("前置增强");
        invocation.getMethod();//获取原始方法
        invocation.getArguments();//获取原始方法调用的实参列表
        invocation.getThis();//获取原始对象

        
        Object result = null;
        try {
            //放行流程,执行目标方法
            result = invocation.proceed();
            System.out.println("后置增强");
        }catch(Exception e){
            e.printStackTrace();
            System.out.println("异常增强");
        }finally {
            System.out.println("最终增强");
        }
        return result;
    }
}

使用环绕增强可以代替前置、后置以及异常增强。

4 切入点表达式

切入点(切点):需要添加额外功能(增强、增强处理)的方法的位置,通过pointcut标签定义切点。

4.1 execution表达式【重点】

execution表达式:通过表达式可以定义到方法级别。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1bnbgNQm-1673610277410)(Spring day03.assets/image-20200401152538740.png)]

实战:通常给service添加增强(额外功能)

<aop:pointcut id="servicePointCut" expression="execution(* com.bz.service..*.*(..))"/>

4.2 args表达式

args表达式:根据形参列表进行匹配.

args(参数表达式)
具体语法细节同execution表达式参数部分一样。

<aop:pointcut id="servicePointCut" expression="args(..)"/>

4.3 within表达式

within表达式:根据全类名进行匹配

语法细节和execution表达式包名和类名部分相同,注意使用within,必须要精确到实现类。

<aop:pointcut id="servicePointCut" expression="within(com.bz.service.impl.*)"/>

4.4 @annotation表达式

@annotation(注解全类名):匹配所有使用特定注解描述的方法。

  1. 自定义注解

    //注解是特殊的接口
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    public @interface MyAnnotation {
    //    public String name(); 注解中属性和方法是一体的
    }
    
  2. 使用注解描述方法,注意:方法不能是抽象方法

    public class UserServiceImpl implements UserService {
        @Override
        @MyAnnotation
        public boolean login(String username, String password) {
            System.out.println("username = [" + username + "], password = [" + password + "]");
            System.out.println("登录成功");
            return false;
        }
        @MyAnnotation
        @Override
        public void removeUser(Integer id) {
            System.out.println("删除成功:id="+id);
            int i = 10/0;
        }
    
    }
    
  3. @annotation(注解全类名)

    <aop:pointcut id="servicePointCut" expression="@annotation(com.bz.annotation.MyAnnotation)"/>
    

4.5 表达式的运算符

切点表达式之间可以进行运算,&&(and) ||(or) !(not)

&& (and)求交集

|| (or)求并集

! (not)取反

由于&在xml有特殊含义,建议使用相同作用的关键字and

 <aop:pointcut id="servicePointcut" expression="@annotation(com.bz.annotation.MyAnnotation) and  args(java.lang.Integer,..)"/>

<aop:pointcut id="servicePointcut" expression="!args(java.lang.Integer,..)"/>

5 Spring的AOP【重点】

AOP(Aspect Oriented Programming)面向切面编程。
OOP(Object Oriented Programming)面向对象编程。

AOP:解决共性功能的抽取以及重用,配合OOP更好的完成编程。

5.1 OOP下共性功能的抽取重用

OOP以对象为基本编程对象,通过对象间的协调、配合完成功能。面向对象中,通过继承抽取共性以及重用共性功能。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pLBRUKMe-1673610277410)(Spring day03.assets/image-20200401161108245.png)]

5.2 Spring AOP

AOP的基础概念:

  1. 增强(增强):共性的额外功能,比如:日志、事务、性能分析
  2. 切入点(切点):添加额外功能的位置
  3. 织入(编织):将增强(增强)添加到切点的过程
  4. 切面:增强在切点位置置入后,形成的一个几何概念

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ei2Xen8x-1673610277410)(Spring day03.assets/image-20200401162517975.png)]

AOP面向切面编程:

以横切的思想,在程序运行过程中动态的将额外功能添加到切点处。好处:灵活、强大、不需要修改原始的目标类。
AOP是在OOP基础上完成,对OOP的补充。

Spring AOP开发步骤:

  1. 配置原始对象
  2. 编码:定义增强类
  3. 配置增强类
  4. 定义切入点
  5. 组装切面

Spring AOP的应用场景:

  1. 在不修改源码的基础上,动态的添加功能
  2. service层:日志、事务、性能监控

6 Spring中的事务控制

事务:用来保证业务操作完整性的一种数据库机制。
添加位置:在业务层中进行事务控制,业务层中一个业务方法表示一个完成的功能。

6.1 事务复习

JDBC中事务控制:

conn.setAutoCommit(false);
  业务逻辑+调用dao
conn.commmit();//成功
conn.rollback();//失败

MyBaits中事务控制:

//mybatis默认禁用自动提交
  业务逻辑+调用dao
sqlSession.commit();//成功
sqlSession.rollback();//失败

6.2 Spring事务控制

Spring提供了2种事务控制方式:

  1. 编程式事务控制:在代码中定义事务控制的代码,不常用。
  2. 声明式事务控制:借助Spring AOP实现,将事务控制的代码定义成增强(增强);通过切入点将增强编织到service方法中。

Spring AOP方式事务控制的思路:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zQbpeaBR-1673610277410)(Spring day03.assets/image-20210617125915405.png)]

添加依赖:

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

Spring AOP方式事务控制的步骤:

  1. 定义原始对象

    <!-- 定义service对象-->
    <bean id="userService" class="com.bz.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
    </bean>
    
  2. 定义增强类(事务控制)

    Spring内置:DataSourceTransactionManager

  3. 配置DataSourceTransactionManager增强类

    <!-- 配置事务管理器-->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="druidDataSource"/>
    </bean>
    <!-- 配置事务增强(增强)-->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- 进一步配置方法的事务控制细节 -->
        <tx:attributes>
            <!-- 所有show开头的方法添加只读的事务 -->
            <tx:method name="show*" read-only="true"/>
            <!-- show开头的方法外的其他所有方法开启事务 -->
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    

    注意:tx:advice是http://www.springframework.org/schema/tx定义的标签。

  4. 定义切点

  5. 编织切面

    <aop:config>
        <aop:pointcut id="servicePointcut" expression="execution(* com.bz.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>
    </aop:config>
    

7 总结:SM项目开发步骤

  1. 搭建开发环境

    1. 新建web项目(补全项目结构)

    2. 导入依赖,pom.xml引入依赖

      数据库依赖:

      mysql-connector-java.jar

      druid

      spring依赖:

      spring-context

      aspectjweaver

      mybatis依赖:

      mybatis

      slf4j-log4j12

      mybatis和spring整合

      spring-jdbc

      mybatis-spring

      servlet+jsp+jstl依赖

      servlet-api

      jsp-api

      jstl

      springmvc依赖

      spring-webmvc

      hutool工具

      hutool-all

    3. 配置文件和工具类

      jdbc.properties

      lo4j.properties

      mybatis-config.xml (不再需要)

      xxxMapper.xml

      web.xml

      applicationContext.xml

      MyBatisUtils.java (不再需要)

    4. 配置文件初始化

      web.xml中配置Spring监听器,创建Spring工厂

  2. 建表

  3. 实体

  4. dao

    1. 接口
    2. 实现: mapper.xml中定义sql语句
  5. service

    1. 接口
    2. 实现:不再编程式的管理事务
  6. test

  7. Controller+jsp

  8. 集成测试

pom.xml

<!-- jdbc依赖-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>

<!-- 阿里巴巴连接池依赖 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.0.24</version>
</dependency>

<!--引入Spring依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

<!-- mybatis依赖-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.4</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.30</version>
</dependency>

<!-- spring 整合 mybatis 依赖-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.2.8.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.4</version>
</dependency>

<!-- servlet jsp jstl 依赖-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.3</version>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>


<!-- SpringMVC依赖 -->
 <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>


<!--
       hutool工具类
    -->
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.2.3</version>
</dependency>

<!-- junit测试依赖-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
    <version>4.12</version>
</dependency>

web.xml

<!-- 配置spring配置文件的路径-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 监听器:监听web应用启动,根据上面配置的spring配置文件路径创建Spring工厂-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

applicationContext.xml

<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 创建连接池 DataSource -->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <!-- 必须的配置 -->
    <property name="url" value="${url}"/>
    <property name="driverClassName" value="${driverClassName}"/>
    <property name="username" value="${user}"/>
    <property name="password" value="${password}"/>
    <!-- 额外的配置-->
</bean>

<!-- 定义SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

    <property name="dataSource" ref="druidDataSource"/>
    <!--
            配置实体类的包名,自动为实体配置短类名的别名
         -->
    <property name="typeAliasesPackage" value="com.bz.entity"/>
    <property name="mapperLocations">
        <!-- 配置mapper.xml的路径-->
        <list>                
            <value>classpath:com/bz/mapper/*Mapper.xml</value>
        </list>
    </property>
</bean>
<!--
        自动创建Mapper实现类对象
        自动扫描basePackage包下的Mapper接口,自动创建Mapper接口的实现类对象

    -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!--
            mapper实现类对象的id规则:接口名首字母小写
            UserMapper  ==> userMapper
            BookMapper ==> bookMapper
        -->
    <property name="basePackage" value="com.bz.mapper"/>
</bean>

<!-- 定义service对象-->
<bean id="userService" class="com.bz.service.impl.UserServiceImpl">
    <property name="userMapper" ref="userMapper"/>
</bean>

<!-- 配置事务管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="druidDataSource"/>
</bean>
<!-- 配置事务增强-->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <!-- 所有show开头的方法添加只读的事务 -->
        <tx:method name="show*" read-only="true"/>
        <!-- show开头的方法外的其他所有方法开启事务 -->
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="servicePointcut" expression="execution(* com.bz.service.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>
</aop:config>

源代码地址如下:https://download.csdn.net/download/qq_36827283/87383453

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/161252.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker安装与基本介绍使用

Docker 一、初识Docker 1、安装Docker # 1.yum包更新到最新 yum update # 2.安装需要的软件包&#xff0c;yum-util提供的yum-config-manager&#xff0c;例外两个是devicemapper驱动依赖的 yum install -y yum-utils device-mapper-persistent-data lvm2 # 3.设置yum源 yum…

hololens2开发环境配置,游戏引擎的全流程安装部署

要进行hololens 2的项目开发&#xff0c;进行基础环境搭建和软件安装部署的记录。 软件安装 UE ue2.6x(安装hololens平台)openxr插件&#xff0c;ux插件&#xff08;可选&#xff09; unity3d unity3d 2020&#xff08;unity3d 2021在打包时&#xff0c;在universal windo…

预测2023:智算中心将人工智能产业推上发展的“拐点”?

文|智能相对论作者|沈浪回顾过去的2022年&#xff0c;人工智能产业继续在巨变中迎来突破性成长。一方面&#xff0c;人工智能产业相关的应用越来越丰富、创新&#xff0c;比如元宇宙的出现和走红&#xff0c;为市场创造的一个全新的业态&#xff0c;也为用户带来了诸多新奇的体…

RabbitMQ 部署及配置详解

一、RabbitMQ 核心概念1. 生产者和消费者Producer: 消息的生产者,用于发布消息&#xff1b;Consumer: 消息的消费者&#xff0c;用于从队列中获取消息.消费者只需关注队列即可&#xff0c;不需要关注交换机和路由键。消费者可以通过basicConsume(订阅模式可以从队列中一直持续的…

【PCB专题】案例:PCB设计失误导致无法正常贴片

案例情况说明 本案例是新人画PCB的时候遇到的,但是遇到的时间已经比较晚了,在生产的时候报的异常。一部分原因也是前期我没有审查出来这个问题。 要生产的时候,工厂报了异常。新人转给我看的时候,我才发现PCB上是没有设计MARK点。这将导致SMT时没有Mark点对位,需要看看有没…

一篇搞定JS的位运算(公式+力扣真题)--- 持续更新

摘要 位操作&#xff08;Bit Manipulation&#xff09;是程序设计中对位模式或二进制数的一元和二元操作。在许多古老的微处理器上&#xff0c;位运算比加减运算略快&#xff0c;通常位运算比乘除法运算要快很多。在现代编程语言中&#xff0c;情况并非如此&#xff0c;很多编程…

Java项目:酒店管理系统(java+SSM+jsp+mysql+maven)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 主要技术:java springmvc mybatis mysql tomcat js jauery jsp log4j等一些常见基本技术适用于Java毕设和学习使用 主要实现&#xff1a; 前台&#xff1a;登录、注册、酒店信息浏览、搜索酒店信息、查看房…

游戏开发 帧同步

帧同步技术是一个古老的技术&#xff0c;没有特别固定的招式&#xff0c;优化方向也是根据实际情况各有不同&#xff0c;但是其核心思想都是一样的。1.为什么需要帧同步技术帧同步主要是为了保证某些类型的游戏在同步时&#xff0c;可以保证很好的游戏体验。游戏类型通常包括&a…

无线wifi的参数即含义

WiFi属性信息 参考&#xff1a;WiFi发展史&#xff1a;https://zhuanlan.zhihu.com/p/74348591&#xff0c;WiFi2.4和5G简述&#xff1a;https://zhuanlan.zhihu.com/p/344652613 下面图中的WiFi4和WiFi5是根据协议的另一个名字。&#xff08;图片来自参考链接&#xff09; …

vue3 antd项目实战——Modal弹窗自定义遮罩 (利用maskStyle属性自定义遮罩样式)

vue3 antd项目实战——Modal弹窗自定义遮罩 maskStyle知识回调场景复现关于mask遮罩的API属性利用maskStyle属性自定义遮罩样式知识回调 文章内容文章链接vue3 antd ts实战——ant-design-vue组件库引入https://blog.csdn.net/XSL_HR/article/details/127396384?spm1001.2014…

随手查——Multisim

关于电路仿真软件Multisim的一些记录&#xff0c;基于Multisim14.0。 Multisim1、Multisim中元器件的颜色2、快速创建一个放大器电路3、如何进行参数扫描&#x1f680;参数扫描数据点导出为Excel&#x1f680;退出参数扫描模式4、交流分析1、Multisim中元器件的颜色 Multisim中…

YOLOV8 | 最先进的 YOLO 模型训练自己的数据集(持续更新中)

本文实现了俩种环境的设置&#xff0c;一种是windows的CPU版本&#xff0c;还有服务器上的GPU版本。CPU版本仅用来实现检测&#xff0c;而GPU版本用来训练自己的数据集&#xff01;&#xff08;选择其中一个环境运行后&#xff0c;训练自己的数据集&#xff09;1.环境1&#xf…

C#,图像二值化(22)——局部阈值的伯恩森算法(Bernsen Thresholding)及源程序

1、局部阈值的伯恩森算法&#xff08;Bernsen Thresholding&#xff09;Bernsen方法是为图像分割开发的局部自适应二值化方法之一。在这项研究中&#xff0c;实现了Bernsen的局部自适应二值化方法&#xff0c;并对不同灰度图像进行了测试。Bernsen’s method is one of locally…

04_FreeRTOS任务挂起和恢复函数

目录 任务的挂起与恢复的API函数 任务挂起函数介绍 任务恢复函数介绍 中断中恢复函数 vTaskSuspend()任务挂起函数 vTaskResume()任务中恢复函数 xTaskResumeFromISR()中断中恢复函数 任务的挂起与恢复的API函数 挂起:挂起任务类似暂停,可恢复;删除任务,无法恢复,类似“…

公务员行测常识积累(持续更新中)

公务员行测常识积累政治天文地理人文戏曲历史经济物理生物医学政治 区域协调发展战略&#xff1a;以城市群为主体构建大中小城市和小城镇协调发展的城镇格局&#xff1b;以疏解北京非首都功能为“牛鼻子”推动京津冀协同发展&#xff1b;以共抓大保护、不搞大开发为导向推动长…

个人建议【建议】

以下只是个人的一些看法 本文已在CSDN博客中发布文章 本文已在CSDN建议社区中发布帖子 重点内容已经被蓝色字体标志出来了&#xff0c;希望能对建设优秀的CSDN有所启发 快速浏览看总结 中心思想看最后 1.我的专栏上限问题还没解决 在2022-10-24 20:33:41就发出了这个问题&…

如何突破以往模式的束缚,如何让互联网行业重新开启新的想象空间

在流量和资本的红利已然被出清的大背景下&#xff0c;以平台经济为代表的互联网经济的发展同样被逼退到了进退维谷的境地里。如何突破以往发展模式的束缚&#xff0c;如何让互联网行业的发展重新开启新的想象空间&#xff0c;成为每一个互联网玩家必然需要思考的重要课题。于是…

Java基础学习笔记(十五)—— Sream流

Sream流1 Stream流初体验2 Stream流概述3 生成Stream流4 中间操作方法5 终结操作方法6 收集操作方法7 Stream流案例1 Stream流初体验 案例需求 创建一个集合&#xff0c;存储多个字符串元素把集合中所有以“张”开头的元素存储到一个新的集合把"张"开头的集合中的长…

SpringCloud高级应用-2(Gateway-01)

Gateway介绍&#xff1a; Spring Cloud Gateway 是Spring Cloud团队的一个全新项目&#xff0c;基于Spring 5.0、SpringBoot2.0、Project Reactor 等技术开发的网关。旨在为微服务架构提供一种简单有效统一的API路由管理方式。 Spring Cloud Gateway 作为SpringCloud生态系统…

Acwing---1214.波动数列

波动数列1.题目2.基本思想3.代码实现1.题目 观察这个数列&#xff1a; 1 3 0 2 -1 1 -2 … 这个数列中后一项总是比前一项增加2或者减少3&#xff0c;且每一项都为整数。 栋栋对这种数列很好奇&#xff0c;他想知道长度为 n 和为 s 而且后一项总是比前一项增加 a 或者减少 …