学习springAOP

第三章 Spring AOP

第一节 AOP 简介

1. 概念

AOP全称为Aspect Oriented Programming,表示面向切面编程。何为切面呢?

由此可以得出,切面是一种将那些与业务无关,但业务模块都需要使用的功能封装起来的技术。这样便于减少系统的重复代码,降低模块之间的耦合度。

2. AOP 基本术语

  • 连接点( Joinpoint ):

    连接点就是被拦截到的程序执行点,因为Spring只支持方法类型的连接点,所以在Spring中连接点就是被拦截到的方法。连接点由两个信息确定:

    • 方法( 表示程序执行点,即在哪个目标方法)
    • 相对点(表示方位,即目标方法的什么位置,比如调用前,后等)
  • 切入点(Pointcut):

    切入点是对连接点进行拦截的条件定义。切入点表达式如何和连接点匹配是AOP的核心,Spring缺省使用AspectJ切入点语法。 一般认为,所有的方法都可以认为是连接点,但是我们并不希望在所有的方法上都添加通知,而切入点的作用就是提供一组规则来匹配连接点,给满足规则的连接点添加通知。

  • 通知、增强(Advice):

    可以为切入点添加额外功能,分为:前置通知、后置通知、异常通知、环绕通知、最终通知等。

  • 目标对象(Target):

    目标对象指将要被增强的对象,即包含主业务逻辑的类对象。或者说是被一个或者多个切面所通知的对象。

  • 织入(Weaving):

    织入是将切面和业务逻辑对象连接起来, 并创建通知代理的过程。织入可以在编译时,类加载时和运行时完成。在编译时进行织入就是静态代理,而在运行时进行织入则是动态代理

  • 代理(Proxy):

    被AOP织入通知后,产生的结果类。

  • 切面(Aspect):

    切面是一个横切关注点的模块化,一个切面能够包含同一个类型的不同增强方法,比如说事务处理和日志处理可以理解为两个切面。切面由切入点和通知组成,它既包含了横切逻辑的定义,也包括了切入点的定义。 Spring AOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。

第二节 AOP 应用

AOP应用场景有许多,最典型的应用场景就是日志和事务。这里以事务实现为例进行讲解。

<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.11</version>
</dependency>
<!-- 切面相关的包 -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.9</version>
</dependency>

1. 编写业务层

public interface UserService {int saveUser(Map<String,Object> params);
}public class UserServiceImpl implements UserService {@Overridepublic int saveUser(Map<String, Object> params) {System.out.println("保存用户信息" + params);return 0;}
}

2. 配置业务层

AOP 功能的实现是基于 IOC 的,因此,业务层对象应该纳入 IOC 容器来管理。

<?xml version="1.0" encoding="UTF-8"?>
<!-- xmlns = xml namespace-->
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 业务层对象--><bean id="userService" class="com.qf.spring.aop.service.impl.UserServiceImpl" />
</beans>

3. 编写通知类

通知分为前置通知、后置通知、异常抛出通知、环绕通知、最终通知五种。首先实现前置通知。

前置通知接口

