Spring学习(总结、笔记)

零、自己的总结

0.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

使用注解时

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

0.2 XML的配置

bean标签

作用: 用于配置对象让spring来创建的。 默认情况下它调用的是类中的无参构造函数。如果没有无参构造函数则不能创建成功。 

代码

 <bean id="accountService"  class="com.itheima.service.impl.AccountServiceImpl" scope=""  init-method="" destroy-method="">
	<property name=""  value="" | ref=""></property>
</bean>

理解

属性:

  1. id:给对象在容器中提供一个唯一标识。用于获取对象。
  2. class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造数。
  3. scope:指定对象的作用范围。
    1. singleton :默认值,单例的.
    2. prototype :多例的。
    3. request :WEB项目中,Spring创建一个Bean的对象,将对象存入到request域中
    4. session :WEB项目中,Spring创建一个Bean的对象,将对象存入到session域中
    5. global session :WEB项目中,应用在Portlet环境.如果没有Portlet环境那globalSession相当于session.
  4. init-method:指定类中的初始化方法名称。
  5. destroy-method:指定类中销毁方法名称。

0.3 一些概念

  1. 有下面三个重要的方法把配置元数据提供给 Spring 容器
    基于 XML 的配置文件
    基于注解的配置
    基于 Java 的配置

  2. applicationContext & BeanFactory区别
    BeanFactory接口
    (1) spring的原始接口,针对原始接口的实现类功能较为单一
    (2)BeanFactory接口实现类的容器,特点是每次在获得对象时才会创建对象

    ApplicationContext接口
    (1)每次容器启动时就会创建容器中配置的所有对象
    (2)提供了更多功能
    (3)从类路径下加载配置文件: ClassPathXmlApplicationContext
    硬盘的绝对路径下加载配置文件:FileSystemXmlApplication

  3. Spring 的优良特性

  • 非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API

  • 控制反转:IOC——Inversion of Control,指的是将对象的创建权交给 Spring 去创建。使用 Spring 之前,对象的创建都是由我们自己在代码中new创建。而使用 Spring 之后。对象的创建都是给了 Spring 框架

  • 依赖注入:DI——Dependency Injection,是指依赖的对象不需要手动调用 setXX 方法去设置,而是通过配置赋值。

  • 面向切面编程:Aspect Oriented Programming——AOP

  • 容器:Spring 是一个容器,因为它包含并且管理应用对象的生命周期

  • 组件化:Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用XML和Java注解组合这些对象。

  • 一站式:在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库(实际上 Spring 自身也提供了表述层的 SpringMVC 和持久层的 Spring JDBC)

控制反转

控制反转IOC——Inversion of Control,指的是将对象的创建权交给Spring去实现IOC思想需要DI做支持。使用Spring之前,对象的创建都是由我们自己在代码中new创建。而使用Spring之后。对象的创建都是由给了Spring框架。

依赖注入

依赖注入DI——Dependency Injection,是指依赖的对象不需要手动调用setXX方法去设值,而是通过配置赋值。
spring这个容器中,替你管理着一系列的类,前提是你需要将这些类交给spring容器进行管理,然后在你需要的时候,不是自己去定义,而是直接向spring容器索取,当spring容器知道你的需求之后,就会去它所管理的组件中进行查找,然后直接给你所需要的组件.

容器

容器:Spring可以看作是一个装有对象的map集合,因为它包含并且管理应用对象的生命周期

耦合概念

  1. 什么是程序的耦合
    模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差。
    在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。
    内聚与耦合:内聚标志一个模块内各个元素彼此结合的紧密程度,它是信息隐蔽和局部化概念的自然扩展。它描述的是模块内的功能联系。
    在进行软件设计时,应力争做到高内聚低耦合

  2. 怎么降低耦合?
    解耦:降低程序间的依赖关系,实际开发中,应该做到:编译期不依赖运行时才依赖
    解耦的思路:工厂模式解耦
    第一步:使用反射来创建对象,而避免使用new关键字。
    第二步:通过读取配置文件来获取要创建的对象全限定类名

  3. 工厂模式解耦
    创建一个Bean对象的工厂。
    第一个:需要一个配置文件来配置我们需要创建对象的属性,配置的内容:唯一标识 = 全限定类名(key=value)
    第二个:通过读取配置文件中配置的内容,反射创建对象,我的配置文件可以是xml也可以是properties

一、Spring概述

核心是什么?

  1. Spring的核心是控制反转(IoC)和面向切面(AOP)
    控制反转:把创建对象的事交给spring框架来做,spring创建的对象存在一个类似于map集合的IoC容器中。

Spring是什么?

**轻量级开源框架**,使用Spring开发可以将Bean对象,Dao组件对象,Service组件**对象等交给Spring容器来管理**,这样使得很多复杂的代码在Spring中开发却变得非常的优雅和简洁,**有效的降低代码的耦合度**,极大的**方便项目的后期维护**、**升级和扩展**。

