Spring概述

​ 我们常说的 Spring 实际上是指 Spring Framework,而 Spring Framework 只是 Spring 家族中的一个分支而已。Spring 是为了解决企业级应用开发的复杂性而创建的。

​ 如果我们想实现某个功能,代码量一般都是固定的,要么全自己写,要么用已有的优秀框架,而Spring不仅已经给我们提供了各种优秀组件,还提供了良好的代码组织逻辑跟业务开发流程规范框架,我们主要学习Spring中以下几点:

  • IOC/DI
  • AOP
  • 声明式事务
  • JdbcTemplate

Spirng组件

​ Spring框架具有很多组件,大约有20多个模块 。我们要记住以下7个核心组件和它的含义。

  1. Spring Core:Spring核心,它是框架最基础的部分,提供IOC和依赖注入DI特性
  2. Spring Context:Spring上下文容器,它是 BeanFactory 功能加强的一个子接口
  3. Spring Web:它提供Web应用开发的支持。
  4. Spring MVC:它针对Web应用中MVC思想的实现。
  5. Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性。
  6. Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring + Hibernate、Spring + iBatis、Spring + JDO的整合等。
  7. Spring AOP:即面向切面编程,它提供了与AOP联盟兼容的编程实现。

​ 下图就是maven导入spring后的组件:

IOC

​ IOC(Inversion of Control),中文叫做控制反转

​ Spring提出了一种思想:由Spring来负责控制对象的生命周期和对象间的关系。所有的类都会在Spring容器中登记,告诉Spring这这个类是什么,需要什么,然后Spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的Bean。所有的类的创建、销毁都由Spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是Spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转(Inversion of Controller),也可以叫依赖注入 DI(Dependency Injection)。

​ 举个例子:

public class Book {
private Integer id;
private String name;
private Double price;
//省略getter/setter
}
public class User {
private Integer id;
private String name;
private Integer age; public void doSth() {
Book book = new Book();
book.setId(1);
book.setName("故事新编");
book.setPrice((double) 20);
}
}

​ 上面这个例子中,Book对象的控制权在User里面,Book和User高度耦合,如果在其他对象中需要使用 Book 对象,得重新创建,也就是说,对象的创建、初始化、销毁等操作,统统都要开发者自己来完成。

使用 Spring 之后,我们可以将对象的创建、初始化、销毁等操作交给 Spring 容器来管理。就是说,在项目启动时,所有的 Bean 都将自己注册到 Spring 容器中去(如果有必要的话),然后如果其他 Bean 需要使用到这个 Bean ,则不需要自己去 new,而是直接去 Spring 容器去要。

什么是Bean

​ 我们本篇会一直提到Bean,先在前文给Bean做一个大概的介绍。Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象。Spring 容器会自动完成@bean对象的实例化。创建应用对象之间的协作关系的行为称为:装配(wiring),这就是依赖注入的本质。

何为控制

​ 是 bean 的创建、管理的权利,控制 bean 的整个生命周期。

何为反转

​ 把这个权利交给了 Spring 容器,而不是自己去控制,就是反转。由之前的自己主动创建对象,变成现在被动接收别人给我们的对象的过程,这就是反转。

何为依赖

​ 程序运行需要依赖外部的资源,提供程序内对象的所需要的数据、资源。

何为注入

​ 配置文件把资源从外部注入到内部,容器加载了外部的文件、对象、数据,然后把这些资源注入给程序内的对象,维护了程序内外对象之间的依赖关系。

实例1:进一步了解IOC

​ 我们在IDEA创建一个普通Maven项目,然后再pom文件中引入spring-context 依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId>
<artifactId>SpringDemo</artifactId>
<version>1.0-SNAPSHOT</version> <dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies> </project>

​ 然后在 resources 目录下创建一个 spring 的配置文件spring.xml,头文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<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"> </beans>

​ 文件中我们可以配置bean,把我们的book配置进去

<?xml version="1.0" encoding="UTF-8"?>
<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 class="org.javaboy.Book" id="book"/>
</beans>

说明:class 属性表示需要注册的 bean 的全路径,id 则表示 bean 的唯一标记,也开可以 name 属性作为 bean 的标记,在超过 99% 的情况下,id 和 name 其实是一样的。

