spring框架--全面详解(学习笔记)

2023-05-16

目录

1.Spring是什么

2.Spring 框架特点

3.Spring体系结构

4.Spring开发环境搭建

5.spring中IOC和DI

6.Spring中bean的生命周期

7.Spring Bean作用域

8.spring注解开发

9.Spring框架中AOP(Aspect Oriented Programming)

10.AOP 实现分类

11.AOP 术语

12.SM框架的整合

13.Spring中的事务


1.Spring是什么

spring 是目前主流的 Java Web 开发框架,是 Java 世界最为成功的框架。该框架是一个轻量级的开源框架,具有很高的凝聚力和吸引力。

Spring 由 Rod Johnson 创立,2004 年发布了 Spring 框架的第一版,其目的是用于简化企业级应用程序开发的难度和周期。

Spring 是分层的 Java SE/EE 一站式轻量级开源框架,以 IoC(Inverse of Control,控制反转)和 AOP(Aspect Oriented Programming,面向切面编程)为内核。

IoC 指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们使用 new 创建,而使用 Spring 之后,对象的创建都交给了 Spring 框架。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等

2.Spring 框架特点

1)方便解耦,简化开发

Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。

2)方便集成各种优秀框架

Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。

3)降低 Java EE API 的使用难度

Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。

4)方便程序的测试

Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。

5)AOP 编程的支持

Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。

6)声明式事务的支持

只需要通过配置就可以完成对事务的管理,而无须手动编程

3.Spring体系结构

Spring 框架采用分层的理念,根据功能的不同划分成了多个模块,这些模块大体可分为 Data Access/Integration(数据访问与集成)、Web、AOP、Aspects、Instrumentation(检测)、Messaging(消息处理)、Core Container(核心容器)和 Test。如下图所示(以下是 Spring Framework 4.x 版本后的系统架构图)

上图中包含了 Spring 框架的所有模块,这些模块可以满足一切企业级应用开发的需求,在开发过程中可以根据需求有选择性地使用所需要的模块

1. Data Access/Integration(数据访问/集成)

数据访问/集成层包括 JDBC、ORM、OXM、JMS 和 Transactions 模块,具体介绍如下。

  • JDBC 模块:提供了一个 JBDC 的样例模板,使用这些模板能消除传统冗长的 JDBC 编码还有必须的事务控制,而且能享受到 Spring 管理事务的好处。

  • ORM 模块:提供与流行的“对象-关系”映射框架无缝集成的 API,包括 JPA、JDO、Hibernate 和 MyBatis 等。而且还可以使用 Spring 事务管理,无需额外控制事务。

  • OXM 模块:提供了一个支持 Object /XML 映射的抽象层实现,如 JAXB、Castor、XMLBeans、JiBX 和 XStream。将 Java 对象映射成 XML 数据,或者将XML 数据映射成 Java 对象。

  • JMS 模块:指 Java 消息服务,提供一套 “消息生产者、消息消费者”模板用于更加简单的使用 JMS,JMS 用于用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。

  • Transactions 事务模块:支持编程和声明式事务管理。

2. Web模块

Spring 的 Web 层包括 Web、Servlet、WebSocket 和 Portlet 组件,具体介绍如下。

  • Web 模块:提供了基本的 Web 开发集成特性,例如多文件上传功能、使用的 Servlet 监听器的 IOC 容器初始化以及 Web 应用上下文。

  • Servlet 模块:提供了一个 Spring MVC Web 框架实现。Spring MVC 框架提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等及一套非常易用的 JSP 标签,完全无缝与 Spring 其他技术协作。

  • WebSocket 模块:提供了简单的接口,用户只要实现响应的接口就可以快速的搭建 WebSocket Server,从而实现双向通讯。

  • Portlet 模块:提供了在 Portlet 环境中使用 MVC 实现,类似 Web-Servlet 模块的功能。

3. Core Container(Spring的核心容器)

Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 SpEL 表达式语言模块组成,没有这些核心容器,也不可能有 AOP、Web 等上层的功能。具体介绍如下。

  • Beans 模块:提供了框架的基础部分,包括控制反转和依赖注入。

  • Core 核心模块:封装了 Spring 框架的底层部分,包括资源访问、类型转换及一些常用工具类。

  • Context 上下文模块:建立在 Core 和 Beans 模块的基础之上,集成 Beans 模块功能并添加资源绑定、数据验证、国际化、Java EE 支持、容器生命周期、事件传播等。ApplicationContext 接口是上下文模块的焦点。

  • SpEL 模块:提供了强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从 Spring 容器获取 Bean,它也支持列表投影、选择和一般的列表聚合等。

4. AOP、Aspects、Instrumentation和Messaging

在 Core Container 之上是 AOP、Aspects 等模块,具体介绍如下:

  • AOP 模块:提供了面向切面编程实现,提供比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态的把这些功能添加到需要的代码中,这样各司其职,降低业务逻辑和通用功能的耦合。

  • Aspects 模块:提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程(AOP)框架。

  • Instrumentation 模块:提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。

  • messaging 模块:Spring 4.0 以后新增了消息(Spring-messaging)模块,该模块提供了对消息传递体系结构和协议的支持。

5. Test模块

Test 模块:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。

4.Spring开发环境搭建

使用 Spring 之前需要安装 JDK、Tomcat 和 Eclipse

下载Apache Common Logging API

Common Logging 是使用 Spring 的必要组件。Apache Common Logging API 下载地址:Apache Commons Logging - Download Apache Commons Logging

