Spring

Posted 小企鹅推雪球!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring相关的知识,希望对你有一定的参考价值。

Spring Bean的作用域

  1. 在Spring中定义一个bean时,必须声明该bean的作用域的选项
  2. 例如,为了强制 Spring 在每次需要时都产生一个新的 bean 实例,你应该声明 bean 的作用域的属性为 prototype
  3. ,如果想让 Spring 在每次需要时都返回同一个bean实例,应该声明 bean 的作用域的属性为 singleton。
  4. Spring 框架支持以下五个作用域,分别为 singleton、prototype、request、session 和 global session,
    1. singleton作用域:在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
    2. prototype作用域:每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
    3. request作用域:每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
    4. session作用域:同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境

singleton作用域

  1. singleton 是默认的作用域
  2. 当将一个 bean 定义设置为 singleton 作用域的时候,Spring IoC 容器只会创建该 bean 定义的唯一实例。
  3. Singleton 是单例类型,就是在创建起容器时就同时自动创建了一个 bean 的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="singleton">
    <!-- collaborators and configuration for this bean go here -->
</bean>

Spring singleton 作用域样例

  1. 在创建项目的 src 文件夹中创建一个包 com.tutorialspoint
  2. 使用 Add External JARs 选项,添加所需的 Spring 库,
  3. 在 com.tutorialspoint 包中创建 Java 类 HelloWorld 和 MainApp。
  4. 在 src 文件夹中创建 Beans 配置文件 Beans.xml。
  5. 创建的所有 Java 文件和 Bean 配置文件的内容

HelloWorld.java 文件的内容

package com.tutorialspoint;
public class HelloWorld {
   private String message;
   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
}

MainApp.java 文件的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");
      objA.setMessage("I'm object A");
      objA.getMessage();
      HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
      objB.getMessage();
   }
}

singleton 作用域必需的配置文件 Beans.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-3.0.xsd">

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" 
      scope="singleton">
   </bean>

</beans>

创建源代码和 bean 配置文件完成后,我们就可以运行该应用程序并将输出以下信息

Your Message : I'm object A
Your Message : I'm object A

Spring-prototype 作用域

  1. 当一个 bean 的作用域为 Prototype,表示一个 bean 定义对应多个对象实例
  2. Prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。
  3. Prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象
  4. 注意:对有状态的 bean 应该使用 prototype 作用域,而对无状态的bean则应该使用 singleton 作用域。
  5. 为了定义 prototype 作用域,你可以在 bean 的配置文件中设置作用域的属性为 prototype
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="prototype">
   <!-- collaborators and configuration for this bean go here -->
</bean>

Spring-prototype 作用域样例

prototype 作用域必需的配置文件 Beans.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-3.0.xsd">

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld" 
      scope="prototype">
   </bean>

</beans>

Spring Bean生命周期

  1. 当一个bean被实例化时,可能需要执行一些初始化使它转换成可用状态,当 bean 不再需要,并且从容器中移除时,可能需要做一些清除工作。
  2. 为了定义安装和拆卸一个 bean,需要声明带有 init-method 和/或 destroy-method 参数的bean,
  3. init-method 属性指定一个方法,在实例化 bean 时,立即调用该方法。同样,destroy-method 指定一个方法,只有从容器中移除 bean 之后,才能调用该方法
  4. Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁

Spring Bean生命周期样例

第一:HelloWorld.java文件内容

package com.tutorialspoint;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}

第二: MainApp.java 文件的内容。需要注册一个在 AbstractApplicationContext 类中声明的关闭 hook 的 registerShutdownHook() 方法。它将确保正常关闭,并且调用相关的 destroy 方法。

package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}

第三:init 和 destroy 方法必需的配置文件 Beans.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-3.0.xsd">

   <bean id="helloWorld" 
       class="com.tutorialspoint.HelloWorld"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean>

</beans>

创建源代码和 bean 配置文件完成后,运行该应用程序,输出

Bean is going through init.
Your Message : Hello World!
Bean will destroy now.

默认的初始化和销毁方法

  1. 如果有太多具有相同名称的初始化或者销毁方法的 Bean,不需要在每一个 bean 上声明初始化方法和销毁方法
  2. 框架使用 元素中的 default-init-method 和 default-destroy-method 属性提供了灵活地配置销毁多个同名的Bean
<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-3.0.xsd"
    default-init-method="init" 
    default-destroy-method="destroy">

   <bean id="..." class="...">
       <!-- collaborators and configuration for this bean go here -->
   </bean>