​ 最后,我们来测试一下,创建一个Main方法来加载这个配置文件,通过 getBean 方法,从容器中去获取对象:

public class Main {
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Book book = (Book) ctx.getBean("book");
System.out.println(book);
}
}

​ 打印的结果为:Book{id=null, name='null', price=null}

说明:上面getBean中传入的是我们命名的name或id,这种方式好处是我们给它起了个名,在引入两个或多个相同对象时,有别名不至于混淆。有些教程喜欢在getBean中直接通过Class 去获取一个 Bean,如传入Book.class,如果spring.xml中引入两个book的bean,那么这种做法就会报错,所以我个人不推荐通过Class去获取Bean。

name与id之间的一些注意点

​ 上文中提到了name与id,确实,大部分时候name和id是一样的,也很少在开发中又用name又用id,但是还是要注意一些细节。

  • 配置两个相同的 id 或者 name 都不能通过。
  • 如果既配置了 id ,也配置了 name ,则两个都生效。如果id和name都没有指定,则用类全名作为name,如<bean class="com.stamen.BeanLifeCycleImpl">,则你可以通过getBean("com.stamen.BeanLifeCycleImpl")返回该实例。
  • 如果配置基本类的时候,注解和配置文件都使用的时候,注解和配置文件中 name 相同的时候, 则两个冲突,配置文件生效; 如果配置基本类的时候,注解和配置文件都使用的时候,注解和配置文件中 name 不相同的时候, 则两个不冲突,都能够生效。

属性注入

​ 上一个例子中我们明白了Spirng的IOC可以帮我们管理Bean,将对象的创建、初始化、销毁等操作交给Spring管理,使开发更加方便。此外,上一个例子中我们在spring.xml中配置了Book,最后打印的结果中我们看到Book中的属性并没有值,是null。这一小节就是了解spring是如何注入属性的,有以下几种方式:

  • 构造方法注入
  • set方法注入
  • p命名空间注入
  • 自动装配和@Autowired注解注入
  • 静态工厂注入
  • 实例工厂注入

构造方法注入

  1. 给Book添加一个有参和无参构造方法:

  2. 在xml中注入bean

    <?xml version="1.0" encoding="UTF-8"?>
    <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 class="com.wms.Demo01.Book" id="book">
    <constructor-arg index="0" value="1"/>
    <constructor-arg index="1" value="宇宙未解之谜"/>
    <constructor-arg index="2" value="39.9"/>
    </bean>
    </beans>

    或者使用name标签,更加清晰

    <bean class="com.wms.Demo01.Book" id="book">
    <constructor-arg name="id" value="1"/>
    <constructor-arg name="name" value="宇宙未解之谜"/>
    <constructor-arg name="price" value="39.9"/>
    </bean>
  3. 说明:

  • constructor-arg --> 指定构造函数的参数
  • index --> 参数的顺序
  • name --> 参数的名称
  • value --> 给参数赋值
  • 注意,你也可以按index2, 0, 1等顺序来给属性注入值,但记得 index 的值和 value 要一一对应,id就要注入id相符的值。

set方法注入

​ set方法注入方式如下:

<bean class="com.wms.Demo01.Book" id="book">
<property name="id" value="1"/>
<property name="name" value="宇宙未解之谜"/>
<property name="price" value="39.9"/>
</bean>

​ 注意这里使用的是property标签,而且name并不是Book这个对象中定义的属性,而是通过get/set方法分析出来的属性名,只是我们规范get/set方法就是get/set + 属性名。

p命名空间注入

​ p 名称空间注入,使用的比较少,它本质上也是调用了 set 方法。

<bean class="com.wms.Demo01.Book" id="book" p:id="1" p:bookName="宇宙未解之谜" p:price="39.9"></bean>

自动装配和@Autowired注解注入

​ 我将这两个放在一起讲,因为要介绍到byName和byTpye的区别。Spring提供了自动装配的功能,简化了我们的配置,自动装配默认是不打开的,常用的方式有两种,byName和byType。方式是在bean标签中加入autowire="byName"autowire="byType"

<bean class="com.wms.Demo01.Book" id="book" autowire="byType"/>

​ 后续我们还会接触到@Autowired注解,@Autowired注解可以实现自动装配,只要在对应的属性上标记该注解,但是@Autowired注解只按照byType注入。这个注解常见于Controller层。如下:

