Spring框架——AOP配置文件方式

目录

Spring框架的核心功能之AOP技术

AOP的概述

Spring的AOP的简单介绍

AOP概述

什么是AOP?

Spring底层AOP实现

Spring的AOP的简介

AOP开发的相关术语

Spring框架的AOP的底层实现

JDK的动态代理(代码了解,理解原理)

CGLIB的代理技术(代码了解)

Spring基于AspectJ的AOP的开发

AOP的相关术语

AspectJ的XML方式完成AOP的开发

切入点的表达式

AOP的通知类型

通用化切入点表达式的写法


Spring框架的核心功能之AOP技术


AOP的概述

1. 什么是AOP的技术?
    * 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程
    * AOP是一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
    * AOP最早由AOP联盟的组织提出的,制定了一套规范.Spring将AOP思想引入到框架中,必须遵守AOP联盟的规范
    * 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
    * AOP是OOP(面向对象)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型
    * 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率
​
2. AOP:面向切面编程.(思想.---解决OOP遇到一些问题)
3. AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存)
​
4. 为什么要学习AOP
    * 可以在不修改源代码的前提下,对程序进行增强!!   

Spring的AOP的简单介绍

Spring的AOP的简单介绍,主要包括Spring的AOP的简单介绍使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

AOP概述

什么是AOP?

  • AOP:面向切面编程,AOP是OOP的扩展和延伸,解决OOP中遇到的问题

  • AOP使用了横向抽取代替了传统的纵向继承;下面有一个示例

img

  • 假设Dao层在调用save方法保存到数据库前需要加上一个权限校验,传统的方式是通过写一个通用的BaseDao类并写一个checkPri的权限校验方法,然后让所有需要进行权限校验的类继承通用BaseDao,那么继承BaseDao的类就均能够在执行save方法前调用权限校验方法;这就是传统的纵向继承;

  • 而横向抽取是为所有的Dao生成一个代理,然后访问的时候就是访问代理对象UserDaoProxy,相当于一个增强方法

Spring底层AOP实现

Spring底层的AOP采用了两种动态代理:

  • Jdk动态代理:只能对实现接口的类产生代理

  • Cglib动态代理(类似于Javassist第三方代理技术,不要用final修饰类):对没有实现接口的类产生代理对象,生成子类对象

  • 两种代理的简单示例:Spring底层AOP的原理示例(JDK动态代理和cglib动态代理)_白丶程序猿的博客-CSDN博客

Spring的AOP的简介

  • AOP思想最早是由AOP联盟组织提出的,Spring是使用这种思想最好的框架。

  • Spring的AOP原来有自己实现的方式(非常繁琐)。AspectJ是一个AOP的框架,Spring在意识到它的不足后,将AspectJ引入到了Spring的AOP中,作为自身的开发

  • Spring有两套AOP的开发方式:(1)Spring传统方式(弃用);(2)Spring基于AspectJ的AOP开发

AOP开发的相关术语

img

  • 连接点(JoinPoint):可以被拦截到的点,通俗的来说就是一个类中的方法就称为连接点

  • 切入点(Pointcut):真正被拦截到的点,即一个类中真正被增强的方法,如上图假设我们想要对save方法增强,。

  • 通知、增强(Advice):假设对save方法进行权限校验,那么权限校验的方法(checkPri)就是通知;这是针对方法层面的增强

  • 引介(Introduction):类层面的增强,比如在类中添加一个属性或者增加一个方法,这个类就被增强了,就称为引介

  • 目标(Target):就是被增强的对象

  • 代理(proxy):当需要对一个方法增强时,需要生成一个代理

  • 切面(Aspect):多个通知和多个切入点的组合

Spring框架的AOP的底层实现

1. Srping框架的AOP技术底层也是采用的代理技术,代理的方式提供了两种
    1. 基于JDK的动态代理
        * 必须是面向接口的,只有实现了具体接口的类才能生成代理对象
    
    2. 基于CGLIB动态代理
        * 对于没有实现了接口的类,也可以产生代理,产生这个类的子类的方式
​
2. Spring的传统AOP中根据类是否实现接口,来采用不同的代理方式
    1. 如果实现类接口,使用JDK动态代理完成AOP
    2. 如果没有实现接口,采用CGLIB动态代理完成AOP

JDK的动态代理(代码了解,理解原理)