Spring的优势

  1. 方便解耦,简化开发(高内聚低耦合)
    Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护交给Spring管理spring工厂是用于生成bean
  2. AOP编程的支持
    Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
  3. 声明式事务的支持
    只需要通过配置就可以完成对事务的管理,而无需手动编程,提高开发效率和质量。
  4. 方便程序的测试
    Spring对Junit4支持,可以通过注解方便的测试Spring程序
  5. 方便集成各种优秀框架
    Spring不排斥各种优秀的开源框架,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持。
  6. 降低JavaEE API的使用难度
    Spring对JavaEE API(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低。
  7. Java源码是经典学习范例
    Spring的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。它的源代码无意是Java技术的最佳实践的范例。

二、控制反转(IOC)

2.1 IOC入门案例

pom.xml文,导入jar包

<?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>com.Ljj</groupId>
    <artifactId>day01_Spring_IOC</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>
</project>

配置文件applicationContext.xml,applicationContext.xml放在resources文件下面。

<?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">
    <!-- 配置service 
        bean标签:配置需要创建的对象,并且存入IoC容器中
            id :相当于命名,用于之后从spring容器获得实例时使用的
            class :需要创建实例的全限定类名
    -->
    <bean id="userService" class="com.ljj.Service.UserServiceImpl"></bean>
</beans>

测试

   @Test
    public void testIOC(){
        //1.获得容器
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        //2.获得对象。不需要自己new,从spring容器获得
        //括号中的userService指的就是配置文件中的id属性
        UserService userService = (UserService) applicationContext.getBean("userService");

2.2 DI入门案例

UserDao:

public interface UserDao {
    public void save();
}

UserDaoImpl:


public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("di add user");
    }
}

UserService接口

public interface UserService {
    public abstract void addUser();
}
public class UserServiceImpl implements UserService {
    // 之前:接口 = new 实现类
    // 现在:接口 + setter
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    @Override
    public void addUser(){
        this.userDao.save();
    }
}

配置文件bean.xml

<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">
    <!-- 
    模拟spring执行过程
        创建service实例:UserService userService = new UserServiceImpl(); IoC  <bean>
        创建dao实例:UserDao userDao = new UserDaoImpl();         		IoC <bean>
        将dao设置给service:userService.setUserDao(userDao);    		 	DI   <property>

     <property> 用于进行属性注入
         name: bean的属性名,通过setter方法获得
             setBookDao ##> BookDao  ##> bookDao
         ref :另一个bean的id值的引用
     -->
     
    <!-- 创建service -->
    <bean id="userService" class="com.ljj.Service.UserServiceImpl">
        <property name="userDao" ref="UserDao"></property>
    </bean>
    
    <!-- 创建dao实例 -->
    <bean id="userDao" class="com.ljj.Dao.UserDaoImpl"></bean>
</beans>

测试

    @Test
    public void demo01(){
        //1.获得容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
        //2.创建对象
        UserService userService = (UserService) applicationContext.getBean("userService")
        //3.调用方法
        userService.addUser();
    }

2.3 Spring BeanFactory 容器

  1. 它主要的功能是为依赖注入 (DI) 提供支持,这个容器接口在 org.springframework.beans.factory.BeanFactor 中被定义。

  2. 在 Spring 中,有大量对 BeanFactory 接口的实现。其中,最常被使用的是 XmlBeanFactory 类。这个容器从一个 XML 文件中读取配置元数据,由这些元数据来生成一个被配置化的系统或者应用。

  3. 第一步:利用框架提供的 XmlBeanFactory() API 去生成工厂 bean 以及利用 ClassPathResource() API 去加载在路径 CLASSPATH 下可用的 bean 配置文件。XmlBeanFactory() API 负责创建并初始化所有的对象,即在配置文件中提到的 bean。

  4. 第二步:利用第一步生成的 bean 工厂对象的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象,该对象最后可以用于实际的对象。一旦得到这个对象,你就可以利用这个对象来调用任何方法。

2.4 Spring ApplicationContext 容器

  1. Application Context 是 BeanFactory 的子接口,也被称为 Spring 上下文。和 BeanFactory 类似,它可以加载配置文件中定义的 bean,将所有的 bean 集中在一起,当有请求的时候分配 bean。

  2. 最常被使用的 ApplicationContext 接口实现类

    1. FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。需要提供给构造器 XML 文件的完整路径。它可以加载磁盘任意路径下的配置文件(必须有访问权限),
    2. ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。它可以加载类路径下的配置文件,要求配置文件必须在类路径下。
    3. WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。
    4. AnnotationConfigApplicationContext:它是用于读取注解创建容器的。
  3. 主程序代码

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new FileSystemXmlApplicationContext
            ("C:/Users/ZARA/workspace/HelloSpring/src/Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
      obj.getMessage();
   }
}

需要注意以下两点:

第一步生成工厂对象。加载完指定路径下 bean 配置文件后,利用框架提供的 FileSystemXmlApplicationContext API 去生成工厂 bean。FileSystemXmlApplicationContext 负责生成和初始化所有的对象,比如,所有在 XML bean 配置文件中的 bean。

第二步利用第一步生成的上下文中的 getBean() 方法得到所需要的 bean。 这个方法通过配置文件中的 bean ID 来返回一个真正的对象。一旦得到这个对象,就可以利用这个对象来调用任何方法。

2.5 Spring Bean 定义