</beans>

Spring Bean后置处理器

  1. Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。
  2. BeanPostProcessor ​接口定义回调方法,可以实现该方法来提供自己的实例化逻辑,依赖解析逻辑等。也可以在 ​Spring​ 容器通过插入一个或多个 ​BeanPostProcessor​ 的实现来完成实例化,配置和初始化一个​bean​之后实现一些自定义逻辑回调方法。
  3. 可以配置多个 ​BeanPostProcessor ​接口,通过设置 ​BeanPostProcessor ​实现的​ Ordered ​接口提供的​ order​ 属性来控制这些​ BeanPostProcessor​ 接口的执行顺序。
  4. BeanPostProcessor​ 可以对​ bean​(或对象)实例进行操作,这意味着 ​Spring IoC​ 容器实例化一个 ​bean​ 实例,然后 ​BeanPostProcessor​ 接口进行它们的工作。
  5. ApplicationContext​ 会自动检测由 ​BeanPostProcessor​ 接口的实现定义的 ​bean​,注册这些​ bean​ 为后置处理器,然后通过在容器中创建​ bean​,在适当的时候调用它。
  6. 自定义的​ BeanPostProcessor​ 接口实现类中,要实现以下的两个抽象方法 ​
BeanPostProcessor.postProcessBeforeInitialization(Object, String)​ 和  ​BeanPostProcessor.postProcessAfterInitialization(Object, String)​ 和,注意命名要准确

否则会出现: ​“ The type InitHelloWorld must implement the inherited abstract method BeanPostProcessor.postProcessBeforeInitialization(Object, String) ”​之类的错误

Spring Bean后置处理器样例

  1. 在 ​ApplicationContext​ 的上下文中编写,注册和使用 ​BeanPostProcessor
  2. 第一步:创建一个名称为 ​SpringExample​ 的项目,并且在创建项目的​ src ​文件夹中创建一个包 ​com.tutorialspoint
  3. 第二步:使用​ Add External JARs ​选项,添加所需的​ Spring​ 库
  4. 第三步;在 ​com.tutorialspoint ​包中创建 Java 类 ​HelloWorld​、​InitHelloWorld​​和 ​MainApp
  5. 第四步:在​ src ​文件夹中创建​ Beans ​配置文件​ Beans.xml

HelloWorld.java 文件的内容:

package com.tutorialspoint;
public class HelloWorld {
   private String message;
   public void setMessage(String message){
      this.message  = message;
   }
   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
   public void init(){
      System.out.println("Bean is going through init.");
   }
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}

实现​ BeanPostProcessor 在任何 ​bean​ 的初始化的之前和之后输入该 ​bean​ 的名称,可以在初始化 ​bean ​的之前和之后实现更复杂的逻辑,因为有两个访问内置 ​bean​ 对象的后置处理程序的方法

InitHelloWorld.java 文件的内容:

package com.tutorialspoint;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InitHelloWorld implements BeanPostProcessor {
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("BeforeInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      System.out.println("AfterInitialization : " + beanName);
      return bean;  // you can return any other object as well
   }
}

MainApp.java 文件的内容:需要注册一个在 ​AbstractApplicationContext​ 类中声明的关闭​ hook​ 的 ​registerShutdownHook() ​方法。它将确保正常关闭,并且调用相关的 ​destroy​ 方法。

package com.tutorialspoint;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
      context.registerShutdownHook();
   }
}

init​ 和 ​destroy​ 方法需要的配置文件 Beans.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-3.0.xsd"><bean id="helloWorld" class="com.tutorialspoint.HelloWorld"
       init-method="init" destroy-method="destroy">
       <property name="message" value="Hello World!"/>
   </bean><bean class="com.tutorialspoint.InitHelloWorld" /></beans>

创建源代码和 ​bean​ 配置文件完成后,运行该应用程序,输出

BeforeInitialization : helloWorld
Bean is going through init.
AfterInitialization : helloWorld
Your Message : Hello World!
Bean will destroy now.

Spring Bean定义继承

  1. bean 定义可以包含很多的配置信息,包括构造函数的参数,属性值,容器的具体信息例如初始化方法,静态工厂方法名,等等。
  2. 子 bean 的定义继承父定义的配置数据。子定义可以根据需要重写一些值,或者添加其他值。
  3. Spring Bean 定义的继承与 Java 类的继承无关,但是继承的概念是一样的
  4. 可以定义一个父 bean 的定义作为模板和其他子 bean 就可以从父 bean 中继承所需的配置。
  5. 当使用基于 XML 的配置元数据时,通过使用父属性,指定父 bean 作为该属性的值来表明子 bean 的定义。