public class UserController {

    @Autowired
private IUserService userService;
}

​ 这里我们主要还是熟悉byName和byType的区别。其实byName根据被注入的名称作为bean名称作为依赖查找,并将对象设置到该属性。byType通过属性的类型查找javabean依赖的对象并为其注入。

byName和byType

  • byName按名称自动装配,当一个bean节点带有 autowire byName的属性时。

    • 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
    • 去spring容器中寻找是否有此字符串名称id的对象。
    • 如果有,就取出注入;如果没有,就报空指针异常。
  • byType按类型自动装配,使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。

@Autowired、@Qualifier和@Resource

​ 既然讲到了@Autowired,就展开讲一下一些相关的注解。(下面出现的代码来自狂神说的spring教程)

  • @Autowired

    • @Autowired是按类型自动转配的,不支持id匹配。
    • 需要导入 spring-aop的包!
    • @Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。
  • @Qualifier

    • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配。

    • @Qualifier不能单独使用。

      • 在属性上添加Qualifier注解

      • 示例:

        @Autowired
        @Qualifier(value = "cat2")
        private Cat cat;
        @Autowired
        @Qualifier(value = "dog2")
        private Dog dog;
  • @Resource

    • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
    • 其次再进行默认的byName方式进行装配;
    • 如果以上都不成功,则按byType的方式自动装配。
    • 都不成功,则报异常。

实体类:

public class User {
//如果允许对象为null,设置required = false,默认为true
@Resource(name = "cat2")
private Cat cat;
@Resource
private Dog dog;
private String str;
}

beans.xml

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/> <bean id="user" class="com.kuang.pojo.User"/>

测试:结果OK

配置文件2:beans.xml , 删掉cat2

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>

实体类上只保留注解

@Resource
private Cat cat;
@Resource
private Dog dog;

结果:OK

结论:先进行byName查找,失败;再进行byType查找,成功。

@Autowired与@Resource异同:

1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。

2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用

3、@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

静态工厂注入(TODO)

实例工厂注入(TODO)

更多属性注入方式

​ 上述的属性注入方式是比较基础的注入,实际开发中遇到的问题往往更加复杂,比如在开发过程中可能会注入跟多类型的数据,如:

  • 对象
  • 数组
  • Map

对象注入

可以通过 ref 来引用一个对象。

<bean class="com.wms.Demo01.User" id="user">
<property name="cat" ref="cat"/>
</bean>
<bean class="org.javaboy.Cat" id="cat">
<property name="name" value="小白"/>
<property name="color" value="白色"/>
</bean>

数组注入

  • array

    <bean class="com.wms.Demo01.User" id="user">
    <property name="cat" ref="cat"/>
    <property name="favorites">
    <array>
    <value>足球</value>
    <value>篮球</value>
    <value>乒乓球</value>
    </array>
    </property>
    </bean>
    <bean class="com.wms.Demo01.Cat" id="cat">
    <property name="name" value="小白"/>
    <property name="color" value="白色"/>
    </bean>
  • list

    • array 节点,也可以被 list 节点代替。

    • array 或者 list 节点中也可以是对象。

    • 即可以通过 ref 使用外部定义好的 Bean,也可以直接在 list 或者 array 节点中定义 bean。

      <bean class="com.wms.Demo01.User" id="user">
      <property name="cat" ref="cat"/>
      <property name="favorites">
      <list>
      <value>足球</value>
      <value>篮球</value>
      <value>乒乓球</value>
      </list>
      </property>
      <property name="cats">
      <list>
      <ref bean="cat"/>
      <ref bean="cat2"/>
      <bean class="com.wms.Demo01.Cat" id="cat3">
      <property name="name" value="小花"/>
      <property name="color" value="花色"/>
      </bean>
      </list>
      </property>
      </bean>
      <bean class="com.wms.Demo01.Cat" id="cat">
      <property name="name" value="小白"/>
      <property name="color" value="白色"/>
      </bean>
      <bean class="com.wms.Demo01.Cat" id="cat2">
      <property name="name" value="小黑"/>
      <property name="color" value="黑色"/>
      </bean>

Map 注入