2.5.1 一些概念

bean 是一个被实例化组装,并通过 Spring IoC 容器所管理的对象。这些 bean 是由用容器提供的配置元数据创建

  1. bean 定义包含称为配置元数据的信息,下述容器也需要知道配置元数据
    如何创建一个 bean
    bean 的生命周期的详细信息
    bean 的依赖关系

  2. Spring 配置元数据
    Spring IoC 容器完全由实际编写的配置元数据的格式解耦。有下面三个重要的方法把配置元数据提供给 Spring 容器
    基于 XML 的配置文件
    基于注解的配置
    基于 Java 的配置

  3. Bean 与 Spring 容器的关系

    1. Spring容器读取Bean配置信息
    2. Spring容器根据Bean注册表实例化Bean
    3. 将Bean的实例放到Spring容器中
    4. 使用Bean

2.5.2 bean标签

配置如下:

 <bean id="accountService"  class="com.itheima.service.impl.AccountServiceImpl" scope=""  init-method="" destroy-method="">
	<property name=""  value="" | ref=""></property>
</bean>
  1. bean的属性
    id:指的是创建出的bean对象的名称
    class:这个属性是强制性的,并且指定用来创建 bean 的 bean 类。
    name:这个属性指定唯一的 bean 标识符。在基于 XML 的配置元数中,你可以使用 ID 和/或 name 属性来指定 bean 标识符。
    scope:这个属性指定由特定的 bean 定义创建的对象的作用域
    最常用的是singleton(单例)、prototype(多例)。
    constructor-arg构造函数注入依赖关系。
    properties:它是用来注入依赖关系的

2.5.2 实例化bean的三种方式

  1. 使用默认构造函数创建
    在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
<bean id="accountService" class="com.ljj.service.impl.AccountServiceImpl"></bean>
  1. 第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
<bean id="instanceFactory" class="com.itheima.factory.InstanceFactory"	></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
  1. 第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
 <bean id="accountService" class="com.itheima.factory.StaticFactory" factory-method="getAccountService"></bean>

2.6 Spring Bean 作用域

scope属性

  1. 作用域指的是bean标签的scope属性:
    作用:用于指定bean的作用范围
    取值: 常用的就是singleton的和prototype的。
    细节:对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。
<bean id="..." class="..." scope="singleton">
    <!-- collaborators and configuration for this bean go here -->
</bean>

5种作用域

作用域描述
singleton在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()
request每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session同一个HTTP Session共享一个Bean,不同Session使用不同的Bean,仅适用于WebApplicationContext环境
global-session一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext环境
  1. singleton 作用域
    当一个bean的作用域为 Singleton,那么 Spring IoC 容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配,则只会返回 bean 的同一实例。
    Singleton 是单例类型,就是在创建起容器时就同时自动创建了一个 bean 的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton 作用域是 Spring 中的缺省作用域。

  2. prototype 作用域
    当一个 bean 的作用域为 Prototype,表示一个 bean 定义对应多个对象实例。Prototype 作用域的 bean 会导致在每次对该 bean 请求(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法)时都会创建一个新的 bean 实例。
    Prototype 是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。

2.7 Spring Bean 生命周期

  1. 当一个 bean 被实例化时,它可能需要执行一些初始化使它转换成可用状态。同样,当 bean 不再需要,并且从容器中移除时,可能需要做一些清除工作。Bean的生命周期可以表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁
  2. 初始化
    init-method 属性指定一个方法,在实例化 bean 时,立即调用该方法。在基于 XML 的配置元数据的情况下,你可以使用 init-method 属性来指定带有 void 无参数方法的名称。
<bean id="exampleBean" class="examples.ExampleBean" init-method="init"/>
  1. 销毁
    destroy-method 指定一个方法,只有从容器中移除 bean 之后,才能调用该方法。在基于 XML 的配置元数据的情况下,你可以使用 destroy-method 属性来指定带有 void 无参数方法的名称。
<bean id="exampleBean" class="examples.ExampleBean" destroy-method="destroy"/>

单例和多例的生命周期

理解 Spring bean 的生命周期很容易。当一个 bean 被实例化时,它可能需要执行一些初始化使它转换成可用状态。同样,当 bean 不再需要,并且从容器中移除时,可能需要做一些清除工作。

  1. 单例对象:scope=“singleton”
    出生:当容器创建时对象出生
    活着:只要容器还在,对象一直活着
    死亡:容器销毁,对象消亡
    总结:单例对象的生命周期和容器相同

  2. 多例对象:scope=“prototype”
    出生:当我们使用对象时spring框架为我们创建
    活着:对象只要是在使用过程中就一直活着。
    死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收

  3. 默认的初始化和销毁方法
    如果你有太多具有相同名称的初始化或者销毁方法的 Bean,那么你不需要在每一个 bean 上声明初始化方法和销毁方法。框架使用 元素中的 default-init-method 和 default-destroy-method 属性提供了灵活地配置这种情况,如下所示:

<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>
  1. 方法执行顺序
    后置处理器——>初始化方法(init-method)——>后置处理器——>构造函数——>销毁方法(destroy-method)
