Spring Aop及事务管理

news2024/11/29 4:51:40

5 Spring AOP

AOP概述

    AOP:全称是 Aspect Oriented Programming 即:面向切面编程。简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
    Aop的作用:在程序运行期间,不修改源码对已有方法进行增强。
    Aop优势:减少重复代码、提高开发效率、维护方便
    AOP的实现方式:使用动态代理技术

Spring AOP常用术语

Joinpoint( 连接点)

所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。即实际增强功能的方法

Pointcut( 切入点)

所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。一个类中所有的方法都可以是切入点,Spring Aop中切入点只能是方法。所以我么你可以把切入点理解成:目标对象里面所有的方法都称为切入点

Advice( 通知/ 增强)

Advice可以翻译成通知,也有人称为增强。所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。即我们要给目标方法实际提供的增强代码就是增强。

那么根据增强代码书写的位置不同,增强可以分为以下几类:

前置通知,后置通知,异常通知,最终通知,环绕通知。

Target( 目标对象)

 要被增强功能的对象就是目标对象。

Proxy(代理)

一个类被 AOP 织入增强后,就产生一个结果代理类。

Aspect( 切面)

Aspect称为切面。切面是切入点和增强的结合。通过代码会发现,增强功能所在的类称为切面类,里面配置的是增强和切入点的都是切面

案例:Spring AOP

  • pom.xml引入AOP的依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.2.25.RELEASE</version>
    </dependency>
    
  • 定义目标对象

    @Component
    public class Calculator {
        public int add(int num1,int num2){
            int sum = num1 + num2;
            return sum;
        }
        public int div(int num1,int num2){
            int sum = num1 / num2;
            return sum;
        }
    }
    
  • 定义切面类,增强功能所在的类称为切面类

    @Component
    @Aspect //切面
    public class LoggerAdvice {
        public void before(){
            System.out.println("xxx方法被调用了,传入的参数是:...");
        }
        public void after(){
            System.out.println("xxx方法执行完毕了,执行结果是:...");
        }
        public void afterThrowing(){
            System.out.println("xxx方法被执行出错了,出现的异常是:...");
        }
    }
    
  • 指定通知类型,通知就是指实际要增强的代码

    @Component
    @Aspect //切面
    public class LoggerAdvice {
        //指定增强代码实际织入位置:切入点代码执行前
        //    @Before(一个程序中有N个类,具体想给哪些类做增强) //定义切入点
        @Before("execution(* com.woniu.demo.Calculator.add(int,int))")
        public void before(){
            System.out.println("xxx方法被调用了,传入的参数是:...");
        }
    
        //指定增强代码实际织入位置:切入点代码执行后
        @AfterReturning("execution(* com.woniu.demo.Calculator.add(int,int))")
        public void after(){
            System.out.println("xxx方法执行完毕了,执行结果是:...");
        }
    
        //指定增强代码实际织入位置:切入点代码执行出错时
        @AfterThrowing("execution(* com.woniu.demo.Calculator.add(int,int))")
        public void afterThrowing(){
            System.out.println("xxx方法被执行出错了,出现的异常是:...");
        }
    }
    
  • 在Spring的配置类上开启spring aop的代理模式,并选择代理方式
    @Configuration //通知spring容器,这个类与别的类不一样,是一个配置类,用于初始化spring容器的一个类

    @ComponentScan(basePackages = {"com.woniu.dao","com.woniu.service","com.woniu.controller","com.woniu.target"}) 
    @EnableAspectJAutoProxy(proxyTargetClass = true) //开启aop代理 proxyTargetClass选择代码模式true:cglib false:jdk代理
    public class SpringConfig {
    }
    

    proxyTargetClass默认值是false,代表的是如果目标类是有接口的使用jdk的proxy代理,如果没有接口使用cglib;如果将proxyTargetClass设置为true,那么不管目标类是实现了接口,都会使用cglib进行代理。

  • 测试代理对象,观察增强功能是否增强成功

    //1.通知测试类,使用的spring的测试
    @RunWith(SpringJUnit4ClassRunner.class)  //通知测试类基于spring提供的单元测试
    //注解里面赋值,省略属性名,属性值赋值value,class指定配置类的字节码
    @ContextConfiguration(classes = SpringConfig.class)//指定测试时,基于哪个spring的配置文件测试
    public class MySpringTester {
        @Autowired
        private Calculator calculator; //最终注入时就是代理对象
        @Test //java的junit框架提供的注解
        public void test03(){
            //输出:class com.woniu.demo.Calculator$$EnhancerBySpringCGLIB$$d89ada67
            System.out.println(calculator.getClass());
            calculator.add(1,1);
        }
    }
    

    测试效果如下所示:
    在这里插入图片描述