Spring Bean定义继承样例

  1. 创建一个名称为 SpringExample 的项目,并且在创建项目的 src 文件夹中创建一个包 com.tutorialspoint。
  2. 使用 Add External JARs 选项,添加所需的 Spring 库
  3. 在 com.tutorialspoint 包中创建 Java 类 HelloWorld、HelloIndia 和 MainApp。
  4. 在 src 文件夹中创建 Beans 配置文件 Beans.xml。

第一;配置文件 Beans.xml

  1. 在Beans.xml配置文件中我们定义有两个属性 message1 和 message2 的 “helloWorld” bean。
  2. 使用 parent 属性把 “helloIndia” bean 定义为 “helloWorld” bean 的孩子。这个子 bean 继承 message2 的属性,重写 message1 的属性,并且引入一个属性 message3。
<?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-3.0.xsd">

   <bean id="helloWorld" class="com.tutorialspoint.HelloWorld">
      <property name="message1" value="Hello World!"/>
      <property name="message2" value="Hello Second World!"/>
   </bean>

   <bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="helloWorld">
      <property name="message1" value="Hello India!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

</beans>

第二: HelloWorld.java 文件的内容:

package com.tutorialspoint;
public class HelloWorld {
   private String message1;
   private String message2;
   public void setMessage1(String message){
      this.message1  = message;
   }
   public void setMessage2(String message){
      this.message2  = message;
   }
   public void getMessage1(){
      System.out.println("World Message1 : " + message1);
   }
   public void getMessage2(){
      System.out.println("World Message2 : " + message2);
   }
}

第三: HelloIndia.java 文件的内容:

package com.tutorialspoint;

public class HelloIndia {
   private String message1;
   private String message2;
   private String message3;

   public void setMessage1(String message){
      this.message1  = message;
   }

   public void setMessage2(String message){
      this.message2  = message;
   }

   public void setMessage3(String message){
      this.message3  = message;
   }

   public void getMessage1(){
      System.out.println("India Message1 : " + message1);
   }

   public void getMessage2(){
      System.out.println("India Message2 : " + message2);
   }

   public void getMessage3(){
      System.out.println("India Message3 : " + message3);
   }
}

MainApp.java 文件的内容:

package com.tutorialspoint;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");

      HelloWorld objA = (HelloWorld) context.getBean("helloWorld");

      objA.getMessage1();
      objA.getMessage2();

      HelloIndia objB = (HelloIndia) context.getBean("helloIndia");
      objB.getMessage1();
      objB.getMessage2();
      objB.getMessage3();
   }
}

创建源代码和 bean 配置文件完成后,运行程序,输出以下信息

World Message1 : Hello World!
World Message2 : Hello Second World!
India Message1 : Hello India!
India Message2 : Hello Second World!
India Message3 : Namaste India!

**注意:**创建 “helloIndia” bean 的同时并没有传递 message2,但是由于 Bean 定义的继承,所以它传递了 message2。

Bean定义模板

  1. 创建一个 Bean 定义模板,可以被其他子 bean 定义使用
  2. 在定义一个 Bean 定义模板时,不应该指定类的属性,而应该指定带 true 值的抽象属性
<?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-3.0.xsd">

   <bean id="beanTeamplate" abstract="true">
      <property name="message1" value="Hello World!"/>
      <property name="message2" value="Hello Second World!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

   <bean id="helloIndia" class="com.tutorialspoint.HelloIndia" parent="beanTeamplate">
      <property name="message1" value="Hello India!"/>
      <property name="message3" value="Namaste India!"/>
   </bean>

</beans>
  1. 父 bean 自身不能被实例化,因为它是不完整的,而且它也被明确地标记为抽象的。当一个定义是抽象的,它仅仅作为一个纯粹的模板 bean 定义来使用的,充当子定义的父定义使用。

以上是关于Spring的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot:thymeleaf 没有正确渲染片段

What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段

spring练习,在Eclipse搭建的Spring开发环境中,使用set注入方式,实现对象的依赖关系,通过ClassPathXmlApplicationContext实体类获取Bean对象(代码片段

Spring Rest 文档。片段生成时 UTF-8 中间字节无效 [重复]

解决spring-boot启动中碰到的问题:Cannot determine embedded database driver class for database type NONE(转)(代码片段

一张图帮你记忆,Spring Boot 应用在启动阶段执行代码的几种方式