BeforeInitialization : helloWorld
Bean is going through init.
AfterInitialization : helloWorld
Your Message : Hello World!
Bean will destroy now

2.8 Spring定义继承

bean 定义可以包含很多的配置信息,包括构造函数的参数,属性值,容器的具体信息例如初始化方法,静态工厂方法名,等等。子 bean 的定义继承父定义的配置数据。子定义可以根据需要重写一些值,或者添加其他值。
你可以创建一个 Bean 定义模板,不需要花太多功夫它就可以被其他子 bean 定义使用。在定义一个 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>

三、依赖注入DI

  1. 依赖注入用来装配Bean,通过依赖注入的方式来管理Bean之间的依赖关系
    每个基于应用程序的 java 都有几个对象,由这些对象一起工作来呈现出终端用户所看到的工作的应用程序。当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能独立于其他 Java 类来增加这些类重用的可能性,并且在做单元测试时,测试独立于其他类的独立性。依赖注入(或有时称为布线)有助于把这些类粘合在一起,同时保持他们独立。

  2. 依赖注入方式三种装配方式:
    基于xml装配:构造方法setter方法
    基于注解装配

  3. 依赖注入:Dependency Injection(DI),通过依赖注入的方式来管理Bean之间的依赖关系。
    IOC的作用:降低程序间的耦合(依赖关系)
    依赖关系的管理:以后都交给spring来维护,在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明,依赖关系的维护,就称之为依赖注入
    能注入的数据:有三类
    1.基本类型和String
    2.其他bean类型(在配置文件中或者注解配置过的bean)
    3.复杂类型/集合类型

  4. 注入的方式:有三种
    第一种:使用构造函数提供
    第二种:使用set方法提供
    第三种:使用注解提供(明天的内容)

3.1 构造函数依赖注入

  1. 容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。

  2. 使用的标签:constructor-arg
    标签出现的位置:bean标签的内部
    标签中的属性:

    1. type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
    2. index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
    3. name:用于指定给构造函数中指定名称的参数赋值(常用的 )。
      以上三个用于指定给构造函数中哪个参数赋值
    4. value:用于提供基本类型和String类型的数据
    5. ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
  3. 构造函数注入优劣势

    1. 优势:
      在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
    2. 弊端:
      改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。

3.1.1 示例

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">
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <constructor-arg ref="spellChecker"/>
   </bean>
   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>
</beans>

这是 TextEditor.java 文件的内容:

public class TextEditor {
   private SpellChecker spellChecker;
   public TextEditor(SpellChecker spellChecker) {
      System.out.println("Inside TextEditor constructor." );
      this.spellChecker = spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

下面是另一个依赖类文件 SpellChecker.java 的内容:

public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   } 
}

以下是 MainApp.java 文件的内容:

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");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}

输出结果:

Inside SpellChecker constructor.
Inside TextEditor constructor.
Inside checkSpelling.

根据结果我们可以看出先执行SpellChecker 的构造函数,再执行TextEditor 的构造函数,最后调用TextEditor的spellCheck方法。

3.2 设值函数的依赖注入

  1. 当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。

  2. set方法注入(更常用的方式)
    涉及的标签:property
    出现的位置:bean标签的内部
    标签的属性:

    1. name:用于指定注入时所调用的set方法名称
    2. value:用于提供基本类型和String类型的数据
    3. ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
  3. 优劣势

    1. 优势:
      创建对象时没有明确的限制,可以直接使用默认构造函数
    2. 弊端:
      如果有某个成员必须有值,则获取对象是有可能set方法没有执行。

3.2.1 set方法注入示例

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">
   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <property name="spellChecker" ref="spellChecker"/>
   </bean>
   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>
</beans>

TextEditor.java 文件的内容:

public class TextEditor {
   private SpellChecker spellChecker;
   // a setter method to inject the dependency.
   public void setSpellChecker(SpellChecker spellChecker) {
      System.out.println("Inside setSpellChecker." );
      this.spellChecker = spellChecker;
   }
   // a getter method to return spellChecker
   public SpellChecker getSpellChecker() {
      return spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

在这里,你需要检查设值函数方法的名称转换。要设置一个变量 spellChecker,我们使用 setSpellChecker() 方法,该方法与 Java POJO 类非常相似。

让我们创建另一个依赖类文件 SpellChecker.java 的内容:

public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling() {
      System.out.println("Inside checkSpelling." );
   }  
}

以下是 MainApp.java 文件的内容:

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");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}

下面是配置文件 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">

   <!-- Definition for textEditor bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <property name="spellChecker" ref="spellChecker"/>
   </bean>