在 spring 中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。

切入点表达式【会读会用】

语法:
execution( [权限修饰符] 返回值类型 包名.类名.方法名(参数列表) )
举例:
    execution(public int com.woniu.Calculator.div(int,int))
    简化
    execution(int com.woniu.Calculator.div(int,int))
提示:
    语法中出现[]包裹的内容都是可选的

常见的切入点案例

1. execution(public * *(..)) 所有的public的方法

2. execution(* com.spring.aop.*(..))所有的aop包下的所有类的方法(不包含子包) 

3. execution(* com.spring.aop..*(..))所有的aop包及其子包下的所有类的方法.
  切入点表达式:execution(* com.woniu..*(..))  *表示返回值类型、类名、方法名不限  (..)参数列表不限制

4. execution(* com.spring.aop.IOrderService.*(..))IOrderService接口中定义的所有方法

5. execution(* com.spring.aop.IOrderService+.*(..))匹配实现特定接口所有类的方法 IOrderService
 IOrderService+ 举例:IOrderService1 IOrderServiceImpl 不能匹配IOrderService   
 IOrderService* 举例:IOrderService1 IOrderServiceImpl 匹配IOrderService   

6. execution(* save*(..))去匹配所有以save开头的方法 save save1 save2

AOP增强分类

前置通知@Before

作用 用于配置前置通知。指定增强的方法在切入点方法之前执行
属性:
    method:用于指定通知类中的增强方法名称
    ponitcut-ref:用于指定切入点的表达式的引用
    poinitcut:用于指定切入点表达式
执行时间点: 切入点方法执行之前执行

后置通知@AfterReturning

作用:用于配置后置通知
属性:
    method:指定通知中方法的名称。
    pointct:定义切入点表达式
    pointcut-ref:指定切入点表达式的引用
执行时间点:切入点方法正常执行之后。它和异常通知只能有一个执行

异常通知@AfterThrowing

作用:用于配置异常通知,切入点方法发生异常时才执行
    
属性:
    method:指定通知中方法的名称。
    pointcut:定义切入点表达式
    pointcut-ref:指定切入点表达式的引用
执行时间点:切入点方法执行产生异常后执行。它和后置通知只能执行一个

注意:目标行为只有抛出了异常之后才会执行这个增强方法

最终通知@After

作用:用于配置最终通知
属性:
    method:指定通知中方法的名称。
    pointct:定义切入点表达式
    pointcut-ref:指定切入点表达式的引用
执行时间点: 无论切入点方法执行时是否有异常,它都会在其后面执行。

无论是否有异常,最终通知都会执行