<property name="map">
<map>
<entry key="age" value="100"/>
<entry key="name" value="abc"/>
</map>
</property>

Properties 注入

<property name="info">
<props>
<prop key="age">100</prop>
<prop key="name">abc</prop>
</props>
</property>

补充

  • 如果炫技,上面的都可以说。
  • 如果问Spring对象创建方式,要说到构造方法、静态工厂、实例工厂
  • 如果问到Spring注入方式,要说到构造方法、set方法、自动注入、p命名空间

Context

IOC 容器只是提供一个管理对象的空间而已,如何向容器中放入我们需要容器代为管理的对象呢?这就涉及到Spring的应用上下文Context

​ 工作中通过XML配置或注解 将需要管理的Bean跟Bean之间的协作关系配置好,然后利用应用上下文对象Context加载进Spring容器,容器就能为你的程序提供你想要的对象管理服务了。Spring 框架本身就提供了很多个容器的实现。我们在实例1中的Main中出现了ClassPathXmlApplicationContext,就是一种容器,还有很多容器,如下:

  1. AnnotationConfigApplicationContext:从一个或多个基于java的配置类中加载上下文定义,适用于java注解的方式。
  2. ClassPathXmlApplicationContext:从类路径下的一个或多个xml配置文件中加载上下文定义,适用于xml配置的方式。
  3. FileSystemXmlApplicationContext:从文件系统下的一个或多个xml配置文件中加载上下文定义,也就是说系统盘符中加载xml配置文件。
  4. AnnotationConfigWebApplicationContext:专门为web应用准备的,适用于注解方式。
  5. XmlWebApplicationContext:从web应用下的一个或多个xml配置文件加载上下文定义,适用于xml配置方式。

​ 比如ClassPathXmlApplicationContext,来自于我们常提到的ApplicationContext,但如果你点开源码看,就知道ClassPathXmlApplicationContext并不是直接实现ApplicationContext的,而是一层一层的递进,这是为了IOC全面性而考虑。此处的ApplicationContext也是面试中经常出现的问题,经常与BeanFactory一起作比较。

ApplicationContext & BeanFactory区别

BeanFactory接口

  • spring的原始接口,针对原始接口的实现类功能较为单一, 可以理解为 HashMap:它一般只有 get, put 两个功能。

    • Key - bean name
    • Value - bean object
  • BeanFactory接口实现类的容器,特点是每次在获得对象时才会创建对象
  • 优缺点:
    • 优点:应用启动的时候占用资源很少,对资源要求较高的应用,比较有优势;
    • 缺点:运行速度会相对来说慢一些。而且有可能会出现空指针异常的错误,而且通过Bean工厂创建的Bean生命周期会简单一些。

ApplicationContext接口

  • 每次容器启动时就会创建容器中配置的所有对象
  • 它是 BeanFactory 的子类,更好的补充并实现了 BeanFactory.ApplicationContext 多了很多功能,因为它继承了多个接口。 ApplicationContext 的里面有两个具体的实现子类,用来读取配置配件的,上面列举了5个。
  • 优缺点:
    • 优点:所有的Bean在启动的时候都进行了加载,系统运行的速度快;在系统启动的时候,可以发现系统中的配置问题。
    • 缺点:把费时的操作放到系统启动中完成,所有的对象都可以预加载,缺点就是内存占用较大。

BeanFactory & FactoryBean的区别

​ 既然提到了BeanFactory,面试中往往会用FactoryBean来“坑”面试者,这里就讲一下两者的区别。

  • BeanFactory

    • BeanFactory 以 Factory 结尾,表示它是一个工厂类(接口),BeanFacotry 是 Spring 中比较原始的Factory。
    • BeanFactory 无法支持 Spring 的许多插件,如AOP功能、Web应用等。ApplicationContext 接口由BeanFactory接口派生而来,提供了国际化访问、事件传播等多个功能。
    • BeanFactory 是 IOC 容器的核心,负责生产和管理 Bean 对象。
  • FactoryBean
    • FactoryBean 以 Bean 结尾,表示它是一个Bean。
    • FactoryBean 是工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。FactoryBean 接口对于 Spring 框架来说占用重要的地位,Spring自身就提供了70多个FactoryBean的实现。
    • 当在IOC容器中的Bean实现了 FactoryBean 后,通过getBean(String BeanName)获取到的 Bean 对象并不是 FactoryBean 的实现类对象,而是这个实现类中的 getObject() 方法返回的对象。要想获取FactoryBean的实现类,就要 getBean(String &BeanName),在BeanName之前加上 &