1. 使用Proxy类来生成代理对象的一些代码如下:
    /**
     * 使用JDK的方式生成代理对象
     * @author Administrator
     */
    public class MyProxyUtils {
        public static UserDao getProxy(final UserDao dao) {
            // 使用Proxy类生成代理对象
            UserDao proxy = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(),
                    dao.getClass().getInterfaces(), new InvocationHandler() {
                        
                        // 代理对象方法一执行,invoke方法就会执行一次
                        //参数1 就是那个生成的代理对象
                        //参数2  代理对象所调用的方法对象
                        //参数3  代理对象所调用的方法对象中的参数对象数组
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            if("save".equals(method.getName())){
                                System.out.println("记录日志...");
                                // 开启事务
                            }
                            // 提交事务
                            // 让dao类的save或者update方法正常的执行下去
                            return method.invoke(dao, args); 
                        }
                    });
            // 返回代理对象
            return proxy;
        }
    }

@Test
public void run1(){
    // 目标对象
    UserDao dao = new UserDaoImpl();
    dao.save();
    dao.update();
    
    System.out.println("=============================");
    // 使用工具类,获取到代理对象
    UserDao proxy = MyProxyUtils.getProxy(dao);
    // 调用代理对象的方法
    proxy.save();
    proxy.update();
}

CGLIB的代理技术(代码了解)

1. 引入CBLIB的开发包
    * 如果想使用CGLIB的技术来生成代理对象,那么需要引入CGLIB的开发的jar包,在Spring框架核心包中已经引入了CGLIB的开发包了。所以直接引入Spring核心开发包即可!
​
2. 编写相关的代码
    public static OrderDaoImpl getProxy(){
        // 创建CGLIB核心的类
        Enhancer enhancer = new Enhancer();
        // 设置父类
        enhancer.setSuperclass(OrderDaoImpl.class);
        // 设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args,
                    MethodProxy methodProxy) throws Throwable {
                if("save".equals(method.getName())){
                    // 记录日志
                    System.out.println("记录日志了...");
                }
                return methodProxy.invokeSuper(obj, args);
            }
        });
        // 生成代理对象
        OrderDaoImpl proxy = (OrderDaoImpl) enhancer.create();
        return proxy;
    }

Spring基于AspectJ的AOP的开发


AOP的相关术语

1. Joinpoint(连接点)   -- 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
2. Pointcut(切入点)    -- 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义 ,也就是我们想对那个方法做增强,这个方法叫做切入点
3. Advice(通知/增强)    -- 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
4. Introduction(引介) -- 引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field
5. Target(目标对象) -- 代理的目标对象
6. Weaving(织入)  -- 是指把增强应用到目标对象来创建新的代理对象的过程,简单来说也就是生成代理对象的这个过程,称之为织入。
7. Proxy(代理)    -- 一个类被AOP织入增强后,就产生一个结果代理类
8. Aspect(切面)       -- 是切入点和通知的结合,切面是以后咱们自己来编写和配置的

aop

b

AspectJ的XML方式完成AOP的开发

1. 步骤一:创建JavaWEB项目,引入具体的开发的jar包
    * 先引入Spring框架开发的基本开发包
        com.springsource.org.apache.commons.logging-1.1.1.jar
        com.springsource.org.apache.log4j-1.2.15.jar
        spring-beans-5.0.2.RELEASE.jar
        spring-context-5.0.2.RELEASE.jar
        spring-core-5.0.2.RELEASE.jar
        spring-expression-5.0.2.RELEASE.jar
    * 再引入Spring框架的AOP的开发包
        * spring的传统AOP的开发的包
            * spring-aop-5.0.2.RELEASE.jar
            * com.springsource.org.aopalliance-1.0.0.jar  这个在依赖包中找
        
        * aspectJ的开发包
            * com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar 这个在依赖包中找
            * spring-aspects-5.0.2.RELEASE.jar  Spring整合AspectJ的jar包
             *想要做测试的话可以引入Spring测试的包
            spring-test-5.0.2.RELEASE.jar
            
**当然如果是Maven项目我们只需要在pom.xml文件添加jar包坐标即可
    <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        
步骤二:创建Spring的配置文件applicationContext.xml,引入具体的AOP的schema约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
   </beans>

3. 步骤三:创建包结构,编写具体的接口和实现类 ​

        * org.westos.demo3
            * CustomerDao   -- 接口
            * CustomerDaoImpl  -- 实现类  
4.步骤四:将目标类配置到Spring中
<bean id="customerDao" class="org.westos.demo3.CustomerDaoImpl"/>

5. 步骤五:定义切面类
    public class MyAspectXml {
        // 定义通知
        public void log(){
            System.out.println("记录日志...");
        }
    }
​
6. 步骤六:在配置文件中定义切面类
    <bean id="myAspectXml" class="org.westos.demo3.MyAspectXml"/>