案例1:利用前置、后置、异常和最终增强完成日志管理

  • 目标类

    @Component
    public class Calculator implements ICalculator{
        public int sum(int num1,int num2){
            System.out.println("......目标方法sum执行");
            int sum = num1 + num2;
            return sum;
        }
        public int sub(int num1,int num2){
            int result = num1 - num2;
            return result;
        }
        public int plus(int num1,int num2){
            int result = num1 * num2;
            return result;
        }
        public int div(int num1,int num2){
            int result = num1 / num2;
            return result;
        }
    }
    
  • 切面类

    @Aspect 
    @Component
    public class LoggerAdvance {
        //抽取公共切入点
        @Pointcut("execution(* com.woniu.target..*(..))")
        public void myPointCut(){}
        /**
         *
         * @param jp 连接点,AOP实际增强功能的哪个方法 不用程序员传值,spring aop赋值
         */
        //前置增强(切入点表达式)
        @Before("myPointCut()")
        public void before(JoinPoint jp){
            //方法签名
            Signature signature = jp.getSignature();
            String methodName = signature.getName();
            //实参列表
            Object[] args = jp.getArgs();
            System.out.println(methodName+"方法被调用了,用户传入的参数分别是:"+ Arrays.toString(args));
        }
        /**
         *
         * @param jp
         * @param result @AfterReturning后置增强,用来接收即将返回的值,程序员不管,spring aop注入
         */
        @AfterReturning(value = "myPointCut()",returning = "result")//returning属性作用将方法执行结果注入程序员指定的参数中
        public void afterReturning(JoinPoint jp, Object result){
            System.out.println(jp.getSignature().getName()+"方法执行完毕,执行结果是:"+result);
        }
    
        /**
         * 异常增强,切入点方法执行出错时,实现的增强
         * @param e  用来保存spring aop做异常增强时,实际发生的异常对象
         */
        @AfterThrowing(value = "myPointCut()",throwing = "e")
        public void afterThrowing(JoinPoint jp,Throwable e){
            System.out.println(jp.getSignature().getName()+"执行出错啦,出现的错误是:"+e);
        }
    
        /**
         * 最终增强,切入点方法执行过程不管有没有异常,始终会执行的代码 finally{}中的代码
         */
        @After("myPointCut()")
        public void after(){
            System.out.println("无论代码是否出错,你都可以看到这行输出语句 释放哪些资源");
        }
    }
    
  • 测试代码

    @Autowired
    private ICalculator proxy; //代理对象 JDK:代理类 implements ICalculator  CGLIB extends Calculator
    @Test
    public void mt02(){
        proxy.div(12,0);
    }
    

使用@Pointcut注解定义公用切入点

在每一个通知中定义切点,工作量大,不方便维护,我们可以使用@pointcut来声明切点

切点允许逻辑运算 例如mypointcut()||mypointcut1()

6 环绕增强

环绕通知@Around

环绕增强功能是spring aop五种增强里面最厉害!!使用最灵活!!

作用:环绕通知,它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
属性:method:指定通知中方法的名称。
     pointcut:定义切入点表达式
     pointcut-ref:指定切入点表达式的引用

注意:通常情况下,环绕通知都是独立使用的

案例:利用环绕增强完成日志管理

  • 目标类

    @Component
    public class Calculator implements ICalculator{
        public int sum(int num1,int num2){
            System.out.println("......目标方法sum执行");
            int sum = num1 + num2;
            return sum;
        }
        public int sub(int num1,int num2){
            int result = num1 - num2;
            return result;
        }
        public int plus(int num1,int num2){
            int result = num1 * num2;
            return result;
        }
        public int div(int num1,int num2){
            int result = num1 / num2;
            return result;
        }
    }
    
  • 切面类

    @Component
    @Aspect
    public class LoggerAdvicer {
        @Around("execution(* com.woniu.demo..*(..))")
        public Object around(ProceedingJoinPoint pjp){
            try {
                System.out.println(pjp.getSignature().getName()+"方法被调用了xxx传入的参数是:"+ Arrays.toString(pjp.getArgs()));
                //指定目标对象的方法正在执行
                Object result=pjp.proceed(pjp.getArgs());
                System.out.println(pjp.getSignature().getName()+"方法执行完毕了xxx执行结果是:"+result);
                return result;
            } catch (Throwable e) {
                System.out.println(pjp.getSignature().getName()+"方法被执行出错了xxx出现的异常是:"+e);
                throw new RuntimeException(e);
            } finally {
                System.out.println(pjp.getSignature().getName()+"方法不管有没有异常xxx都会执行的代码");
            }
        }
    }
    
  • 测试代码

    @Autowired
    private Calculator calculator; //最终注入时就是代理对象
    @Test //java的junit框架提供的注解
    public void test03(){
        System.out.println(calculator.getClass());
        calculator.add(1,0);//连接点
    }
    