循环依赖

​ 从字面上来理解就是A依赖B的同时B也依赖了A,例如

自动化配置

​ 例如我有一个 UserService,我希望在自动化扫描时,这个类能够自动注册到 Spring 容器中去,那么可以给该类添加一个 @Service,作为一个标记。

​ 和 @Service 注解功能类似的注解,一共有四个:

  • @Component

  • @Repository

  • @Service

  • @Controller

    ​ 这四个中,另外三个都是基于 @Component 做出来的,而且从目前的源码来看,功能也是一致的,那么为什么要搞三个呢?主要是为了在不同的类上面添加时方便。

  • 在 Service 层上,添加注解时,使用 @Service

  • 在 Dao 层,添加注解时,使用 @Repository

  • 在 Controller 层,添加注解时,使用 @Controller

  • 在其他组件上添加注解时,使用 @Component

    ​ 添加完成后,自动化扫描有两种方式,一种就是通过 Java 代码配置自动化扫描,另一种则是通过 xml 文件来配置自动化扫描。

Java 代码配置自动扫描

​ 在项目启动中加载配置类,在配置类中,通过 @ComponentScan 注解指定要扫描的包(如果不指定,默认情况下扫描的是配置类所在的包下载的 Bean 以及配置类所在的包下的子包下的类)

XML 配置自动化扫描

<context:component-scan base-package="org.javaboy.javaconfig"/>

​ 上面这行配置表示扫描 org.javaboy.javaconfig 下的所有 Bean。当然也可以按照类来扫描。

Bean的生命周期和作用域

​ 这两个问题也是面试中常客

Bean的生命周期

​ Spring IOC 初始化跟销毁 Bean 的过程大致分为Bean定义、Bean初始化、Bean的生存期 跟 Bean的销毁4个部分。流程图如下:

浓缩一下:

Bean的生命周期,从Spring容器的创建开始,到Spring容器销毁结束。

  1. ​ 实例化Bean对象
  2. ​ 装配:填充属性
  3. ​ 回调:(可选,如果实现了Aware系列的接口,则会调用回调函数)
  4. ​ 调用预初始化方法(可选,如果实现了BeanPost-Processor的预初始化方法)
  5. ​ 初始化(init-method)
  6. ​ 调用预初始化后置方法(如果实现了BeanPost-Processor的初始化后方法)
  7. ​ 使用bean
  8. ​ 容器关闭
  9. ​ 如果实现了DisposableBean接口,则调用该方法的destory()方法。
  10. ​ 调用自定义的destory方法。

Bean的作用域

​ 在 XML 配置中注册的 Bean,或者用 Java 配置注册的 Bean,如果我多次获取,获取到的对象是否是同一个?

​ 答案是是,因为Spring中Bean默认是单例的,所以多次获取的Bean都是同一个。这里就涉及到Bean的作用域的知识点,

​ 四种常见的 Spring Bean 的作用域:

  • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。

  • prototype : 每次请求都会创建一个新的 bean 实例。

  • request : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。

  • session : 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效。

    怎么更改作用域?

    xml中:

    <bean class="org.javaboy.User" id="user" scope="prototype" />

    注解:

    @Repository
    @Scope("prototype")
    public class UserDao {
    public String hello() {
    return "userdao";
    }
    }