下载完成后,将压缩包解压到相应位置。该文件包含以下 jar 文件和其它支持文档,目录结构如下。

下载Spring

Spring 下载地址:JFrog

该文件目录结构如下:

 

在 libs 目录中,包含了 Spring 框架提供的所有 jar 文件,其中有 4 个 jar 文件是 Spring 框架的基础包,分别对应 Spring 容器的四个模块,具体如表 2 所示。

使用 Spring 框架时,只需将 Spring 的 4 个基础包以及 commons-logging-1.2.jar 包复制到项目的 lib 目录,并发布到类路径中即可

第一个Spring程序

1.创建maven的javaweb项目

2.引入配置文件

5.spring中IOC和DI

IoC 容器是 Spring 的核心,也可以称为 Spring 容器。Spring 通过 IoC 容器来管理对象的实例化和初始化,以及对象从创建到销毁的整个生命周期。

Spring 中使用的对象都由 IoC 容器管理,不需要我们手动使用 new 运算符创建对象。由 IoC 容器管理的对象称为 Spring Bean,Spring Bean 就是 Java 对象,和使用 new 运算符创建的对象没有区别。

Spring 通过读取 XML 或 Java 注解中的信息来获取哪些对象需要实例化。Spring 提供 2 种不同类型的 IoC 容器,即 BeanFactory 和 ApplicationContext 容器

1. BeanFactory 容器

BeanFactory 是最简单的容器,由 org.springframework.beans.factory.BeanFactory 接口定义,采用懒加载(lazy-load),所以容器启动比较快。BeanFactory 提供了容器最基本的功能,配置文件加载时不会创建对象,在获取bean时才会创建对象

为了能够兼容 Spring 集成的第三方框架(如 BeanFactoryAware、InitializingBean、DisposableBean),所以目前仍然保留了该接口。简单来说,BeanFactory 就是一个管理 Bean 的工厂,它主要负责初始化各种 Bean,并调用它们的生命周期方法。BeanFactory 接口有多个实现类 org.springframework.beans.factory.xml.XmlBeanFactory最常见

使用 BeanFactory 需要创建 XmlBeanFactory 类的实例,通过 XmlBeanFactory 类的构造函数来传递 Resource 对象。如下所示。


Resource resource = new ClassPathResource("applicationContext.xml");
BeanFactory factory = new XmlBeanFactory(resource);    

2. ApplicationContext 容器

ApplicationContext 继承了 BeanFactory 接口,由 org.springframework.context.ApplicationContext 接口定义,对象在启动容器时加载。ApplicationContext 在 BeanFactory 的基础上增加了很多企业级功能,例如 AOP、国际化、事件支持等。

ApplicationContext 接口有两个常用的实现类,具体如下。

1)ClassPathXmlApplicationContext

该类从类路径 ClassPath 中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作,具体如下所示。


ApplicationContext applicationContext = new ClassPathXmlApplicationContext(String configLocation);
配置文件加载,则创建对象  

在上述代码中,configLocation 参数用于指定 Spring 配置文件的名称和位置,如 Beans.xml。

2)FileSystemXmlApplicationContext

该类从指定的文件系统路径中寻找指定的 XML 配置文件,并完成 ApplicationContext 的实例化工作,具体如下所示。


ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);  

二者的主要区别在于,如果 Bean 的某一个属性没有注入,使用 BeanFacotry 加载后,第一次调用 getBean() 方法时会抛出异常,而 ApplicationContext 则会在初始化时自检,这样有利于检查所依赖的属性是否注入。

因此,在实际开发中,通常都选择使用 ApplicationContext,只有在系统资源较少时,才考虑使用 BeanFactory。

spring容器加载多个配置文件

1.使用字符串参数,逗号分隔

2.使用字符串数组

3.使用导入

Spring Bean定义

由 Spring IoC 容器管理的对象称为 Bean,Bean 根据 Spring 配置文件中的信息创建。

可以把 Spring IoC 容器看作是一个大工厂,Bean 相当于工厂的产品,如果希望这个大工厂生产和管理 Bean,则需要告诉容器需要哪些 Bean,以及需要哪种方式装配 Bean。

Spring 配置文件支持两种格式,即 XML 文件格式和 Properties 文件格式。

  • Properties 配置文件主要以 key-value 键值对的形式存在,只能赋值,不能进行其他操作,适用于简单的属性配置。

  • XML 配置文件是树形结构,相对于 Properties 文件来说更加灵活。XML 配置文件结构清晰,但是内容比较繁琐,适用于大型复杂的项目。

通常情况下,Spring 的配置文件使用 XML 格式。XML 配置文件的根元素是 <beans>,该元素包含了多个子元素 <bean>。每一个 <bean> 元素都定义了一个 Bean,并描述了该 Bean 如何被装配到 Spring 容器中<bean> 元素中可以包含很多属性,其常用属性如下表所示。