运行测试代码,控制台输出add方法的日志增强代码:

经验分享:

Spring Aop应用的场景

日志记录,性能统计,安全控制,事务处理,异常处理等等。

利用AOP可以将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非主导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。

AOP与OOP区别

OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。

而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。

换而言之,OOD/OOP面向名词领域,AOP面向动词领域。

学习 spring中的aop要明确的事

	a 、开发阶段(我们做的):编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP 编程人员来做。在配置文件中,声明切入点与通知间的关系,即切面。:AOP 编程人员来做。

	b 、运行阶段(Spring  框架完成的):Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

7 spring AOP完成事务管理

引入案例:转账业务

需求:基于atm数据库的cardInfo表完成两个账户之间的转账业务

参考代码

  • CardInfoDao.java完成转账sql

    @Repository
    public class CardInfoDaoImpl implements CardInfoDao {
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Override
        public int updateIn(String cardId, BigDecimal inMoney) {
            return jdbcTemplate.update(
                    "UPDATE cardinfo SET balance=balance+? WHERE card_id=?",
                    inMoney,cardId
            );
        }
    
        @Override
        public int updateOut(String cardId, BigDecimal outMoney) {
            return jdbcTemplate.update(
                    "UPDATE cardinfo SET balance=balance-? WHERE card_id=?",
                    outMoney,cardId
            );
        }
    }
    
  • CardInfoService.java完成转账业务

    @Service
    public class CardInfoServiceImpl implements CardInfoService {
        @Autowired
        private CardInfoDao cardInfoDao;
    
        /**
         * @param outCardId 转出账户
         * @param inCardId 转入账户
         * @param money 交易金额
         */
        @Override
        public void transfer(String outCardId, String inCardId, BigDecimal money) {
            cardInfoDao.updateOut(outCardId,money);
            cardInfoDao.updateIn(inCardId,money);
        }
    }
    
  • 测试转账业务

    @RunWith(SpringJUnit4ClassRunner.class)  
    @ContextConfiguration(classes = SpringConfig.class)
    public class MySpringTester {
        @Autowired
        private CardInfoService cardInfoService;
        @Test
        public void query() {
            cardInfoService.transfer("2394916393","2416932602",new BigDecimal(100));
        }
    }
    

    运行代码,两个账户金额发生变化:账户“2394916393”金额更新为900,账户“2416932602”金额更新为1100,转账成功!!
    我们尝试将CardInfoDao的sql故意写错试一试:

     @Override
        public int updateIn(String cardId, BigDecimal inMoney) {
            return jdbcTemplate.update(
                //此处ST是故意写错的
                    "UPDATE cardinfo ST balance=balance+? WHERE card_id=?",
                    inMoney,cardId
            );
        }
    

    运行代码,两个账户金额依然发生变化:账户“2394916393”金额更新为800,账户“2416932602”金额却依然是1100,转账貌似有一个”成功了“,这种现象符合实际转账功能的需求么????当然不合理!!!转账是一定要保证:两个用户的钱同时变化的。所以转账业务有问题!怎么解决呢?依靠数据库的事务管理。

spring事务控制我们首先要认知到以下几个点:

第一:JavaEE 体系进行分层开发,事务处理位于业务层,Spring 提供了分层设计 业务层的事务处理解决方案。