​
7. 步骤七:在配置文件中完成aop的配置
    <aop:config>
        <!-- 引入切面类 -->
        <aop:aspect ref="myAspectXml">
            <!-- 定义通知类型:切面类的方法和切入点的表达式 -->
            <aop:before method="log" pointcut="execution(public void org.westos.demo3.CustomerDaoImpl.save())"/>
        </aop:aspect>
    </aop:config>
​
8. 完成测试
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("classpath:applicationContext.xml")
    public class Demo3 {
        @Resource(name="customerDao")  //Java的这个注解,没有开启注解扫描,也是可以用的
        private CustomerDao customerDao;
        @Test
        public void run1(){
            customerDao.save();
            customerDao.update();
            customerDao.delete();
        }
    }

切入点的表达式

1. 再配置切入点的时候,需要定义表达式,重点的格式如下:execution(public * *(..)),具体展开如下:
    * 切入点表达式的格式如下:
        * execution([修饰符] 返回值类型 包名.类名.方法名(参数))
    
    * 修饰符可以省略不写,不是必须要出现的。 public 可以省略不写
    * 返回值类型是不能省略不写的,根据你的方法来编写返回值。可以使用 * 代替。  例如: public * org.westos.demo3.BookDaoImpl.save()
    * 包名例如:org.westos.demo3.BookDaoImpl
        * 首先org是不能省略不写的,但是可以使用 * 代替  例如:org.*.*.BookDaoImpl
        * 中间的包名可以使用 * 号代替   例如:public void *.*.*.BookDaoImpl.save()
        * 如果想省略中间的包名可以使用 *..*  例如: public void *..*.BookDaoImpl.save()
    
    * 类名也可以使用 * 号代替,也有类似的写法:*DaoImpl  意思是这个类以DaoImp结尾  例如:public void org.westos.demo3.*DaoImpl.save()
    * 方法也可以使用 * 号代替 
        例如:public void org.westos.demo3.*DaoImpl.*() 通配所有方法名   
        例如: public void org.westos.demo3.*DaoImpl.save*()  通配方法以save开头
    * 参数如果是一个参数可以使用 * 号代替,如果想代表任意参数使用 ..
        例如:public void org.westos.demo3.*DaoImpl.save(*)  通配配一个参数
        例如:public void org.westos.demo3.*DaoImpl.save(..)  统配任意个数的参数,或者没有参数

AOP的通知类型

1. 前置通知 before
    * 在目标类的方法执行之前执行。
    * 配置文件信息:<aop:before method="before" pointcut-ref="myPointcut3"/>
    * 应用:可以对方法的参数来做校验
​
2. 最终通知 after 
    * 在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行。
    * 在配置文件中编写具体的配置:<aop:after method="after" pointcut-ref="myPointcut3"/>
    * 应用:例如像释放资源
​
3. 后置通知
    * 方法正常执行后的通知。       
    * 在配置文件中编写具体的配置:<aop:after-returning method="afterReturning" pointcut-ref="myPointcut2"/>
    * 应用:可以修改方法的返回值
​
4. 异常抛出通知
    * 在抛出异常后通知
    * 在配置文件中编写具体的配置:
     throwing="e" 这个e的意思就是你切面类里面配置的afterThrowingLog(Exception e)这个增强的方法的形参的名称
     
     //当你目标对象中delCustomer()方法中出现了异常,那么切面类里面配置的afterThrowingLog()这个增强的方法就会执行
    <aop:after-throwing method="afterThrowingLog"
                                pointcut="execution(public * *..*.Customer*.delCustomer(..))" throwing="e"/>

         //切面类中 抛出异常后通知 需要在增强的方法形参里面提供一个异常对象,当你切入点里面抛出你配置的这个异常类型
         //这个增强的方法,就会执行
    public void afterThrowingLog(Exception e) {
        System.out.println("方法抛出异常后执行通知 日志记录");
    }
    
    * 应用:包装异常的信息
​
5. 环绕通知
    * 方法的执行前后执行。
    * 在配置文件中编写具体的配置:<aop:around method="around" pointcut-ref="myPointcut2"/>
    * 要注意:目标的方法默认不执行,需要使用ProceedingJoinPoint对来让目标对象的方法执行。
​
/**
 * 环绕通知:方法执行之前和方法执行之后进行通知,默认的情况下,目标对象的方法不能执行的。需要手动让目标对象的方法执行
 */
public void around(ProceedingJoinPoint joinPoint){  //ProceedingJoinPoint 固定的一个类 使用他然目标对象的方法执行.
    System.out.println("环绕通知1...");
    try {
        // 手动让目标对象的方法去执行
        joinPoint.proceed();
    } catch (Throwable e) {
        e.printStackTrace();
    }
    System.out.println("环绕通知2...");
}