属性名称描述
idBean 的唯一标识符,Spring 容器对 Bean 的配置和管理都通过该属性完成。id 的值必须以字母开始,可以使用字母、数字、下划线等符号。
namename 属性中可以为 Bean 指定多个名称,每个名称之间用逗号或分号隔开。Spring 容器可以通过 name 属性配置和管理容器中的 Bean。
class该属性指定了 Bean 的具体实现类,它必须是一个完整的类名,即类的全限定名。
scope用于设定 Bean 实例的作用域,属性值可以为 singleton(单例)、prototype(原型)、request、session 和 global Session。其默认值是 singleton
constructor-arg<bean>元素的子元素,可以使用此元素传入构造参数进行实例化。该元素的 index 属性指定构造参数的序号(从 0 开始),type 属性指定构造参数的类型
property<bean>元素的子元素,用于调用 Bean 实例中的 setter 方法来属性赋值,从而完成依赖注入。该元素的 name 属性用于指定 Bean 实例中相应的属性名
ref<property> 和 <constructor-arg> 等元素的子元索,该元素中的 bean 属性用于指定对某个 Bean 实例的引用
value<property> 和 <constractor-arg> 等元素的子元素,用于直接指定一个常量值
list用于封装 List 或数组类型的依赖注入
set用于封装 Set 类型的依赖注入
map用于封装 Map 类型的依赖注入
entry<map> 元素的子元素,用于设置一个键值对。其 key 属性指定字符串类型的键值,ref 或 value 子元素指定其值
init-method容器加载 Bean 时调用该方法,类似于 Servlet 中的 init() 方法
destroy-method容器删除 Bean 时调用该方法,类似于 Servlet 中的 destroy() 方法。该方法只在 scope=singleton 时有效
lazy-init懒加载,值为 true,容器在首次请求时才会创建 Bean 实例;值为 false,容器在启动时创建 Bean 实例。该方法只在 scope=singleton 时有效

IOC创建对象的方式

1.无参构造器创建对象 (默认)

2.有参构造创建对象

  • 使用下标传递参数

  • 使用数据类型传递参数

  • 通过属性名传递参数

创建对象时属性的其它注入方式

set注入

<bean id="studentService" class="cn.kgc.spring.service.StudentServiceImpl">
    <!-- 属性是引用类型 赋值时使用ref-->
        <property name="studentDao" ref="studentDao"/>
    <!-- 属性是基本类型 String类型 Date类型 赋值时使用value -->
        <property name="age" value="20"/>
        <property name="stuName" value="张三"/>
        <property name="price" value="20.4"/>
        <property name="score" value="80.3"/>
        <property name="birth" value="2021/8/13"/>
        <property name="str" >
            <array>
                <value>张三</value>
                <value>李四</value>
                <value>王五</value>
            </array>
        </property>
        <property name="lis">
            <list>
                <value>抽烟</value>
                <value>喝酒</value>
                <value>烫头</value>
            </list>
        </property>
        <!-- spring容器中组件默认都是单例的 全局共享一个对象-->
      <property name="lis2">
          <list>
              <ref bean="studentDao"></ref>
              <ref bean="studentDao"></ref>
              <ref bean="studentDao"></ref>
          </list>
      </property>
        <property name="books">
            <set>
                <value>java</value>
                <value>php</value>
                <value>c#</value>
            </set>
        </property>
        <property name="scores">
            <map>
                <entry key="math" value="89" ></entry>
                <entry key="english" value="90" ></entry>
                <entry key="java" value="80" ></entry>
            </map>
        </property>
        <property name="map">
            <map>
                <entry key="01" value-ref="studentDao"></entry>
                <entry key="02" value-ref="studentDao"></entry>
                <entry key="03" value-ref="studentDao"></entry>
            </map>
        </property>
        <property name="ps">
            <props>
                <prop key="driver">com.mysql.jdbc.Driver</prop>
                <prop key="url">jdbc:mysql:///mybatis</prop>
                <prop key="username">root</prop>
                <prop key="password">rooot</prop>
            </props>
        </property>
    </bean>

 

使用set注入,每个属性必须含有对应的set方法,否则无法进行属性的注入

Spring的依赖注入之p命名空间和c命名空间

p命名空间是set注入的一种快捷实现方式,想要使用p命名空间注入,需要注意一下几点。

  1. 实体类中必须有set方法;

  2. 实体类中必须有无参构造器(默认存在);

  3. 必须导入p命名空间注入方式依赖。

xml依赖代码:


  

 

导入后即可使用


  

 

c命名空间是构造器注入的一种快捷实现方式,想要使用c命名空间,需要注意一下几点。

  1. 实体类中必须存在有参构造器;

  2. 必须导入c命名空间注入方式依赖。

xml依赖代码:


  

 

导入后即可使用


  

 

类型转换器的使用:

作用:自定义注入参数和实体类中类型的匹配方式

import org.springframework.core.convert.converter.Converter;

public class MyConverter  implements Converter<String, Date> {

    @Override
    public Date convert(String source) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date parse = simpleDateFormat.parse(source);
            return parse;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }
}

Bean的自动装配

1.autowire="byName"在容器的上下文中寻找与类中属性对应的set方法名字相同的id属性值进行装配

 	<bean id="teacher" class="cn.kgc.spring.entity.Teacher">
        <property name="name" value="李老师"/>
        <property name="teaNo" value="001"/>
    </bean>
    <bean id="classRoom1" class="cn.kgc.spring.entity.ClassRoom">
        <property name="address" value="学思楼1楼"/>
        <property name="classNo" value="1"/>
    </bean>
    <bean id="student" class="cn.kgc.spring.entity.Student" autowire="byName" ></bean>

 

2.autowire="byType"在容器的上下文中寻找与类中属性类型相同的Bean进行装配

 

3.使用注解自动装配

1.导入context约束

2.开启注解支持

 

获取配置文件中的值

public class Aoo {

    @Value("${test.boolean}")
    private Boolean testBoolean;

    @Value("${test.string}")
    private String testString;

    @Value("${test.integer}")
    private Integer testInteger;

    @Value("${test.long}")
    private Long testLong;

    @Value("${test.float}")
    private Float testFloat;