第二:spring 框架为我们提供了一组事务控制的接口。具体在后面的第二小节介绍。这组接口是在spring-tx-xx.jar 中。

第三:spring 的事务控制都是基于 AOP 的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。

spring中事务管理机制依靠aop实现,那么完成事务管理也是遵循aop开发流程:首先我们需要定义事务管理的切面类,切面里面写什么代码呢?回忆之前自己管理事务,在核心业务代码基础上就是要提供事务提交、回滚相关的功能,

  • 事务切面类
    • commit
    • rollback
    • 。。。。

这个所谓的事务切面类,在spring中其实已经定义并提供了,称为事务管理器。

在转账案例中我们已经知道了spring中存在的事务问题,接下来我们使用aop技术让spring自动帮我们控制事务。

Spring 中事务控制的 API 介绍

  • PlatformTransactionManage:此接口是 spring 的事务管理器,它里面提供了我们常用的操作事务的方法,如下图:

因为PlatformTransactionManage是一个接口,并没有提供实际的方法实现。Spring为什么会抽取这样一个接口呢?有一个原因我们可以了解一下:

现下持久层框架众多,Spring没有办法提供一套事务的实现能够满足各大持久层框架的需求,比如MyBatis和Hibernate两大持久层框架,实现机制区别很大。所以spring的想法就是我把功能抽取出来,项目中结合自己实际使用的持久层来提供对应的代码实现:

案例:基于spring aop完成事务管理处理转账业务

分析:

我们现在的案例使用的持久层框架是spring内置的Spring-jdbc,所以事务切面类就应该根据上图指示,使用“DataSourceTransactionManager”。这个实现类spring-jdbc已经提供

我们要做的事情,就是让自己项目的spring容器可以扫描到这个事务管理类,但是因为这个类不是我们自己编写,无法直接添加@Component注解,只能在SpringConfig配置类中利用@Bean注入到spring容器中,详细代码如下所示:

  • pom.xml导入事务管理的依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.2.25.RELEASE</version>
    </dependency>
    
  • SpringConfig配置类:配置DataSourceTransactionManager事务管理器对象,利用@EnableTransactionManagement开启事务管理

    @ComponentScan(basePackages = {"com.woniu.dao","com.woniu.service","com.woniu.controller","com.woniu.target","com.woniu.advance"}) //spring不管理实体类entity
    @PropertySource("classpath:db.properties")
    //开启spring AOP代理 proxyTargetClass默认值是false,就是JDK true启用cglib
    @EnableAspectJAutoProxy(proxyTargetClass = true) //开启spring aop动态代理
    @EnableTransactionManagement(proxyTargetClass = true)  //开启spring事务管理
    @Import({JdbcConfig.class}) //导入其他的配置类
    public class SpringConfig {
        @Bean
        public JdbcTemplate jdbcTemplate(HikariDataSource dataSource){
            JdbcTemplate jdbcTemplate=new JdbcTemplate();
            jdbcTemplate.setDataSource(dataSource);
            return jdbcTemplate;
        }
    
        /**
         * 事务管理器,即利用spring AOP管理事务时的增强类
         * @param dataSource
         * @return
         */
        @Bean
        public DataSourceTransactionManager dataSourceTransactionManager(HikariDataSource dataSource){
            DataSourceTransactionManager dataSourceTransactionManager=new DataSourceTransactionManager();
            dataSourceTransactionManager.setDataSource(dataSource);
            return dataSourceTransactionManager;
        }
    }
    
  • 业务层哪个方法需要事务管理,添加spring提供事务注解@Transactional

    @Service
    public class CardInfoServiceImpl implements CardInfoService {
        @Autowired
        private CardInfoDao cardInfoDao;
        //注解:spring提供注解
        @Transactional
        @Override
        public void transfer(String inCardId, String outCardId, BigDecimal money) {
            cardInfoDao.updateOut(outCardId,money);
            cardInfoDao.updateIn(inCardId,money);
        }
    }
    

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

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