   <!-- Definition for spellChecker bean -->
   <bean id="spellChecker" class="com.tutorialspoint.SpellChecker">
   </bean>

</beans>

你应该注意定义在基于构造函数注入和基于设值函数注入中的 Beans.xml 文件的区别。唯一的区别就是在基于构造函数注入中,我们使用的是〈bean〉标签中的〈constructor-arg〉元素,而在基于设值函数的注入中,我们使用的是〈bean〉标签中的〈property〉元素。

第二个你需要注意的点是,如果你要把一个引用传递给一个对象,那么你需要使用 标签的 ref 属性,而如果你要直接传递一个值,那么你应该使用 value 属性。

输出结果:

Inside SpellChecker constructor.
Inside setSpellChecker.
Inside checkSpelling.

结果表示执行顺序:SpellChecker 的构造函数、TextEditor 的set方法、SpellChecker的checkSpelling方法。

3.2.2 p-namespace 注入示例

如果你有许多的设值函数方法,那么在 XML 配置文件中使用 p-namespace 是非常方便的。
标签的标准 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="john-classic" class="com.example.Person">
      <property name="name" value="John Doe"/>
      <property name="spouse" ref="jane"/>
   </bean>

   <bean name="jane" class="com.example.Person">
      <property name="name" value="John Doe"/>
   </bean>

</beans>

上述 XML 配置文件可以使用 p-namespace 以一种更简洁的方式重写,如下所示:

<?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:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="john-classic" class="com.example.Person"
      p:name="John Doe"
      p:spouse-ref="jane"/>
   </bean>

   <bean name="jane" class="com.example.Person"
      p:name="John Doe"/>
   </bean>

</beans>

在这里,你不应该区别指定原始值和带有 p-namespace 的对象引用。-ref 部分表明这不是一个直接的值,而是对另一个 bean 的引用。

3.2.3 注入内部 Beans示例

注入内部 Beans
正如你所知道的 Java 内部类是在其他类的范围内被定义的,同理,inner beans 是在其他 bean 的范围内定义的 bean。因此或元素中的元素称为内部bean,如下所示。

下面是使用内部 bean 为基于 setter 注入进行配置的配置文件 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">

   <!-- Definition for textEditor bean using inner bean -->
   <bean id="textEditor" class="com.tutorialspoint.TextEditor">
      <property name="spellChecker">
         <bean id="spellChecker" class="com.tutorialspoint.SpellChecker"/>
       </property>
   </bean>

</beans>

这里是 TextEditor.java 文件的内容:

public class TextEditor {
   private SpellChecker spellChecker;
   // a setter method to inject the dependency.
   public void setSpellChecker(SpellChecker spellChecker) {
      System.out.println("Inside setSpellChecker." );
      this.spellChecker = spellChecker;
   }  
   // a getter method to return spellChecker
   public SpellChecker getSpellChecker() {
      return spellChecker;
   }
   public void spellCheck() {
      spellChecker.checkSpelling();
   }
}

下面是另一个依赖的类文件 SpellChecker.java 内容:

public class SpellChecker {
   public SpellChecker(){
      System.out.println("Inside SpellChecker constructor." );
   }
   public void checkSpelling(){
      System.out.println("Inside checkSpelling." );
   }   
}

下面是 MainApp.java 文件的内容:

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");
      TextEditor te = (TextEditor) context.getBean("textEditor");
      te.spellCheck();
   }
}

输出结果:

Inside SpellChecker constructor.
Inside setSpellChecker.
Inside checkSpelling.

3.3集合类型依赖注入

  1. 涉及的标签:property
    出现的位置:bean标签的内部

    1. 用于给List结构集合注入的标签:
      list array set
    2. 用于个Map结构集合注入的标签:
      map props
      结构相同,标签可以互换
  2. 你可以使用或来连接任何 java.util.Collection 的实现或数组。你会遇到两种情况
    (1)传递集合中直接的值
    (2)传递一个 bean 的引用作为集合的元素。

3.3.1 直接的值注入示例

下面是配置所有类型的集合的配置文件 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">
   <!-- Definition for javaCollection -->
   <bean id="javaCollection" class="com.tutorialspoint.JavaCollection">
      <!-- results in a setAddressList(java.util.List) call -->
      
      <property name="addressList">
         <list>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
         </list>
      </property>
      <!-- results in a setAddressSet(java.util.Set) call -->
      <property name="addressSet">
         <set>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
        </set>
      </property>
      <!-- results in a setAddressMap(java.util.Map) call -->
      <property name="addressMap">
         <map>
            <entry key="1" value="INDIA"/>
            <entry key="2" value="Pakistan"/>
            <entry key="3" value="USA"/>
            <entry key="4" value="USA"/>
         </map>
      </property>
      <!-- results in a setAddressProp(java.util.Properties) call -->
      <property name="addressProp">
         <props>
            <prop key="one">INDIA</prop>
            <prop key="two">Pakistan</prop>
            <prop key="three">USA</prop>
            <prop key="four">USA</prop>
         </props>
      </property>
   </bean>
</beans>

这里是 JavaCollection.java 文件的内容:

import java.util.*;
public class JavaCollection {
   List addressList;
   Set  addressSet;
   Map  addressMap;
   Properties addressProp;
   // a setter method to set List
   public void setAddressList(List addressList) {
      this.addressList = addressList;
   }
   // prints and returns all the elements of the list.
   public List getAddressList() {
      System.out.println("List Elements :"  + addressList);
      return addressList;
   }
   // a setter method to set Set
   public void setAddressSet(Set addressSet) {
      this.addressSet = addressSet;
   }
   // prints and returns all the elements of the Set.
   public Set getAddressSet() {
      System.out.println("Set Elements :"  + addressSet);
      return addressSet;
   }
   // a setter method to set Map
   public void setAddressMap(Map addressMap) {
      this.addressMap = addressMap;
   }  
   // prints and returns all the elements of the Map.
   public Map getAddressMap() {
      System.out.println("Map Elements :"  + addressMap);
      return addressMap;
   }
   // a setter method to set Property
   public void setAddressProp(Properties addressProp) {
      this.addressProp = addressProp;
   } 
   // prints and returns all the elements of the Property.
   public Properties getAddressProp() {
      System.out.println("Property Elements :"  + addressProp);
      return addressProp;
   }
}

下面是 MainApp.java 文件的内容:

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");
      JavaCollection jc=(JavaCollection)context.getBean("javaCollection");
      jc.getAddressList();
      jc.getAddressSet();
      jc.getAddressMap();
      jc.getAddressProp();
   }
}

运行结果:

List Elements :[INDIA, Pakistan, USA, USA]
Set Elements :[INDIA, Pakistan, USA]
Map Elements :{1=INDIA, 2=Pakistan, 3=USA, 4=USA}
Property Elements :{two=Pakistan, one=INDIA, three=USA, four=USA}

3.3.2 注入 Bean 引用

下面的 Bean 定义将帮助你理解如何注入 bean 的引用作为集合的元素。甚至你可以将引用和值混合在一起,如下所示:

下面是配置所有类型的集合的配置文件 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 Definition to handle references and values -->
   <bean id="..." class="...">

      <!-- Passing bean reference  for java.util.List -->
      <property name="addressList">
         <list>
            <ref bean="address1"/>
            <ref bean="address2"/>
            <value>Pakistan</value>
         </list>
      </property>

      <!-- Passing bean reference  for java.util.Set -->
      <property name="addressSet">
         <set>
            <ref bean="address1"/>
            <ref bean="address2"/>
            <value>Pakistan</value>
         </set>
      </property>

      <!-- Passing bean reference  for java.util.Map -->
      <property name="addressMap">
         <map>
            <entry key="one" value="INDIA"/>
            <entry key ="two" value-ref="address1"/>
            <entry key ="three" value-ref="address2"/>
         </map>
      </property>

   </bean>

</beans>

为了使用上面的 bean 定义,你需要定义 setter 方法,它们应该也能够使用这种方式来处理引用。

1.注入 null 和空字符串的值

如果你需要传递一个空字符串作为值,那么你可以传递它,如下所示:

<bean id="..." class="exampleBean">
   <property name="email" value=""/>
</bean>

这个例子相当于 Java 代码:exampleBean.setEmail("")。

如果你需要传递一个 NULL 值,那么你可以传递它,如下所示:

<bean id="..." class="exampleBean">
   <property name="email"><null/></property>
</bean>

这个例子相当于 Java 代码:exampleBean.setEmail(null)。

3.4 基于注解依赖注入

  1. 注解:就是一个类,使用@注解名称

  2. 开发中:使用注解 取代 xml配置文件。

    1. @Component 取代< bean class= " " >
      @Component( “id” ) 取代 < bean id = " " class = " ">
    2. web开发,提供3个@Component注解衍生注解(功能一样)取代
      @Repository :dao层
      @Service:service层
      @Controller:web层
  3. 依赖注入,给私有字段设值,也可以给setter方法设值
    普通值:@Value(" ")
    引用值:
    方式1:按照【类型】注入
    @Autowired
    方式2:按照【名称】注入1
    @Autowired
    @Qualifier(“名称”)
    方式3:按照【名称】注入2
    @Resource(“名称”)

  4. 生命周期
    初始化:@PostConstruct
    销毁:@PreDestroy

  5. 作用域
    @Scope(“prototype”) 多例
    @Scope(“singleton”) 单例

四、常用注解

4.1 前提准备

使用注解配置时候需要使用到的标签

context标签

1、添加约束

基于注解整合时,导入约束时需要多导入一个context名称空间下的约
xmlns:context="http://www.springframework.org/schema/context"

2、开启注解和开启注解扫描

开启Spring注解
<context:annotation-config/>
告知spring创建容器时要扫描的包 
<context:component-scan base-package="com.itheima"></context:component-scan>

其它功能

扫描配置文件时的配置

扫描db.properties配置文
<context:property-placeholder location="classpath:db.properties"/>

曾经XML的配置:

 <bean id="accountService"  class="com.itheima.service.impl.AccountServiceImpl" scope=""  init-method="" destroy-method="">
	<property name=""  value="" | ref=""></property>
</bean>

注解分成了四个方面:
1.用于创建对象的
2.用于注入数据的
3.用于改变作用范围的
4.和生命周期相关

4.2 标注set方法

@Required 注解

@Required 注解应用于 bean 属性的 setter 方法,它表明受影响的 bean 属性在配置时必须放在 XML 配置文件中,否则容器就会抛出一个 BeanInitializationException 异常。下面显示的是一个使用 @Required 注释的示例。

下面是 Student.java 文件的内容:

import org.springframework.beans.factory.annotation.Required;
public class Student {
   private Integer age;
   private String name;
   @Required
   public void setAge(Integer age) {
      this.age = age;
   }
   public Integer getAge() {
      return age;
   }
   @Required
   public void setName(String name) {
      this.name = name;
   }
   public String getName() {
      return name;
   }
}

4.2 用于创建对象

Controller、Service、Repository注解

  1. 用于创建对象时他们的功能相当于在XML配置文件中编写一个< bean >标签。将对象交给IoC容器管理。表示这个类可以使用 Spring IoC 容器作为 bean 定义的来源
    注解使用位置:要创建对象的上面。

  2. 使用的注解通常有4个:
    Controller:一般用在表现层
    Service:一般用在业务层
    Repository:一般用在持久层
    Component:不属于上面三层时候使用
    四个注解作用和属性是完全一样的,上面三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰。
    属性:value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。只有一个value属性时候可以省略value。

4.3 用于注入数据

  1. 他们的作用就和在xml配置文件中的bean标签中写一个< property >标签的作用是一样的。出现位置:可以是变量上,也可以是方法上。

4.3.1 @Autowired注解

自动装配。作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。如果Ioc容器中有多个类型匹配时:使用Qualifier标签搭配。

属性中的 @Autowired
public class SimpleMovieLister 
    private MovieFinder movieFinder
    @Autowired
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
 
    // ...
}

配置在成员变量上面。你可以在属性中使用 @Autowired 注释来除去 setter 方法。当时使用 为自动连接属性传递的时候,Spring 会将这些传递过来的值或者引用自动分配给那些属性。

构造函数 @Autowired
public class MovieRecommender 
    private final CustomerPreferenceDao customerPreferenceDao;
    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }
    // ...
}

说明当创建 bean 时,即使在 XML 文件中没有使用 元素配置 bean ,构造函数也会被自动连接。

方法中的 @Autowired
public class MovieRecommender 
    private MovieCatalog movieCatalog
    private CustomerPreferenceDao customerPreferenceDao
    @Autowired
    public void prepare(MovieCatalog movieCatalog,
            CustomerPreferenceDao customerPreferenceDao) {
        this.movieCatalog = movieCatalog;
        this.customerPreferenceDao = customerPreferenceDao;
    }
 
    // ...
}
字段的@Autowired

您也可以将 @Autowired 注释应用于字段,或者将其与构造函数混合,如以下示例所示

public class MovieRecommender 
    private final CustomerPreferenceDao customerPreferenceDao;
   
    @Autowired
    private MovieCatalog movieCatalog;
 
    @Autowired
    public MovieRecommender(CustomerPreferenceDao customerPreferenceDao) {
        this.customerPreferenceDao = customerPreferenceDao;
    }
 
    // ...
}

直接应用于字段是我们使用的最多的一种方式,但是使用构造方法注入从代码层面却是更加好的。

4.3.2 @Qualifier注解

作用:在按照类中注入的基础之上再按照名称注入

它在给类成员注入时不能单独使用要配合Autowired使用。当你创建多个具有相同类型的 bean 时,并且想要用一个属性只为它们其中的一个进行装配,在这种情况下,你可以使用 @Qualifier 注释和 @Autowired 注释通过指定哪一个真正的 bean 将会被装配来消除混乱

使用示例

配置文件 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"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

   <context:annotation-config/>

   <!-- Definition for profile bean -->
   <bean id="profile" class="com.tutorialspoint.Profile">
   </bean>

   <!-- Definition for student1 bean -->
   <bean id="student1" class="com.tutorialspoint.Student">
      <property name="name"  value="Zara" />
      <property name="age"  value="11"/>
   </bean>

   <!-- Definition for student2 bean -->
   <bean id="student2" class="com.tutorialspoint.Student">
      <property name="name"  value="Nuha" />
      <property name="age"  value="2"/>
   </bean>

</beans>

这里是 Student.java 文件的内容:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
   @Autowired
   @Qualifier("student1")
   private Student student;
   public Profile(){
      System.out.println("Inside Profile constructor." );
   }
   public void printAge() {
      System.out.println("Age : " + student.getAge() );
   }
   public void printName() {
      System.out.println("Name : " + student.getName() );
   }
}

这里是 Profile.java 文件的内容:

package com.tutorialspoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
public class Profile {
   @Autowired
   @Qualifier("student1")
   private Student student;
   public Profile(){
      System.out.println("Inside Profile constructor." );
   }
   public void printAge() {
      System.out.println("Age : " + student.getAge() );
   }
   public void printName() {
      System.out.println("Name : " + student.getName() );
   }
}

下面是 MainApp.java 文件的内容:

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");
      Profile profile = (Profile) context.getBean("profile");
      profile.printAge();
      profile.printName();
   }
}

运行结果:

Inside Profile constructor.
Age : 11
Name : Zara

4.4 用于改变作用范围

@Scope注解

  1. 他们的作用就和在bean标签中使用scope属性实现的功能是一样的

  2. 使用的注解:
    Scope
    作用:用于指定bean的作用范围
    value属性:指定范围的取值。常用取值:singleton(单例)、prototype(多例)。

4.5 生命周期相关