示例如下

public class XmlAopDemoUserLog {
//    方法执行前通知
    public void beforeLog() {
        System.out.println("开始执行前置通知  日志记录");
    }
//    方法执行完后通知
    public void afterLog() {
        System.out.println("开始执行后置通知 日志记录");
    }
//    执行成功后通知
    public void afterReturningLog() {
        System.out.println("方法成功执行后通知 日志记录");
    }
//    抛出异常后通知
    public void afterThrowingLog(Exception e) {
        System.out.println("方法抛出异常后执行通知 日志记录");
    }
    
    
​
//    环绕通知
    public Object aroundLog(ProceedingJoinPoint joinpoint) {
        Object result = null;
        try {
            System.out.println("环绕通知开始 日志记录");
            long start = System.currentTimeMillis();
                    //有返回参数 则需返回值
        result =  joinpoint.proceed();
​
        long end = System.currentTimeMillis();
        System.out.println("总共执行时长" + (end - start) + " 毫秒");
        System.out.println("环绕通知结束 日志记录");
    } catch (Throwable t) {
        System.out.println("出现错误");
    }
    return result;
}
}

通用化切入点表达式的写法

<!--定义切面 指定拦截方法时 做什么-->
<bean id="xmlAopDemoUserLog" class="com.ganji.demo.service.aspect.XmlAopDemoUserLog"></bean>
<aop:config>
    <aop:aspect ref="xmlAopDemoUserLog"> <!--指定切面-->
        <!--定义切点-->
        <aop:pointcut id="logpoint" expression="execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..))"></aop:pointcut>
        <!--定义连接点-->
        <aop:before pointcut-ref="logpoint" method="beforeLog"></aop:before>
        <aop:after pointcut-ref="logpoint" method="afterLog"></aop:after>
        <aop:after-returning pointcut-ref="logpoint" method="afterReturningLog"></aop:after-returning>
        <aop:after-throwing pointcut-ref="logpoint" method="afterThrowingLog"></aop:after-throwing>
    </aop:aspect>
</aop:config>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring学习笔记——1

Spring学习笔记——1 一、Spring入门1.1、学习路线1.2、传统Javaweb开发困惑及解决方法1.3、三种思想的提出和框架概念1.3.1、IoC、DI和AOP思想提出1.3.2、框架的基本特点 1.4、Spring概述1.5、BeanFactory快速入门1.6、ApplicationContext快速入门1.7、BeanFactory与Applicati…

安全狗V3.512048版本绕过

安全狗安装 安全狗详细安装、遇见无此服务器解决、在windows中命令提示符中进入查看指定文件夹手动启动Apache_安全狗只支持 glibc_2.14 但是服务器是2.17_黑色地带(崛起)的博客-CSDN博客 安全狗 safedogwzApacheV3.5.exe 右键电脑右下角安全狗图标-->选择插件-->安装…

Python:列表(list)与元组(tuple)

列表与元组 列表&#xff1a;list元组&#xff1a;tuple 比较直观的区分&#xff1a;列表是中括号"[ ]“&#xff0c;元组是小括号”( )"元组可以看成列表的只读形式 # 列表 list1 [hello, world] list2 [1, 2, 3, 4, 5] list3 ["a", "b", &…

ChatGPT + Stable Diffusion + 百度AI + MoviePy 实现文字生成视频,小说转视频,自媒体神器!(一)

ChatGPT Stable Diffusion 百度AI MoviePy 实现文字生成视频&#xff0c;小说转视频&#xff0c;自媒体神器&#xff01;(一) 前言 最近大模型频出&#xff0c;但是对于我们普通人来说&#xff0c;如何使用这些AI工具来辅助我们的工作呢&#xff0c;或者参与进入我们的生活…

Flink非对齐checkpoint原理(Flink Unaligned Checkpoint)

Flink非对齐checkpoint原理&#xff08;Flink Unaligned Checkpoint&#xff09; 为什么提出Unaligned Checkpoint&#xff08;UC&#xff09;&#xff1f; 因为反压严重时会导致Checkpoint失败&#xff0c;可能导致如下问题 恢复时间长-服务效率低非幂等和非事务会导致数据…

深入解析项目管理中的用户流程图

介绍用户流程图 用户流程图的定义 用户流程图(User Flow Diagram)是一种可视化工具&#xff0c;它描绘了用户在应用或网站上完成任务的过程。这些任务可以是购物、注册账户、查找信息等&#xff0c;任何需要用户交互的动作都可以在用户流程图中找到。 用户流程图的重要性 用…