相关文章

CinemachineFreelook相机鬼畜抖动的解决方法

又是培训机构的出品。。。。。。 2020.3.27 发现跟随时抖动的原因了&#xff0c;其实应该按照传统相机的跟随逻辑放在late update里执行&#xff0c;但是由于开发cinemachine的开发组很坑地把cinemachine freelook里的三个轨道Damping值默认给了3&#xff0c;于是相机会以每0.7…

【Windows】DNG Converter(DNG格式转换器)软件介绍

软件介绍 DNG Converter是一款免费软件&#xff0c;用于将数码相机原始RAW图像文件转换为DNG格式&#xff08;数字负片&#xff09;文件。DNG格式是一种数字负片格式&#xff0c;它旨在成为一种行业标准&#xff0c;以便摄影师可以使用一个统一的格式来存储其相机拍摄的原始图…

探索高效存储与快速查找: 深入了解B树数据结构

探索高效存储与快速查找: 深入了解B树数据结构 一、什么是B树二、B树的实现2.1 节点的定义2.2 插入关键字2.3 删除关键字2.4 查找关键字2.5 遍历B树 一、什么是B树 B树&#xff0c;也称为B-tree&#xff0c;是一种多路平衡查找树。它被广泛用于文件系统和数据库之中&#xff0c…

SringBoot 如何使用HTTPS请求及Nginx配置Https

SringBoot 如何使用HTTPS请求及Nginx配置Https SringBoot 如何使用HTTPS请求生成证书导入证书及配制创建配置类将pfx转成.key和.pem Nginx 安装SSL依赖./configure 安装依赖编译安装完openssl后报了新错 Nginx配置 SringBoot 如何使用HTTPS请求 生成证书 由于业务数据在传输过…

Python保姆级教程 数据类型—新手小白入门必看

python学习资料&#xff0c;下方已打包好 一、基本数据类型与变量&#xff08;上&#xff09; 2.1 注释 优点&#xff1a; 代码说明 没注释的代码 有注释的代码 不让解释器执行注释的那句话 2.2 单行注释 单行注释快捷键&#xff1a;ctrl &#xff1f; 2.3多行注释 …

服务器如何有效解决源IP暴露问题

在现代互联网环境中&#xff0c;服务器的安全性至关重要。源IP暴露不仅增加了服务器遭受DDoS攻击、恶意扫描和数据泄露的风险&#xff0c;还可能影响业务的正常运行。本文将探讨如何利用技术手段&#xff0c;尤其是CDN和防火墙策略&#xff0c;来有效地解决服务器源IP暴露的问题…

redis+lua实现分布式限流

redislua实现分布式限流 文章目录 redislua实现分布式限流为什么使用redislua实现分布式限流使用ZSET也可以实现限流&#xff0c;为什么选择lua的方式实现依赖lua脚本yaml代码实现 Jmeter压测 为什么使用redislua实现分布式限流 原子性&#xff1a;通过Lua脚本执行限流逻辑&am…

融合心血管系统(CVS)多视角信号的新架构新策略

随着深度学习的发展和传感器的广泛采用&#xff0c;自动多视角融合&#xff08;MVF&#xff09;在心血管系统&#xff08;CVS&#xff09;信号处理方面取得了进展。然而&#xff0c;普遍的MVF模型架构通常将同一时间步骤但不同视角的CVS信号混合成统一的表示形式&#xff0c;忽…

RFID技术在农产品管理中的应用

使用RFID技术对农产品生产、加工、存储和销售的全过程进行跟踪&#xff0c;追溯食品的生产和加工过程&#xff0c;能够有效加强农产品的管理&#xff0c;如图7—10所示。 将RFID技术应用于农业食品安全&#xff0c;首先是建立完整、准确的食品供应链信息记录。借助RFID 对物体…

unity简单数字拼图小游戏(源码)