    @Value("${test.double}")
    private Double testDouble;

    @Value("#{'${test.array}'.split(',')}")
    private String[] testArray;

    @Value("#{'${test.list}'.split(',')}")
    private List<String> testList;

    @Value("#{'${test.set}'.split(',')}")
    private Set<String> testSet;

    @Value("#{${test.map}}")
    private Map<String, Object> testMap;
    
}

 配置文件 properties

spring中复杂对象的创建

1.FactoryBean

public class ConnectionFactoryBean  implements FactoryBean<Connection> {

    @Override
    public Connection getObject() throws Exception {

        Class.forName("com.mysql.jdbc.Driver");
        Connection connection = DriverManager.getConnection("jdbc:mysql:///java2215?serverTimezone=UTC", "root", "root");
        return connection;
    }

    @Override
    public Class<?> getObjectType() {
        return Connection.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

 

 

 

 

 

 

 

 

6.Spring中bean的生命周期

1.singleton 容器启动的时候创建对象,容器正常关闭时销毁对象

2.prototype 获取对象的时候创建对象,spring容器不负责对象的销毁

生命周期的过程:

1.调用无参创建对象

2.调用set方法初始化属性

3.调用初始化方法

4.对象创建完成,使用对象

5.关闭容器,调用销毁的方法

7.Spring Bean作用域

在配置文件中,除了可以定义 Bean 的属性值和相互之间的依赖关系,还可以声明 Bean 的作用域。例如,如果每次获取 Bean 时,都需要一个 Bean 实例,那么应该将 Bean 的 scope 属性定义为 prototype,如果 Spring 需要每次都返回一个相同的 Bean 实例,则应将 Bean 的 scope 属性定义为 singleton。

作用域的种类

Spring 容器在初始化一个 Bean 实例时,同时会指定该实例的作用域。Spring 5 支持以下 6 种作用域。

1)singleton

默认值,单例模式,表示在 Spring 容器中只有一个 Bean 实例,Bean 以单例的方式存在。

2)prototype

原型模式,表示每次通过 Spring 容器获取 Bean 时,容器都会创建一个 Bean 实例。

3)request

每次 HTTP 请求,容器都会创建一个 Bean 实例。该作用域只在当前 HTTP Request 内有效。

4)session

同一个 HTTP Session 共享一个 Bean 实例,不同的 Session 使用不同的 Bean 实例。该作用域仅在当前 HTTP Session 内有效。

5)application

同一个 Web 应用共享一个 Bean 实例,该作用域在当前 ServletContext 内有效。

类似于 singleton,不同的是,singleton 表示每个 IoC 容器中仅有一个 Bean 实例,而同一个 Web 应用中可能会有多个 IoC 容器,但一个 Web 应用只会有一个 ServletContext,也可以说 application 才是 Web 应用中货真价实的单例模式。

6)websocket

websocket 的作用域是 WebSocket ,即在整个 WebSocket 中有效

8.spring注解开发

1.开启注解的包扫描

 

2.常用的注解

 

四个注解的功能是一样的,只是使用不同的注解可以看出层次结构

3.作用域注解

 

9.Spring框架中AOP(Aspect Oriented Programming)

1.代理模式讲解

 

作用:

通过代理类为原始类增加额外的功能

代理分类:

1.1静态代理

静态代理优缺点

1)优点 :在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展 2)缺点 :因为代理对象需要与目标对象实现一样的接口,所以会很多代理类 ,一旦接口增加方法,目标对象与代理对象都要维护

开发代理对象的原则:

1.代理对象和目标对象实现相同的接口

2.代理对象依赖于目标对象

1.2动态代理(反射)

程序运行的过程中,通过jdk提供代理技术动态的为某个类产生动态代理对象的过程

开发代理对象的原则:

1)代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用JDK动态代理。 2)代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象。 3)动态代理也叫做 :JDK代理、接口代理

 @Test
    public void test4() { //jdk的动态代理

        // 被代理对象
        UserServiceImpl userService = new UserServiceImpl();
        InvocationHandler handler = new InvocationHandler() {
            /**
             * @param proxy  生成的代理对象  可忽略
             * @param method  原始对象中的方法
             * @param args     原始对象中的参数
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("------log---------");
                Object invoke = method.invoke(userService, args);
                return invoke;
            }
        };

        /**
         *参数1:类加载器,动态代理对象没有类加载器 需要借助别的类的加载器实现类的加载
         * 类加载器的作用:
         *  1.加载class文件到JVM虚拟机
         *  2.创建类的class对象,进而创建类的实例化对象
         *
         * 参数2:原始类实现的所有接口  基于jdk的动态代理要求代理对象和原始对象要实现相同的接口
         *
         * 参数3:代理对象额外增加的功能  InvocationHandler
         *
         */
  UserService o =(UserService) Proxy.newProxyInstance(TestStaticProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler);
        o.login();
        o.register();

    }

 

基于CGLib的动态代理

开发代理对象的原则:

1.代理对象无需和原始类对象实现相同的接口

2.代理对象和原始类对象要存在父子类关系

实现步骤

@Test
    public void test5(){ //基于cglib的动态代理

        UserServiceImpl userService = new UserServiceImpl();

        Enhancer enhancer = new Enhancer();
        enhancer.setClassLoader(this.getClass().getClassLoader());
        enhancer.setSuperclass(userService.getClass());
        //设置额外的功能
        MethodInterceptor callback = new MethodInterceptor() {
            //等价于  jdk代理中 invocationHandler 中的 invoke 方法
            /**
             * @param o          代理对象
             * @param method    原始对象中的方法
             * @param objects   原始对象中的参数
             * @param methodProxy  代理方法
             * @return    原始方法的返回值
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("---------cglib log------------");
                return  method.invoke(userService, objects);
            }
        };
        enhancer.setCallback(callback);

        // 创建代理对象
        UserService usrService =(UserService) enhancer.create();
        usrService.login();
        usrService.register();
    }

 

2.AOP概述

AOP为Aspect Oriented Programming的缩写,是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型

AOP可以分离业务代码和关注点代码(重复代码),在执行业务代码时,动态的注入关注点代码。切面就是关注点代码形成的类。Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口

 

10.AOP 实现分类

AOP 要达到的效果是,保证开发者不修改源代码的前提下,去为系统中的业务组件添加某种通用功能,按照 AOP 框架修改源代码的时机,可以将其分为两类:

  • 静态 AOP 实现, AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。

  • 动态 AOP 实现, AOP 框架在运行阶段对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP

11.AOP 术语

  • 连接点JointPoint) :与切入点匹配的执行点,在程序整个执行流程中,可以织入切面的位置,方法的执行前后,异常抛出的位置

  • 切点(PointCut) : 在程序执行流程中,真正织入切面的方法。

  • 切面(ASPECT) :切点+通知就是切面

  • 通知(Advice) :切面必须要完成的工作,也叫增强。即,它是类中的一个方法,方法中编写织入的代码。

    前置通知 后置通知

    环绕通知 异常通知

    最终通知

  • 目标对象(Target) ;被织入通知的对象

  • 代理对象(Proxy) :目标对象被织入通知之后创建的新对象

快速使用

1.基于接口形式实现(spring自身对于aop的实现)

使用Spring aop接口方式实现aop, 可以通过自定义通知来供Spring AOP识别对应实现的接口是:

  1. 前置通知: MethodBeforeAdvice

  2. 返回通知:AfterReturningAdvice

  3. 异常通知:ThrowsAdvice

  4. 环绕通知:MethodInterceptor

通知的类型

Spring 方面可以使用下面提到的五种通知工作:

通知描述
前置通知在一个方法执行之前,执行通知。
最终通知在一个方法执行之后,不考虑其结果,执行通知。
后置通知在一个方法执行之后,只有在方法成功完成时,才能执行通知。
异常通知在一个方法执行之后,只有在方法退出抛出异常时,才能执行通知。
环绕通知在一个方法调用之前和之后,执行通知。

案例

业务接口

 

实现类

 

实现接口定义通知类

 

配置方式

 

基于Aspectj实现AOP操作

1.基于xml配置文件

2.基于注解的形式实现

切入点表达式

作用:声明对哪个类中的哪个方法进行增强

语法:

execution([访问权限修饰符] 返回值 [ 类的全路径名 ] 方法名 (参数列表)[异常])

  • 访问权限修饰符:

    可选项,不写就是四个权限都包含

    写public就表示只包括公开的方法

  • 返回值类型

    必填项 * 标识返回值任意

  • 全限定类名

    可选项,两个点 .. 表示当前包以及子包下的所有类,省略表示所有类

  • 方法名

    必填项 * 表示所有的方法 set*表示所有的set方法

  • 形参列表

    必填项

    ()表示没有参数的方法

    (..)参数类型和参数个数随意的方法

    (*)只有一个参数的方法

    (*,String) 第一个参数类型随意,第二个参数String类型

  • 异常信息

    可选项 省略时标识任何异常信息

方式2:定义切面类

public class PointCut {

     //前置通知
    public void beforeMethod(){
        System.out.println("开启事务");
    }
    //后置通知  切点方法正常执行之后执行
    public void afterMethod(){
        System.out.println("关闭事务");
    }

    //环绕通知
    public void around(ProceedingJoinPoint jp)  {


        try {
            System.out.println("------环绕前------");
            Object proceed = jp.proceed();
            System.out.println("------环绕后------");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常通知");
        }finally {
            System.out.println("最终通知");
        }

    }

    //最终通知  无论切点方法是否正常执行 都会在其后执行
    public void fy(){
        System.out.println("最终通知");
    }

    //异常通知   和后置通知永远只能执行一个
    public void exceptionMethod(){
        System.out.println("异常通知");
    }
    
}

 使用xml配置方式实现aop

注解方式实现aop

 

@Component
@Aspect
public class PointCut2 {

    //前置通知
    @Before("execution(* cn.kgc.spring.service.StudentServiceImpl.*(..))")
    public void beforeMethod(){
        System.out.println("开启事务");
    }
    //后置通知  切点方法正常执行之后执行
    @AfterReturning("execution(* cn.kgc.spring.service.StudentServiceImpl.*(..))")
    public void afterMethod(){
        System.out.println("关闭事务");
    }

    //环绕通知
    @Around("execution(* cn.kgc.spring.service.StudentServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp){

        try {
            System.out.println("------环绕前------");
            Object proceed = jp.proceed();
            System.out.println("------环绕后------");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("异常通知");
        }finally {
            System.out.println("最终通知");
        }

    }
    //最终通知  无论切点方法是否正常执行 都会在其后执行
    @After("execution(* cn.kgc.spring.service.StudentServiceImpl.*(..))")
    public void fy(){
        System.out.println("最终通知");
    }
    //异常通知   和后置通知永远只能执行一个
    @AfterThrowing("execution(* cn.kgc.spring.service.StudentServiceImpl.*(..))")
    public void exceptionMethod(){
        System.out.println("异常通知");
    }
}

 

 通用切点的定义方式

 

12.SM框架的整合

1.引入依赖

<dependencies>
<!--    mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.44</version>
    </dependency>
    <!--druid-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.10</version>
    </dependency>
<!--mybatis-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.7</version>
    </dependency>

    <!--IOC 依赖注入-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.9</version>
    </dependency>

    <!--mybatis&spring 整合包-->

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.5</version>
    </dependency>
    
    <!--aspects 切面-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.3.9</version>
    </dependency>

    <!--jdbc-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.3.9</version>
    </dependency>

    <!--lombok-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.16</version>
    </dependency>

    <!-- 日志工具-->
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.17</version>
    </dependency>
    <!--mybatis分页插件-->
    <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.2.1</version>
    </dependency>
<!--测试工具-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

  </dependencies>

 2.配置spring的文件

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context.xsd">
    <!--引入外部的数据源配置文件-->
    <context:property-placeholder location="db.properties"/>
    <!--配置druid数据库连接池-->
    <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--sqlSessionFactory-->
    <bean id="ssf" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 配置数据源-->
        <property name="dataSource" ref="druid"/>
    <!-- 注入mybatis的核心配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <!--mapper映射文件-->
        <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    </bean>

    <!--扫描所有的接口-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--扫描所有的接口,生成代理对象,注入spring容器-->
        <property name="basePackage" value="cn.kgc.spring.dao"/>
    </bean>
</beans>

3.配置mybatis文件 
  
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
    <!--开启字段的驼峰命名-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <!--开启日志-->
    <setting name="logImpl" value="LOG4J"/>
</settings>
    <!--设置实体类的别名-->
    <typeAliases>
        <package name="cn.kgc.mybatis.entity"/>
    </typeAliases>
   <!-- 分页配置-->
     <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
            <!-- 配置mysql方言 -->
            <property name="helperDialect" value="mysql" />
            <!-- 设置为true时,如果pageSize=0就会查询出全部的结果 -->
            <property name="pageSizeZero" value="true" />
            <!-- 3.3.0版本可用,分页参数合理化,默认false禁用 -->
            <!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 -->
            <!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 -->
            <property name="reasonable" value="true" />
        </plugin>
    </plugins>
</configuration>

日志文件 (log4j.properties)

4.编写测试类 测试

 

13.Spring中的事务

1.配置式事务

<?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"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
                 http://www.springframework.org/schema/context
                 http://www.springframework.org/schema/context/spring-context.xsd
                 http://www.springframework.org/schema/tx
                 http://www.springframework.org/schema/tx/spring-tx.xsd">

<!--    注入事务管理器-->
  <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="druid"/>
  </bean>
    
<!--配置事务通知-->
<tx:advice id="tx" transaction-manager="dataSourceTransactionManager">
    <tx:attributes>
        <tx:method name="save"/>
        <tx:method name="delete"/>
    </tx:attributes>
</tx:advice>

<!--配置事务的aop-->
    <aop:config>
        <aop:pointcut id="servicePoint" expression="execution(* cn.kgc.spring.service.*.*(..))"/>
        <aop:advisor advice-ref="tx" pointcut-ref="servicePoint"/>
    </aop:config>
</beans>

 2.声明式事务

 

 

事务传播方式

事务最重要的两个特性,是事务的传播级别和数据隔离级别。传播级别定义的是事务的控制范围,事务隔离级别定义的是事务在数据库读写方面的控制范围。

 

事务传播方式演示:

1、PROPAGATION_REQUIRED

说明:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。

演示:

 

public interface UserMapper{
        Integer deleteById(int id);
}
public interface EmpMapper {
    Integer deleteByEmpNo(String empno);
}

public interface EmpService {
    Integer deleteByEmpNo(String empno);
}

@Service
public class EmpServiceImpl implements EmpService {
    @Autowired
    private EmpMapper empMapper;
    /**
     * 根据员工编号删除员工信息
     * @param empno
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public Integer deleteByEmpNo(String empno) {
        Integer integer = empMapper.deleteByEmpNo(empno);
        if(integer ==1 ){
            throw  new RuntimeException();
        }
        return integer;
    }
}

public interface UserService {
    int deleteById(int id);
}

// 实现类
@Service
public class UserServiceImpl  implements UserService{

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private EmpService empService;

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public int deleteById(int id) {
        Integer line =  userMapper.deleteById(id);
        Integer integer = empService.deleteByEmpNo("7698");
        return line+integer;
    }
}

结果:

2、PROPAGATION_SUPPORTS

说明:支持当前事务,如果当前没有事务,就以非事务方式执行。

 

3、PROPAGATION_REQUIRES_NEW

说明:新建事务,如果当前存在事务,把当前事务挂起

 

 

 

 

         

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring框架--全面详解(学习笔记) 的相关文章

  • 记一个万金油开源框架JHipster

    本文地址 xff1a http blog csdn net sushengmiyan article details 53190236 百搭代码生成框架 体验新技术汇总 xff1a Spring BootSpring SecurityAng
  • SQLServer触发器创建、删除、修改、查看...适用于级联删除

    一 触发器是一种特殊的存储过程 它不能被显式地调用 而是在往表中插入记录 更新记录或者删除记录时被自动地激活 所以触发器可以用来实现对表实施复杂的完整性约束 二 SQL Server为每个触发器都创建了两个专用表 Inserted表和Del
  • 工薪族巧理财之定期存款中整存整取、零存整取、存本取息之间的微妙区别

    银行的官方术语先给大家普及一下 xff1a 定期存款是在存款时约定存储时间 一次或按期分次 在约定存期 存入本金 xff0c 整笔或分期平均支取本金利息的一种储蓄 按存取方式定期存款分为整存整取定期存款 零存整取定期存款 存本取息定期存款
  • CentOS防火墙相关命令

    目录 1 开放端口2 查看防火墙所有开放的端口3 关闭防火墙4 查看防火墙状态5 查看监听的端口6 检查端口被哪个进程占用7 查看进程的详细信息 1 开放端口 firewall cmd zone span class token opera
  • no module named win32com.client错误解决

    无论什么时候 xff0c 你在运行的时候发现有importError no module named win32com client这个提示 你都可以这么解决 xff1a 请下载http sourceforge net projects p
  • java.util.concurrent同步框架(AQS论文中文翻译)

    java util concurrent同步框架 摘要目录和主题描述一般条款关键字1 介绍 xff1a 需求设计实现4 使用方式5 性能6 结论7 致谢 Doug Lea SUNY Oswego Oswego NY 13126 dl 64
  • POJ2287 田忌赛马---贪心算法

    田忌赛马 题目详见http poj org problem id 61 2287 田忌赛马大家都听过 xff0c 可是如果不是上中下三等马 xff0c 而是很多匹马 xff0c 优劣有很多种分类 xff0c 就不仅仅是321的问题了 这个很
  • 贪心算法详解

    之前讲过动态规划DP xff0c 现在来说说贪心 贪心算法在解决问题的策略上目光短浅 xff0c 只根据当前已有的信息就做出选择 xff0c 而且一旦做出了选择 xff0c 不管将来有什么结果 xff0c 这个选择都不会改变 也就是说贪心对
  • 搜索智能提示suggestion,附近点搜索

    第三十六 三十七章 搜索智能提示suggestion xff0c 附近地点搜索 作者 xff1a July 致谢 xff1a caopengcs 胡果果 时间 xff1a 二零一三年九月七日 题记 写博的近三年 xff0c 整理了太多太多的
  • 多重继承及虚继承中对象内存的分布

    多重继承及虚继承中对象内存的分布 这篇文章主要讲解G 43 43 编译器中虚继承的对象内存分布问题 xff0c 从中也引出了dynamic cast和static cast本质区别 虚函数表的格式等一些大部分C 43 43 程序员都似是而非
  • 【Google】25匹马的角逐

    问题是这样的 xff1a 一共有25匹马 xff0c 有一个赛场 xff0c 赛场有5个赛道 xff0c 就是说最多同时可以有5匹马一起比赛 假设每匹马都跑的很稳定 xff0c 不用任何其他工具 xff0c 只通过马与马之间的比赛 xff0
  • HDOJ 1058 Humble Numbers解题报告【DP】

    Humble Numbers 题目详见http acm hdu edu cn showproblem php pid 61 1058 开始拿到这个题目的时候还纠结了半天 xff0c 英语很差的话这个题是不可能AC的 而我就是其中之一 Hum
  • 背包问题详解

    背包问题 背包问题 Knapsack problem 是一种组合优化的NP完全问题 问题可以描述为 xff1a 给定一组物品 xff0c 每种物品都有自己的体积和价值 xff0c 在限定的总体积内 xff0c 我们如何选择 xff0c 才能
  • 楼教主男人必解八题之 Coins 解题报告

    楼教主男人必解八题之 Coins 解题报告 题目详见http acm hdu edu cn showproblem php pid 61 2844 这个题目和POJ1742是一个题目 xff0c 也是楼教主的男人八题之一 说的是给出N种硬币
  • CentOS7安装MySQL5.7过程以及常用需要修改操作,安装mysqlclient,安装mysql-devel报错问题以及卸载MySQL

    目录 Docker安装运行命令mysql配置 Centos安装下载安装启动修改root用户密码修改远程访问权限1 改表法2 授权法 MySQL密码验证mysqlclient时候报错 OSError mysql config not foun
  • 如何证明程序的正确性?

    什么样的程序才是正确的 xff1f 如何来保证程序是正确的 xff1f 测试 xff1f NO xff01 采用测试方法确实可以发现程序中的错误 xff0c 但却不能保证和证明程序中没有错误 xff01 先来看一些概念 xff0c 有关 程
  • 平摊分析

    平摊分析 我们经常在处理数据结构的时间复杂度的时候 xff0c 大多数操作代价很低 xff0c 可是由于某些个别操作的代价较高 xff0c 导致最后求得时间复杂度的上界不是那么的紧凑 在平摊分析中 xff0c 执行一系列数据结构操作所需要的
  • java中用FTPClient,执行到ftp.storeFile(fileName, inputFile);无反应

    package com aa test import cn hutool core util StrUtil import com nuctech platform tip constant TipConstant import lombo
  • SpringMVC拦截去之HandlerInterceptorAdapter的使用

    定义 HandlerInterceptorAdapter是SpringMVC中的拦截器 xff0c 它是用于拦截URL请求的 xff0c 主要是为了请求的预处理和后续处理 使用方法 编写代码 我们只需要自定义一个拦截器去继承HandlerI
  • EKF之雅克比矩阵(一)

    扩展卡尔曼滤波 EKF EKF之雅克比矩阵 文章目录 扩展卡尔曼滤波 EKF 前言一 什么是线性化 xff1f 二 雅克比矩阵1 矩阵的几何含义2 非线性矩阵与基底的关系3 雅克比矩阵 三 工程中雅克比矩阵如何应用总结 前言 一般的卡尔曼滤

随机推荐

  • Java数据结构与算法-程序员十大常用算法[day13]

    程序员十大常用算法 文章目录 程序员十大常用算法二分查找算法 非递归 分治算法分治算法最佳实践 汉诺塔 动态规划算法KMP算法KMP算法简介KMP实现 贪心算法普利姆算法克鲁斯卡尔算法分析克鲁斯卡尔算法分析 迪杰斯特拉算法弗洛伊德算法回溯算
  • SNMP测试

    SNMP测试 测试环境 xff1a Solaris10 10 10 128 89 Linux xff1a 10 10 151 8 windows 测试方案 xff1a 1 本地测试 2 远程测试 配置文件 xff1a 修改环境变量 在sol
  • apex编译错误解决方案

    这里写自定义目录标题 apex编译错误解决方案 csrc mlp cpp 123 3 note in expansion of macro AT DISPATCH FLOATING TYPES AND HALF AT DISPATCH FL
  • Javaweb项目实践MVC入门到精通

    Javaweb项目实践MVC入门到精通 目标配置环境实体模型 user Dao的实现实体模型 ModelViewController xff1a 转发任务 xff0c 路由器的功能安全sql注入常见问题 目标 这个目标是写一个MVC模型 通
  • C++ 铪铪铪铪 烫烫烫 屯屯屯

    VS中 xff0c Debug模式下 xff0c 对于未初始化的内存 xff1a 1 xff09 若为栈内存 xff0c 默认为一连串 烫烫烫 xff0c 0xcc 2 xff09 若为堆内存 xff0c 默认为一连串 屯屯屯 xff0c
  • git常用操作命令

    目录 git删除push到远程服务器的commit用户名和邮箱撤销add操作commit message写错了删除已经上传的文件添加文件追踪 git删除push到远程服务器的commit span class token comment 会
  • 魔方矩阵

    看到魔方矩阵 xff0c 好奇 xff0c 好玩儿 xff0c 正好赶上周五 xff0c 就来放松一下 xff0c 总结一下几种魔方矩阵的规律 xff0c 并写一下C 43 43 实现过程 定义 xff1a 平面魔方的一般定义 xff1a
  • 样条插值曲线类型及其优缺点说明

    Spline Types This page gives a breakdown of each spline type how to use each one and the advantages disadvantages of eac
  • caffe layer层详解

    1 基本的layer定义 xff0c 参数 1 基本的layer定义 xff0c 参数 如何利用caffe定义一个网络 xff0c 首先要了解caffe中的基本接口 xff0c 下面分别对五类layer进行介绍 Vision Layers
  • caffe编译中的python问题

    问题 usr include boost python detail wrap python hpp 50 23 fatal error pyconfig h No such file or directory 解决方案 make clea
  • latex图像注释位置

    latex图像注释的位置在左边 不知道谁把模板里的 usepackage caption 给注释掉了
  • pytorch pretrained model

    pytorch pretrained model two methods method 1 比较大小 self span class token punctuation span model span class token operato
  • nodejs之minimist中间件使用

    minimist是nodejs的命令行参数解析工具 xff0c 因其简单好用 xff0c 轻量等特性 xff0c 所以用户使用较多 特性 xff1a short options long options Boolean 和 Number类型
  • RNA-seq 保姆教程:差异表达分析(一)

    介绍 RNA seq 目前是测量细胞反应的最突出的方法之一 RNA seq 不仅能够分析样本之间基因表达的差异 xff0c 还可以发现新的亚型并分析 SNP 变异 本教程 1 将涵盖处理和分析差异基因表达数据的基本工作流程 xff0c 旨在
  • 腾讯、阿里云服务器安装java全流程(yum安装java超简单详细版)

    有些服务器中自带了java xff0c 但不是你想要的版本的话 xff0c 可以先卸载掉 xff0c 然后更换想要的ava版本 因为是有网环境 xff0c 可以使用yum安装 无网环境可以参考我写的另一篇文章 xff1a linux无网环境
  • 某个牛人做WINDOWS系统文件详解

    某个牛人做WINDOWS系统文件详解 超牛 很详细介绍WINDOWS系统文件用途 想各位保存一份以后说定会有用 A ACCESS CHM Windows帮助文件 ACCSTAT EXE 辅助状态指示器 ADVAPI32 DLL 高级Win3
  • Nginx 流量统计分析

    目录 程序简介输出结果环境程序要求例子代码 程序简介 通过分析nginx日志 xff0c 统计出nginx流量 xff08 统计nginx日志中 body bytes sent 字段 xff09 xff0c 能自定义时间间隔 xff0c 默
  • 融资租赁业务系统(财务中台)

    融资租赁业务系统 财务中台 产品白皮书 版本号 xff1a V1 1 李雷 微信号 xff1a yanan122914 平台概述 融资租赁财务中台产品是一套专门针对融资租赁行业设计的融资租赁财务统一解决方案 对租赁公司传统的大单回租 直租
  • Session详解,学习 Session对象一篇文章就够了

    目录 1 Session概述 2 Session原理 3 Session使用 3 1 获取Session 3 2 Session保存数据 3 3 Session获取数据 3 4 Session移除数据 4 Session与Request应用
  • spring框架--全面详解(学习笔记)

    目录 1 Spring是什么 2 Spring 框架特点 3 Spring体系结构 4 Spring开发环境搭建 5 spring中IOC和DI 6 Spring中bean的生命周期 7 Spring Bean作用域 8 spring注解开