public interface MethodBeforeAdvice extends BeforeAdvice {/*** Callback before a given method is invoked.*/void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
public class BeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("准备执行方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args));}
}

4. 配置通知

通知的实现也是基于 IOC 容器的,因此需要将通知对象纳入 IOC 容器管理。

<?xml version="1.0" encoding="UTF-8"?>
<!-- xmlns = xml namespace-->
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 业务层对象--><bean id="userService" class="com.qf.spring.aop.service.impl.UserServiceImpl" /><!--配置通知对象--><bean id="before" class="com.qf.spring.aop.advice.BeforeAdvice" />
</beans>

5. AOP 配置

当通知对象和业务层对象都纳入 IOC 容器管理之后,需要将通知对象作用在业务层对象上。Spring 提供了 aop 标签来完成这一功能。

<aop:config><!--pointcut表示切点,也就是通知会在哪些位置触发expression表示切点表达式,切点表达式必须是execution(), execution()方法中的参数必须配置到方法上比如 * com.qf.spring.aop.service..*(..)第一个 * 表示任意访问修饰符com.qf.spring.aop.service.. 最后的两个..表示service包下面的所有子包中的类*(..) 表示任意方法, 如果()中没有..,则表示不带参数的方法;有,就表示带任意参数--><aop:pointcut id="切点ID" expression="切点表达式"/><aop:advisor advice-ref="通知ID" pointcut-ref="切点ID" />
</aop:config>

要使用 aop 标签,必须要在 beans 标签上添加 aop 命名空间

xmlns:aop="http://www.springframework.org/schema/aop"

然后在 xsi:schemaLocation 属性值中添加 aop 命名空间和约束文档

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
<aop:config><aop:pointcut id="pc" expression="execution(* com.qf.spring.aop.service..*(..))"/><aop:advisor advice-ref="before" pointcut-ref="pc" />
</aop:config>

6. 测试

public class AopTest {@Testpublic void saveUserTest(){ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean("userService", UserService.class);Map<String,Object> params = new HashMap<>();params.put("name", "刘德华");params.put("sex", "男");userService.saveUser(params);}
}

7. 后置通知

后置通知接口

public interface AfterReturningAdvice extends AfterAdvice {/*** Callback after a given method successfully returned.*/void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
public class AfterAdvice implements AfterReturningAdvice {@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("执行完方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",得到返回值:" + returnValue);}
}
<bean id="after" class="com.qf.spring.aop.advice.AfterAdvice" />
<aop:config><!--pointcut表示切点,也就是通知会在哪些位置触发expression表示切点表达式,切点表达式必须是execution(), execution()方法中的参数必须配置到方法上比如 * com.qf.spring.aop.service..*(..)第一个 * 表示任意访问修饰符com.qf.spring.aop.service.. 最后的两个..表示service包下面的所有子包中的类*(..) 表示任意方法, 如果()中没有..,则表示不带参数的方法;有,就表示带任意参数--><aop:pointcut id="pc" expression="execution(* com.qf.spring.aop.service..*(..))"/><aop:advisor advice-ref="before" pointcut-ref="pc" /><aop:advisor advice-ref="after" pointcut-ref="pc" />
</aop:config>

8. 异常抛出通知

异常抛出通知接口

/*** There are not any methods on this interface, as methods are invoked by* reflection. Implementing classes must implement methods of the form:* void afterThrowing([Method, args, target], ThrowableSubclass);* public void afterThrowing(Exception ex)</pre>* public void afterThrowing(RemoteException)</pre>* public void afterThrowing(Method method, Object[] args, Object target, Exception ex)* public void afterThrowing(Method method, Object[] args, Object target, ServletException ex)*/
public interface ThrowsAdvice extends AfterAdvice {
}
public class ExceptionAdvice implements ThrowsAdvice {public void afterThrowing(Method method, Object[] args, Object target, Exception ex){String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("执行方法时:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",发生了异常:" + ex.getMessage());}
}public class UserServiceImpl implements UserService {@Overridepublic int saveUser(Map<String, Object> params) {System.out.println("保存用户信息" + params);throw new RuntimeException("异常抛出演示");}
}
<bean id="exception" class="com.qf.spring.aop.advice.ExceptionAdvice" />
<aop:config><!--pointcut表示切点,也就是通知会在哪些位置触发expression表示切点表达式,切点表达式必须是execution(), execution()方法中的参数必须配置到方法上比如 * com.qf.spring.aop.service..*(..)第一个 * 表示任意访问修饰符com.qf.spring.aop.service.. 最后的两个..表示service包下面的所有子包中的类*(..) 表示任意方法, 如果()中没有..,则表示不带参数的方法;有,就表示带任意参数--><aop:pointcut id="pc" expression="execution(* com.qf.spring.aop.service..*(..))"/><aop:advisor advice-ref="before" pointcut-ref="pc" /><aop:advisor advice-ref="after" pointcut-ref="pc" /><aop:advisor advice-ref="exception" pointcut-ref="pc" />
</aop:config>

9. 环绕通知

环绕通知接口

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {/*** Implement this method to perform extra treatments before and* after the invocation.*/@NullableObject invoke(@Nonnull MethodInvocation invocation) throws Throwable;
}
public class AroundAdvice implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {Method method = invocation.getMethod(); //获取被拦截的方法对象Object[] args = invocation.getArguments();//获取方法的参数Object target = invocation.getThis(); //获取代理对象String methodName = method.getName();String className = method.getDeclaringClass().getName();try {System.out.println("准备执行方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args));Object returnValue = method.invoke(target, args);System.out.println("执行完方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",得到返回值:" + returnValue);return returnValue;} catch (Throwable t){System.out.println("执行方法时:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",发生了异常:" + t.getMessage());throw t;}}
}
<!--配置通知对象-->
<!--  <bean id="before" class="com.qf.spring.aop.advice.BeforeAdvice" /><bean id="after" class="com.qf.spring.aop.advice.AfterAdvice" /><bean id="exception" class="com.qf.spring.aop.advice.ExceptionAdvice" />-->
<bean id="around" class="com.qf.spring.aop.advice.AroundAdvice" />
<aop:config><!--pointcut表示切点,也就是通知会在哪些位置触发expression表示切点表达式,切点表达式必须是execution(), execution()方法中的参数必须配置到方法上比如 * com.qf.spring.aop.service..*(..)第一个 * 表示任意访问修饰符com.qf.spring.aop.service.. 最后的两个..表示service包下面的所有子包中的类*(..) 表示任意方法, 如果()中没有..,则表示不带参数的方法;有,就表示带任意参数--><aop:pointcut id="pc" expression="execution(* com.qf.spring.aop.service..*(..))"/><!--   <aop:advisor advice-ref="before" pointcut-ref="pc" /><aop:advisor advice-ref="after" pointcut-ref="pc" /><aop:advisor advice-ref="exception" pointcut-ref="pc" />--><aop:advisor advice-ref="around" pointcut-ref="pc" />
</aop:config>

第三节 AspectJ

1. AspectJ 简介

AspectJ是一个面向切面的框架,它扩展了Java语言,定义了AOP 语法,能够在编译期提供代码的织入。Spring通过集成AspectJ实现了以注解的方式定义增强类,大大减少了配置文件中的工作量

2. AspectJ 注解