单点突破:Spring(上)的更多相关文章

  1. spring上传文件

    在使用spring上传文件的时候,使用的文件接收参数类型为 org.springframework.web.multipart.MultipartFile 如果该参数没有指定@RequestParam ...

  2. spring 上传 下載文件

    1,spring配置文件添加文件上传配置 <!-- 上传文件 --> <bean id="multipartResolver" class="org.s ...

  3. Spring上传文件,图片,以及常见的问题

    1. 在工程依赖库下添加文件上传jar包 commons-fileupload-1.2.2.jar commons-io-2.4.jar 2.在springMVC配置文件中配置视图解析multipar ...

  4. spring 上传文件文件的一个例子,

    /** * 类名称:UploadTest 类描述:创建人:zhang 创建时间:2015年3月13日 下午4:20:57 修改人:zhang * 修改时间:2015年3月13日 下午4:20:57 修 ...

  5. spring boot:spring security+oauth2+sso+jwt实现单点登录(spring boot 2.3.3)

    一,sso的用途 ? 1,如果有多个应用系统,用户只需要登录一次就可以访问所有相互信任的应用系统. 不需要每次输入用户名称和用户密码, 也不需要创建并记忆多套用户名称和用户密码. 2,系统管理员只需维 ...

  6. Spring 上传文件

    最近碰到一个上传文件的需求,其实之前也做过但是都是search->copy 没有细究过,这次纯手工. 先看一下需要依赖的包: <dependency> <groupId> ...

  7. 机器学习模型从windows下 spring上传到预发布会导致模型不可加载

    1.通过上传到redis,程序通过redis拉取模型,解决问题. 2.问题原因初步思考为windows下模型文件上传到 linux导致,待继续跟进查找.

  8. Spring上传报错413

    SpringMVC上传文件报错413 笔者今天工作时,运维的同事反馈我们上线不久的项目上传文件过大时,总是提示上传失败. 场景重现一下,发现报错信息显示413:Request entity too l ...

  9. 单点突破:Set

    HashSet HashSet存放的是散列值,它是按照元素的散列值来存取元素的. 元素的散列值通过hashCode方法计算 HashSet通过判断两个元素的Hash值是否相等,如果相等就会用equal ...

随机推荐

  1. AppScan扫描器的用法

    目录 AppScan 软件功能 建立一次基础的扫描 AppScan AppScan是一款非常好用且功能强大的Web 应用安全测试工具,曾以 Watchfire AppScan 的名称享誉业界,AppS ...

  2. Shodan的使用

    目录 Shodan Shodan工作原理 Shodan的使用 使用搜索过滤 Kali中安装 Shodan Kali中Shodan的使用 Shodan Shodan 是一个搜索引擎,但它与 Google ...

  3. 堆栈上的舞蹈之释放重引用(UAF) 漏洞原理实验分析

    0x01 前言 释放重引用的英文名名称是 Use After Free,也就是著名的 UAF 漏洞的全称.从字面意思可以看出 After Free 就是释放后的内存空间,Use 就是使用的意思,使用释 ...

  4. Linux提权

    讲Linux提权之前,我们先看看与Linux有关的一些知识: 我们常说的Linux系统,指的是Linux内核与各种常用软件的集合产品,全球大约有数百款的Linux系统版本,每个系统版本都有自己的特性和 ...

  5. 【python】Leetcode每日一题-删除排序链表中的重复元素2

    [python]Leetcode每日一题-删除排序链表中的重复元素2 [题目描述] 存在一个按升序排列的链表,给你这个链表的头节点 head ,请你删除链表中所有存在数字重复情况的节点,只保留原始链表 ...

  6. Thyemleaf报错: Method call: Attempted to call method *** on null context object

    翻译:方法调用:尝试在null上下文对象上调用方法*** 解释:在Thyemleaf上下中不存在所要调用的对象,相当于Java代码中的NullPointerException 解决方案: 方案1. 需 ...

  7. 数据表格 layui.table

    layui官网-表单 自动渲染 方法渲染 table.render,cols中的field是后台传递的data map.put("data",stuService.selectSt ...

  8. Java发送邮件报错:com.sun.mail.util.LineOutputStream.<init>(Ljava/io/OutputStream;Z)V

    在练习使用Java程序发送邮件的代码 运行出现了com.sun.mail.util.LineOutputStream.<init>(Ljava/io/OutputStream;Z)V报错信 ...

  9. ThinkPHP5查询-select与find理解

    出现问题 在tp5框架中判断select查询结果是否为空时,无论查询条件是否满足,判断查询结果都不为空 解析问题 select查询的是多条数据,若查询数据为空,则返回一个空的二维数组 array(ar ...

  10. 一句 Task.Result 就死锁, 这代码还怎么写?

    一:背景 1. 讲故事 前些天把 .NET 高级调试 方面的文章索引到 github 的过程中,发现了一个有意思的评论,详见 文章,截图如下: 大概就是说在 Winform 的主线程下执行 Task. ...