@PostConstruct、@PreDestroy注解

  1. 他们的作用就和在bean标签中使用init-methoddestroy-methode是一样的。

  2. 使用的注解:
    PreDestroy
    作用:用于指定销毁方法
    PostConstruct
    作用:用于指定初始化方法

使用示例

这里是 HelloWorld.java 文件的内容:

import javax.annotation.*;
public class HelloWorld {
   private String message;
   public void setMessage(String message){
      this.message  = message;
   }
   public String getMessage(){
      System.out.println("Your Message : " + message);
      return message;
   }
   @PostConstruct
   public void init(){
      System.out.println("Bean is going through init.");
   }
   @PreDestroy
   public void destroy(){
      System.out.println("Bean will destroy now.");
   }
}

4.6 用于单元测试

@Runwith、@ContextConfiguration注解

  1. 分析
    1、应用程序的入口main方法
    2、junit单元测试中,没有main方法也能执行,junit集成了一个main方法,该方法就会判断当前测试类中哪些方法有 @Test注解,junit就让有Test注解的方法执行。
    3、junit不会管我们是否采用spring框架,在执行测试方法时,junit根本不知道我们是不是使用了spring框架,所以也就不会为我们读取配置文件/配置类创建spring核心容器
    4、由以上三点可知
    当测试方法执行时,没有Ioc容器,就算写了Autowired注解,也无法实现注入。

  2. 解决方法:Spring整合junit的配置
    1、导入spring整合junit的jar(坐标):spring-test
    2、使用Junit提供的一个注解 @Runwith把原有的main方法替换了,替换成spring提供的
    3、使用**@ContextConfiguration**注解告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置。
    *@ContextConfiguration注解中的两个属性:
    1.locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
    2.classes:指定注解类所在地位置

注意:当我们使用spring 5以上版本的时候,要求junit的jar必须是4.12及以上。

代码

     @RunWith(SpringJUnit4ClassRunner.class)//帮我们创建容器
     @ContextConfiguration("classpath:applicationContext.xml")//指定创建容器时使用哪个配置文件
     public class AnnotationTest(){
     //将名为student的对象注入到student中
     @Resource(name="student")
     private Student student;
     }
     @Test
     //下面是一些单元测试的方法    

4.7事务相关

@Transactional注解

@Transactional:类级的注解、适用于类中所有的public的方法,要是只在接口上写, 接口的实现类就会继承下来、接口的实现类的具体方法,可以覆盖类声明处的设置

@Transactional注解中常用参数说明

1.readOnly
该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)

2.isolation
该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置

3.timeout
该属性用于设置事务的超时秒数,默认值为-1表示永不超时

4.propagation
该属性用于设置事务的传播行为,具体取值可参考表6-7。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

@Transactional注意事项

1、@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.

2、用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException(“注释”);)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception(“注释”);)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
如下:
@Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
public void methodName() {
throw new Exception(“注释”)
}
@Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException(“注释”);)会回滚
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException(“注释”);
}
3、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 < tx:annotation-driven/ >元素的出现 开启 了事务行为。

4、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。

4.8 纯注解方式

  1. 使用纯注解方式,也就是把bean.xml删除了。需要创建一个配置类,它的作用和bean.xml是一样。

代码

主配置类中代码:

//Configuration注解指定当前类是一个配置类。
@Configuration
//用于通过ComponentScan注解指定spring在创建容器时要扫描的包
@ComponentScan("com.itheima")
//Import用于导入其他的配置类(子配置类)。例如连接数据库的类。
@Import(JdbcConfig.class)
//PropertySource用于指定properties文件的位置
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}

子配置类中代码:(连接数据库用)‘’

public class JdbcConfig {
	//使用value注解注入数据
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;

    /**
     * 用于创建一个QueryRunner对象
     * @param dataSource
     * @return
     */
     //Bean用于把当前方法的返回值作为bean对象存入spring的ioc容器中
    @Bean(name="runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(DataSource dataSource){
        return new QueryRunner(dataSource);
    }
     /**
     * 创建数据源对象
     * @return
     */
    @Bean(name="ds")
    public DataSource createDataSource(){
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

注解说明

  1. 注解说明
    1.Configuration
    作用:指定当前类是一个配置类。
    细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。

    2.ComponentScan
    作用:用于通过注解指定spring在创建容器时要扫描的包
    属性:value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。我们使用此注解就等同于在xml中配置了:<context:component-scan base-package="com.itheima"> </context:component-scan>
    3.Bean
    作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
    属性:name:用于指定bean的id。当不写时,默认值是当前方法的名称
    细节:当我们使用注解配置方法时,如果方法有参数,spring框架会去容器中查找有没有可用的bean对象。查找的方式和Autowired注解的作用是一样的。
    4.Import
    作用:用于导入其他的配置类(子配置类)。例如连接数据库的类。
    属性:value:用于指定其他配置类的字节码。
    细节:当我们使用Import的注解之后,有Import注解的类就父配置类,而导入的都是子配置类。
    5.PropertySource
    作用:用于指定properties文件的位置
    属性:value:指定文件的名称和路径,其中关键字:classpath,表示文件是在类路径下。

五、AOP和事务管理

请看w3cschool

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值