  • @Aspect 切面标识
  • @Pointcut 切入点
  • @Before 前置通知
  • @AfterReturning 后置通知
  • @Around 环绕通知
  • @AfterThrowing 异常抛出通知

3. AspectJ 应用

3.1 通知类编写
@Aspect
public class AspectJAdvice {@Before(value = "execution(* com.qf.spring.aop.service..*(..))")public void before(JoinPoint jp){Object[] args = jp.getArgs(); //获取方法参数Signature signature = jp.getSignature(); //获取签名if(signature instanceof MethodSignature){ //如果签名是方法签名Method method = ((MethodSignature) signature).getMethod(); //获取方法String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("准备执行方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args));}}@AfterReturning(value = "execution(* com.qf.spring.aop.service..*(..))", returning = "returnValue")public void after(JoinPoint jp, Object returnValue){Object[] args = jp.getArgs(); //获取方法参数Signature signature = jp.getSignature(); //获取签名if(signature instanceof MethodSignature){ //如果签名是方法签名Method method = ((MethodSignature) signature).getMethod(); //获取方法String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("执行完方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",得到返回值:" + returnValue);}}@AfterThrowing(value = "execution(* com.qf.spring.aop.service..*(..))", throwing = "t")public void exception(JoinPoint jp, Throwable t){Object[] args = jp.getArgs(); //获取方法参数Signature signature = jp.getSignature(); //获取签名if(signature instanceof MethodSignature){ //如果签名是方法签名Method method = ((MethodSignature) signature).getMethod(); //获取方法String methodName = method.getName();String className = method.getDeclaringClass().getName();System.out.println("执行方法时:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",发生了异常:" + t.getMessage());}}@Around("execution(* com.qf.spring.aop.service..*(..))")public Object around(ProceedingJoinPoint pjp) throws Throwable {Object[] args = pjp.getArgs();//获取方法的参数Object target = pjp.getTarget(); //获取代理对象Signature signature = pjp.getSignature(); //获取签名if(signature instanceof MethodSignature) { //如果签名是方法签名Method method = ((MethodSignature) signature).getMethod(); //获取被拦截的方法对象String methodName = method.getName();String className = method.getDeclaringClass().getName();try {System.out.println("准备执行方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args));Object returnValue = method.invoke(target, args);System.out.println("执行完方法:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",得到返回值:" + returnValue);return returnValue;} catch (Throwable t){System.out.println("执行方法时:" + className + "." + methodName + ",参数:" + Arrays.toString(args) + ",发生了异常:" + t.getMessage());throw t;}}return null;}
}
3.2 启用注解支持
<bean  class="com.qf.spring.aop.advice.AspectJAdvice" />
<!--配置通知对象-->
<!--  <bean id="before" class="com.qf.spring.aop.advice.BeforeAdvice" /><bean id="after" class="com.qf.spring.aop.advice.AfterAdvice" /><bean id="exception" class="com.qf.spring.aop.advice.ExceptionAdvice" />-->
<!--    <bean id="around" class="com.qf.spring.aop.advice.AroundAdvice" />-->
<!--<aop:config>&lt;!&ndash;pointcut表示切点,也就是通知会在哪些位置触发expression表示切点表达式,切点表达式必须是execution(), execution()方法中的参数必须配置到方法上比如 * com.qf.spring.aop.service..*(..)第一个 * 表示任意访问修饰符com.qf.spring.aop.service.. 最后的两个..表示service包下面的所有子包中的类*(..) 表示任意方法, 如果()中没有..,则表示不带参数的方法;有,就表示带任意参数&ndash;&gt;<aop:pointcut id="pc" expression="execution(* com.qf.spring.aop.service..*(..))"/>&lt;!&ndash;   <aop:advisor advice-ref="before" pointcut-ref="pc" /><aop:advisor advice-ref="after" pointcut-ref="pc" /><aop:advisor advice-ref="exception" pointcut-ref="pc" />&ndash;&gt;<aop:advisor advice-ref="around" pointcut-ref="pc" /></aop:config>--><!-- 启动AspectJ 注解  自动为类生成代理-->
<aop:aspectj-autoproxy proxy-target-class="true" />

第四节 代理模式

代理模式一共分为两种: 静态代理和动态代理

1. 静态代理

静态代理模式由三个部分构成:

  • 一个公共的接口

  • 一个代理角色

  • 一个被代理角色

其中代理角色和被代理角色均需要实现公共接口。

/*** 人类接口,描述人类购物*/
public interface Person {//购物void shopping();
}
/*** 被代理的角色*/
public class ZhangSan implements Person{@Overridepublic void shopping() {System.out.println("购物");}
}
/*** 代理角色*/
public class PersonProxy implements Person{private ZhangSan zhangSan; //维护一个被代理的角色public PersonProxy(ZhangSan zhangSan) {this.zhangSan = zhangSan;}@Overridepublic void shopping() {System.out.println("代理人准备代理购物");zhangSan.shopping();System.out.println("代理人代理购物完毕");}
}
/*** 静态代理测试*/
public class StaticProxyTest {public static void main(String[] args) {Person p = new PersonProxy(new ZhangSan());p.shopping();}
}

思考:如果有多人想要代理购物,那么像PersonProxy这样的类就需要写多次;从编程的角度出发,这显然不合理。应该如何解决?

使用泛型进行解决。

public class StaticProxy<T> implements Person {private T t;public StaticProxy(T t) {this.t = t;}@Overridepublic void shopping() {//判断当前对象是否继承或者实现了Person接口if(!Person.class.isAssignableFrom(t.getClass()))throw new RuntimeException(t.getClass().getName() + "没有实现Person接口");System.out.println("代理人准备代理购物");((Person)t).shopping();System.out.println("代理人代理购物完毕");}
}/*** 静态代理测试*/
public class StaticProxyTest {public static void main(String[] args) {
//        Person p = new PersonProxy(new ZhangSan());
//        p.shopping();Person p = new StaticProxy<>(new ZhangSan());p.shopping();}
}

思考:如果有多个接口想要代理,应该如何解决?

使用动态代理。

2. 动态代理

动态代理也分为两种:JDK 动态代理 和 CGLIB 动态代理

2.1 JDK 动态代理

JDK 动态代理是基于接口实现的,因此只能为实现了接口的类做代理。其实现原理是:在内存中生成一个代理类继承与 Proxy, 同时实现代理接口,然后在内存中进行编译,编译后使用类加载器将该代理类加载进来,从而创建一个代理对象。

public class DynamicProxyTest {public static void main(String[] args) {Person p = new ZhangSan();Class<?> clazz = Person.class;Class[] interfaces = { clazz };ClassLoader loader = clazz.getClassLoader();InvocationHandler handler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("准备进行代理购物");return method.invoke(p, args);}};Person proxy = (Person) Proxy.newProxyInstance(loader, interfaces, handler);proxy.shopping();}
}
2.2 CGLIB 动态代理

CGLIB 动态代理是基于继承实现的,因此可以为任何类做代理。如果一个类实现了接口,通常会使用 JDK 动态代理,但也可以强制使用 CGLIB 动态代理。

public class CgLibProxy {public static void main(String[] args) {final Person p = new ZhangSan();//创建字节码增强对象Enhancer enhancer = new Enhancer();//设置父类,需要继承enhancer.setSuperclass(p.getClass());//需要注意:这里的InvocationHandler是CGLIB提供的net.sf.cglib.proxy.InvocationHandlerenhancer.setCallback(new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] params) throws Throwable {System.out.println("准备进行代理购物");return method.invoke(p, params);}});//创建动态代理实例Person proxy = (Person) enhancer.create();proxy.shopping();}
}

Spring CGLIB

public class SpringCgLibProxy {public static void main(String[] args) {final Person p = new ZhangSan();//创建字节码曾强对象Enhancer enhancer = new Enhancer();//设置父类,需要继承enhancer.setSuperclass(p.getClass());enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {System.out.println("准备进行代理购物");return method.invoke(p, params);}});//创建动态代理实例Person proxy = (Person) enhancer.create();proxy.shopping();}
}
2.3 区别

JDK 动态代理只能为实现了接口的类做代理, CGLIB 动态代理能够为所有的类做代理。JDK 动态代理的创建代理从效率上来说要比 CGLIB 动态代理快。Cglib不能对声明final的方法进行代理,因为final关键字修饰的方法不可被重写。

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

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

相关文章

昇思25天学习打卡营第4天|应用实践

昇思25天学习打卡营第4天 文章目录 昇思25天学习打卡营第4天基于 MindSpore 实现 BERT 对话情绪识别模型简介环境配置数据集数据加载和数据预处理input_idsattention_mask 模型构建模型验证模型推理自定义推理数据集 打卡记录 基于 MindSpore 实现 BERT 对话情绪识别 模型简介…

奥比中光astra_pro相机使用记录

一、信息获取 1、官网 用于了解产品信息 http://www.orbbec.com.cn/sys/37.html 2、开发者社区 咨询问题下载开发部https://developer.orbbec.com.cn/ 二 、windowvs19 1、相机型号 orbbec_astro_pro 根据对应的型号找到需要的包工具 踩坑1&#xff0c;因为这个相机型号…

第20章 Mac+VSCode配置C++环境

1. 下载VSCode VSCode下载地址在mac终端里输入xcode- select --install命令&#xff0c;根据提示安装xcode工具。 2. 安装插件&#xff08;4个&#xff09; 打开VScode&#xff0c;点击应用右侧菜单栏 C/C&#xff08;必装&#xff09; Code Runner&#xff08;必装&#xf…

UCOS-III 任务调度与就绪列表管理

01. 就绪优先级位图 在实时操作系统中&#xff0c;任务调度的效率至关重要。UCOS-III通过就绪优先级位图来快速查找最高优先级的就绪任务&#xff0c;从而实现高效调度。就绪优先级位图是一个按位表示的结构&#xff0c;每个位代表一个优先级&#xff0c;当某个优先级上有任务就…

【FFmpeg】avcodec_open2函数

目录 1. avcodec_open21.1 编解码器的预初始化&#xff08;ff_encode_preinit & ff_decode_preinit&#xff09;1.2 编解码器的初始化&#xff08;init&#xff09;1.3 释放编解码器&#xff08;ff_codec_close&#xff09; FFmpeg相关记录&#xff1a; 示例工程&#xff…

Windows编程之多线程事件对象(Event Object)用法详解

目录 一、前言 二、基础用法 三、API详解 1.创建事件对象 2控制事件状态 3.等待事件对象&#xff1a; 四、实战案例 1.案例描述 2.代码设计 3.总设计代码 4.运行结果 一、前言 事件对象&#xff08;Event Object&#xff09;是我们在大型项目中&#xff0c;进行多线…

竞赛选题 医学大数据分析 - 心血管疾病分析

文章目录 1 前言1 课题背景2 数据处理3 数据可视化4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的心血管疾病分析 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9…

AI绘画Stable Diffusion 解锁精美壁纸创作:利用SD与LLM定制你的专属壁纸,AI副业变现指南!

大家好&#xff0c;我是画画的小强 今天给大家分享一下用AI绘画Stable Diffusion 制作精美手机壁纸&#xff0c;这也可能是当前最快AIGC变现的一种途径。虽然本文的主题为手机壁纸&#xff0c;当调整不同的比例的分辨率宽高比例&#xff0c;就可以直接复用到手机、电脑和平板、…

机器学习原理之 -- 支持向量机分类:由来及原理详解

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是统计学习理论的一个重要成果&#xff0c;广泛应用于分类和回归问题。SVM以其高效的分类性能和良好的泛化能力在机器学习领域中占据重要地位。本文将详细介绍支持向量机的由来、基本原理、构建过程及其优缺点。…

LVS负载均衡群集部署之——DR模式的介绍及搭建步骤

一、LVS-DR集群介绍1.1 LVS-DR 工作原理1.2 数据包流向分析1.3 LVS-DR 模式的特点1.4 LVS-DR中的ARP问题1.4.1 问题一1.4.2 问题二二、构建LVS-DR集群2.1 构建LVS-DR集群的步骤&#xff08;理论&#xff09;1.配置负载调度器&#xff08;192.168.80.30&#xff09;&#xff08;…

5分钟教你用AI把老照片动起来,别再去花49块9的冤枉钱了

文章目录 需要的工具 最近&#xff0c;AI视频在各大平台上&#xff0c;又火了。 只是火的形式&#xff0c;变成了将老照片动起来&#xff0c;打情感牌&#xff0c;或者做很多经典电视剧的再整活。 直接把可灵的生成时间&#xff0c;从以前的4分钟&#xff0c;生生的干成了20分钟…

鸿蒙应用笔记

安装就跳过了&#xff0c;一直点点就可以了 配置跳过&#xff0c;就自动下了点东西。 鸿蒙那个下载要12g个内存&#xff0c;大的有点吓人。 里面跟idea没区别 模拟器或者真机运行 真机要鸿蒙4.0&#xff0c;就可以实机调试 直接在手机里面跑&#xff0c;这个牛逼&#xf…

国标GB/T 28181详解:国标GBT28181-2022 SIP服务器发起广播的命令流程

目录 一、定义 二、作用 1、实现信息的集中管理和分发 &#xff08;1&#xff09;信息集中 &#xff08;2&#xff09;信息分发 2、提高信息传输的可靠性和效率 &#xff08;1&#xff09;可靠性 &#xff08;2&#xff09;提高效率 3、支持多种设备和系统的互通 &am…

mongdb学习与使用

1. 基础概念 MongoDB简介&#xff1a; MongoDB是一个基于文档的NoSQL数据库&#xff0c;具有高性能、高可用性和易扩展性。数据存储在类似JSON的BSON格式中。 基本术语&#xff1a; Database&#xff08;数据库&#xff09;&#xff1a; 集合的容器。Collection&#xff08;集合…

国产强大免费WAF, 社区版雷池动态防护介绍

雷池WAF&#xff0c;基于智能语义分析的下一代 Web 应用防火墙 使用情况 我司于2023年4月23日对雷池进行测试&#xff0c;测试一个月后&#xff0c;于2023年5月24日对雷池进行正式切换&#xff0c;此时版本为1.5.1。 里程碑纪念 后续一直跟随雷池进行版本升级&#xff0c;当前…

QT_GUI

1、QT安装 一个跨平台的应用程序和用户界面框架&#xff0c;用于开发图形用户界面&#xff08;GUI&#xff09;应用程序以及命令行工具。QT有商业版额免费开源版&#xff0c;一般使用免费开源版即可&#xff0c;下面安装的是QT5&#xff0c;因为出来较早&#xff0c;使用较多&…

Python特征工程 — 1.4 特征归一化方法详解

目录 1 Min-Max归一化 方法1&#xff1a;自定义的Min-Max归一化封装函数 方法2&#xff1a; scikit-learn库中的MinMaxScaler 2 Z-score归一化 方法1&#xff1a;自定义的Z-score归一化封装函数 方法2&#xff1a; scikit-learn库中的StandardScaler 3 最大值归一化 4 L…

考研生活day1--王道课后习题2.2.1、2.2.2、2.2.3

2.2.1 题目描述&#xff1a; 解题思路&#xff1a; 这是最基础的操作&#xff0c;思路大家应该都有&#xff0c;缺少的应该是如何下笔&#xff0c;很多同学都是有思路但是不知道如何下笔&#xff0c;这时候看思路的意义不大&#xff0c;可以直接看答案怎么写&#xff0c;最好…

Java项目:基于SSM框架实现的游戏攻略网站系统分前后台【ssm+B/S架构+源码+数据库+毕业论文+任务书】

一、项目简介 本项目是一套基于SSM框架实现的游戏攻略网站系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功能…

redhat7.x 升级openssh至openssh-9.8p1

1.环境准备&#xff1a; OS系统&#xff1a;redhat 7.4 2.备份配置文件&#xff1a; cp -rf /etc/ssh /etc/ssh.bak cp -rf /usr/bin/openssl /usr/bin/openssl.bak cp -rf /etc/pam.d /etc/pam.d.bak cp -rf /usr/lib/systemd/system /usr/lib/systemd/system.bak 3.安装…