uniapp小程序自定义loding,通过状态管理配置全局使用

一、在项目中创建loding组件 在uniapp的components文件夹下创建loding组件&#xff0c;如图&#xff1a; 示例代码&#xff1a; <template><view class"loginLoading"><image src"../../static/loading.gif" class"loading-img&q…

Python(五十六)列表元素的排序操作

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

css实现水平居中

代码示例 <div class"box"><div class"box1"></div> </div>1.弹性布局&#xff1a;&#xff08;推荐&#xff09; display:flex&#xff1b; 这些要添加在父级的&#xff0c;是父级的属性 //父级添加display:flex; //父级添加jus…

【测试联调】如何在前后端测试联调时优雅的构造异常场景

目录 背景 使用iptables实现 利用iptables丢弃某ip数据包 使用 -L 列出所有规则 IP 连通性 通信 测试 插入一条规则&#xff0c;丢弃此ip 的所有协议请求 列出所有规则 测试 丢弃规则内的IP 连通性 清除 规则列表的 限制 模拟ip进行丢包50%的处理。 mysql proxy 代理…

【业务功能篇56】SpringBoot 日志SLF4J Logback

3.5.1 日志框架分类与选择 3.5.1.1 日志框架的分类 日志门面 (日志抽象)日志实现JCL(Jakarta Commons Logging) SLF4J(Simple Logging Facade for Java)Jul(Java Util Logging) , Log4j , Log4j2 , Logback 记录型日志框架 Jul (Java Util Logging)&#xff1a;JDK中的日志…

【电网技术复现】考虑实时市场联动的电力零售商鲁棒定价策略(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

阿里云AK创建

要在阿里云上创建 Access Key&#xff08;AK&#xff09;&#xff0c;您需要按照以下步骤进行操作&#xff1a; 登录到阿里云控制台&#xff08;[https://www.aliyun.com/?utm_contentse_1014243503)&#xff09;。 点击右上方的主账号&#xff0c;点击“AccessKey管理”。 …

NLP实战9:Transformer实战-单词预测

目录 一、定义模型 二、加载数据集 三、初始化实例 四、训练模型 五、评估模型 &#x1f368; 本文为[&#x1f517;365天深度学习训练营]内部限免文章&#xff08;版权归 *K同学啊* 所有&#xff09; &#x1f356; 作者&#xff1a;[K同学啊] 模型结构图&#xff1a; &a…

idea 安装 插件jrebel 报错LS client not configured.

这个报错找了好久&#xff0c;有博主说版本不对&#xff0c;我脑子没反应过来以为是随便换一个低版本的就行&#xff0c;没想到只能是2022.4.1 这个版本才行 一定要用jrebel 2022.4.1的插件版本&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 插件下载地址&…

[Java] 观察者模式简述

模式定义&#xff1a;定义了对象之间的一对多依赖&#xff0c;让多个观察者对象同时监听某一个主题对象&#xff0c;当主题对象发生变化时&#xff0c;他的所有依赖者都会收到通知并且更新 依照这个图&#xff0c;简单的写一个代码 package Section1.listener;import java.ut…

安卓耗电量分析

这里写自定义目录标题 耗电原因分析分析类型 生成分析数据batterystats操作步骤:生成report报告 battery-historian手动编译安装容器安装内容解析 耗电原因分析 下文有阐述&#xff0c;很详细 https://www.cnblogs.com/SA226343/p/6047543.html https://www.cnblogs.com/mytec…

Spring框架——IOC配置文件方式

Spring框架的概述和入门 目录 Spring框架的概述和入门 什么是Spring框架 Spring框架的特点 Spring框架的IOC核心功能快速入门 Spring框架中的工厂&#xff08;了解&#xff09; Spring 创建Bean对象的三种方式 Spring框架的Bean管理的配置文件方式 Spring框架中标签的配…

Python Web开发(详细教程)

前言 PythonWeb开发是使用Python语言进行Web应用程序开发的过程。Python是一种简洁、易读且功能强大的编程语言&#xff0c;因此在Web开发领域广受欢迎。 一、PythonWeb开发简介 PythonWeb开发可以涵盖多个方面&#xff0c;包括服务器端开发、数据库管理、前端设计和API开发…

SQL-每日一题【1084. 销售分析III】

题目 Table: Product Table: Sales 编写一个SQL查询&#xff0c;报告2019年春季才售出的产品。即仅在2019-01-01至2019-03-31&#xff08;含&#xff09;之间出售的商品。 以 任意顺序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 前置知识 between and between…
最新文章