代码&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.SceneManagement;public class DragImage : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler {pub…

1_常见指令【Linux中常见30个指令的学习和使用】【万字长文】

常见指令以及权限理解 开始学习linux前的注意事项 在学习linux之前&#xff0c;我们要知道linux是一个操作系统。 那操作系统是什么呢&#xff1f;&#xff08;这里只做大概了解&#xff09; 操作系统就是一个管理软硬件的软件。 它对上提供良好&#xff08;稳定、高效、安…

大模型Prompt-Tuning技术入门

Prompt-Tuning方法 1 NLP任务四种范式 目前学术界一般将NLP任务的发展分为四个阶段&#xff0c;即NLP四范式&#xff1a; 第一范式&#xff1a;基于「传统机器学习模型」的范式&#xff0c;如TF-IDF特征朴素贝叶斯等机器算法&#xff1b;第二范式&#xff1a;基于「深度学习模…

Echarts图表: 矩形树图都有哪些配置项,一文告诉你

Hello&#xff0c;本期和大家分享矩形树图的配置项&#xff0c;欢迎评论区和贝格前端工场互动交流。 一、矩形树图是什么 矩形树图是ECharts中的一种图表类型&#xff0c;用于展示树形结构的数据。矩形树图通过矩形的大小和位置来表示树形结构中节点的层次关系和数据的大小。…

C端设计师去做B端界面设计易犯哪些?要不要给他提个醒。

2024-03-29 17:03大美B端工场 很多C端设计师初涉B端设计&#xff0c;思路转变不过来&#xff0c;还用C端思想指导B端设计&#xff0c;结果就是总感觉不舒服&#xff0c;大美B端工场&#xff0c;为大家详细解读一下。 当C端设计师去设计B端界面时&#xff0c;可能会经常犯以下…

【Spine学习08】之短飘,人物头发动效制作思路

上一节说完了跑步的&#xff0c; 这节说头发发型。 基础过程总结&#xff1a; 1.创建骨骼&#xff08;头发需要在上方加一个总骨骼&#xff09; 2.创建网格&#xff08;并绑定黄线&#xff09; 3.绑定权重&#xff08;发根位置的顶点赋予更多总骨骼的权重&#xff09; 4.切换到…

使用星鸾云GPU云服务器搭配Jupyter Lab,创建个人AI大模型

最近我们公司IT部门宣布了一个大事情&#xff0c;他们开发了一款内部用的大模型&#xff0c;叫作一号AI员工&#xff08;其实就是一个聊天机器人&#xff09;&#xff0c;这个一号员工可以回答所有关于公司财务、人事、制度、产品方面的问题。 我问了句&#xff1a;公司加班有…

【服务器硬件由 CPU、RAM、硬盘等组成,选购时需考虑应用需求、预算等。散热、安全、监控与维护亦重要,未来发展趋势包括高性能、低能耗和智能化。】

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

蚁剑webshell实验

GitHub - AntSwordProject/AwesomeScript: AntSword Shell 脚本分享/示例 命令行和文件管理 https 基本上请求一次响应一次就断开。

Opencv数一数有多少个水晶贴纸?

1.目标-数出有多少个贴纸 好久没更新博客了&#xff0c;最近家里小朋友在一张A3纸上贴了很多水晶贴纸&#xff0c;要让我帮他数有多少个&#xff0c;看上去有点多&#xff0c;贴的也比较随意&#xff0c;于是想着使用Opencv来识别一下有多少个。 原图如下&#xff1a; 代码…

如何应对pcdn的流量攻击?

面对PCDN的流量攻击&#xff0c;可以采取以下措施来应对&#xff1a; 一&#xff0e;配置防火墙&#xff1a; 1.禁止未授权的PCDN域名访问&#xff1a;根据网络需求&#xff0c;配置防火墙规则&#xff0c;只允许特定的PCDN域名进行访问&#xff0c;从而防止未经授权的PCDN节…