Spring学习总结—注册IOC容器和使用IOC容器、在xml文件中多种bean配置实验详解、工厂配置、以及在类中运用注解配置

一、为什么需要学习Spring,以及Spring框架的作用?

(一)为什么需要学习Spring?

  1. 目前流行的框架比较
    目前最流行和运用最广泛的是SpringMVC框架(Spring,SpringMVC,Mybatis)整合,其他框架不做分析,企业一般也会采取该中框架进行企业开发;是学习关于java后端的"必经之路";

(二)Spring框架的作用?

  1. 耦合性低
    它会把重复率较高的代码进行封装,方便再引用;它的耦合性低(程序的耦合:程序之间的依赖关系,包括类之间和方法之间的依赖),也可以说它的解耦(解耦:降低程序见的依赖关系)性高;因为,在我们实际开发中,需要做到:编译器不依赖,运行时才依赖;Spring中解耦的思路:第一步:使用反射来创建对象,而避免使用new关键字;第二步:通过读取配置文件来获取要创建的对象全限定类名
  2. AOP 编程的支持
    通过 Spring 的 AOP 功能,方便进行面向切面的编程,许多不容易用传统 OOP 实现的功能可以
    通过 AOP 轻松应付。
  3. 声明式事务的支持
    可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,
    提高开发效率和质量。
  4. 方便程序的测试
    可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可
    做的事情。
  5. 方便集成各种优秀框架
    Spring 可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz
    等)的直接支持。
  6. 降低 JavaEE API 的使用难度
    Spring 对 JavaEE API(如 JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些 API 的
    使用难度大为降低。
  7. Java 源码是经典学习范例
    Spring 的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对 Java 设计模式灵活运用以
    及对 Java 技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。

二、Spring框架中什么叫IOC?,什么叫DI?

(一)IOC(思想)(Inversion(反转) of Control):控制反转;

(1). 控制即:资源的获取方式;
(2). 一种为主动式(需要什么资源自己创建即可),一种为被动式(资源不是自己创建,而是交给一个容器来创建和设置);
(3). 容器:管理所有的组件(有功能的类),目的就是把主动的new资源变为被动的接受资源;
(4). 用例子说明就是(容器)婚介所,主动获取变为被动接受;

(二) DI:(Dependency lnjection)依赖注入:如果说IOC是思想,那DI就是实现和操作运行;

(1). 容器能知道哪个组件(类)运行的时候,需要另外一个类(组件);容器通过反射的形式,将容器中准备好的对象注入(利用反射给属性赋值)
(2). 只要容器管理的组件,都能使用容器提供的强大功能;

三、Spring框架实现和部署HelloWord小实例

  1. 导入jar包:
    1. 导入beans,context,core,expression核心容器(也是我们的分布图上面黑色部分需要导入的包)绿色的为模块在这里插入图片描述
    2. 最后,还需要导入一个日志包,spring运行的时候依赖一个日志包,没有就会报错;
  2. 配置:Spring的配置文件中,集合了Spring的ioc容器管理的所有组件(会员清单)创建要给Spring Bean Configuration File(Spring的bean配置文件)
  3. 测试:
    1. ClassPathXmlApplicationContext(ioc.xml): ioc容器的配置文件在类路径下(但是。ider的module模块下的src文件夹只会识别class文件,所以,我们的这个应用配置xml文件,就会报错找不到文件)
    2. FileSystemXmlApplicationContext("D:\\IderWorkspace_Spring\\src\\ioc.xml");意思为ioc容器的配置文件在磁盘路径下;(我开始初学用的是这个,建议使用ClassPathXmlApplicationContext(ioc.xml):

四、bean配置实验总结:

(一)根据bean的类型从ioc容器中获取bean的实例,通过构造器为bean赋值,通过p命名空间为bean赋值设置

  1. 第一步,创建一个Person实体类
package com.atguigu.bean;


import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author liuqi
 * @create 2020--04--24--22:18
 */
public class Person {
    //基本类型直接使用:
    //<property name="lastName" value="李四"></property>自动的进行类型转换;
    private String lastName="小明";
    private Integer age;
    private String gender;
    private String email;

    private Car car;
    private List<Book> books;
    private Map<String,Object> map;
    private Properties properties;
    //xxxxx
    public Person() {
    }

    public Person(String lastName, Integer age, String gender) {
        this.lastName = lastName;
        this.age = age;
        this.gender = gender;
        System.out.println("三个参构造器...age");
    }
    public Person(String lastName,String email,String gender) {
        this.lastName = lastName;
        this.gender = gender;
        this.email = email;
        System.out.println("三个参构造器...email");
    }

    public Person(String lastName, Integer age, String gender, String email) {
        this.lastName = lastName;
        this.age = age;
        this.gender = gender;
        this.email = email;
        System.out.println("有参参构造器");
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public List<Book> getBooks() {
        return books;
    }

    public void setBooks(List<Book> books) {
        this.books = books;
    }

    public Map<String, Object> getMap() {
        return map;
    }

    public void setMap(Map<String, Object> map) {
        this.map = map;
    }

    public Properties getProperties() {
        return properties;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "Person{" +
                "lastName='" + lastName + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", email='" + email + '\'' +
                ", car=" + car +
                ", books=" + books +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }
}

  1. 根据Person的实体类属性再创建Car实体类
package com.atguigu.bean;

/**
 * @author liuqi
 * @create 2020--05--15--17:45
 */
public class Car {
    private String carName;
    private String  price;
    private String color;

    public String getCarName() {
        return carName;
    }

    public void setCarName(String carName) {
        this.carName = carName;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Car{" +
                "carName='" + carName + '\'' +
                ", price='" + price + '\'' +
                ", color='" + color + '\'' +
                '}';
    }
}

  1. 根据Person的实体类属性再创建Book实体类
package com.atguigu.bean;

/**
 * @author liuqi
 * @create 2020--05--15--20:37
 */
public class Book {
    private String bookName;
    private String author;

    public void initBook(){
        System.out.println("这是initBook()方法,初始化方法");
    }

    public void destroyBook(){
        System.out.println("这是destroyBook()方法,销毁方法");
    }

    public Book() {
        System.out.println("创建book的无参构造方法");
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookName='" + bookName + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}

  1. 创建ioc.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" xmlns:util="http://www.springframework.org/schema/util"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    <!--frame:框架-->
    <!--注册一个Person对象,Spring会自动创建这个person对象
    一个Bean标签可以注册一个组件(对象,类)
    class,写要组测的组件的全类名;
    id:这个对象的唯一标识;-->

<!--
     使用property标签为Person对象的属性赋值;
     name :指定属性名;
     value:为这个属性赋值
-->
    <!--这种配置会调用无参构造器和set方法-->
 <!--   <bean id="person1" class="com.atguigu.bean.Person">
    <property name="lastName" value="张三"></property>
    <property name="age" value="19"></property>
    <property name="gender" value="男"></property>
    <property name="email" value="[email protected]"></property>
    </bean>-->
    <!--<bean id="person02" class="com.atguigu.bean.Person">-->
        <!--<property name="lastName" value="李四"></property>-->
        <!--<property name="age" value="19"></property>-->
        <!--<property name="gender" value="男"></property>-->
        <!--<property name="email" value="[email protected]"></property>-->
    <!--</bean>-->
    <!--constructor-arg:(最常用的,最有效的,掌握)构造器元,构造器有几个参数就要写几个构造器标签,set方法也不会调用了,直接用构造方法-->
    <bean id="person03" class="com.atguigu.bean.Person">
        <!--public Person(String lastName, Integer age, String gender, String email)-->
        <constructor-arg name="lastName" value="03"></constructor-arg>
        <constructor-arg name="age" value="19"></constructor-arg>
        <constructor-arg name="gender" value="男"></constructor-arg>
        <constructor-arg name="email" value="[email protected]"></constructor-arg>
    </bean>

    <bean id="person03.2" class="com.atguigu.bean.Person">
        <!--public Person(String lastName, Integer age, String gender, String email)-->
        <!--如果不写name,则必须按照有参构造器的参数顺序写-->
        <constructor-arg  value="03.2"></constructor-arg>
        <constructor-arg value="19"></constructor-arg>
        <constructor-arg  value="男"></constructor-arg>
        <constructor-arg  value="[email protected]"></constructor-arg>
    </bean>

    <bean id="person03.3" class="com.atguigu.bean.Person">
        <!--public Person(String lastName, Integer age, String gender, String email)-->
        <constructor-arg  value="03.3"></constructor-arg>
        <constructor-arg  value="19"></constructor-arg>
        <!--index 从0开始 为参数指定索引-->
        <constructor-arg  value="[email protected]" index="3"></constructor-arg>
        <constructor-arg  value="男" index="2"></constructor-arg>
    </bean>

   <!-- <bean id="person03.4" class="com.atguigu.bean.Person">
   <!--如果遇到两个构造器,有一样数量的参数,但是,参数的数据类型不一致时,可以使用type属性让构造器辨别它是什么属性的(重载的情况下用type可以指定参数的类型)-->
     <!-- public Person(String lastName, Integer age, String gender)-->
        <!-- public Person(String lastName,String email,String gender)-->
        <constructor-arg  value="03.4"></constructor-arg>
        <constructor-arg  value="男" index = "2"></constructor-arg>
        <constructor-arg  value="19" index="1" type="java.lang.String"></constructor-arg>
    </bean>-->
     <!--为了能够不写重复的标签代码,可以通过p名称空间为bean赋值,导入p名称空间
     名称空间:在xml中名称空间是用来防止标签重复的;
    1、导入名称空间的写法 2、直接使用-->
    <!-- <bean id="person04" class="com.atguigu.bean.Person"
           p:age="12" p:email="04.email"  p:lastName="4" p:gender="男">
     </bean>-->
</beans>

  1. 创建IOCTest通过容器来测试每一个bean配置
package com.atguigu.test;

import com.atguigu.bean.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * @author liuqi
 * @create 2020--04--24--22:27
 */
public class IOCTest  {
   private static ApplicationContext ioc = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\ioc.xml");
/*中文报错意思:初始化程序错误异常,原因就是我用的是文件路径,而其他地方用的时候,由于项目名不一样就会报错,建议使用ClassPathXmlApplicationContext()
    java.lang.ExceptionInInitializerError
    Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from file [D:\IderWorkspace_Spring\src\ioc.xml]; nested exception is java.io.FileNotFoundException: D:\IderWorkspace_Spring\src\ioc.xml (系统找不到指定的路径。)
*/

    //@Test的使用 是该方法可以不用main方法调用就可以测试出运行结果,是一种测试方法
    //一般函数都需要有main方法调用才能执行,注意被测试的方法必须是public修饰的
    @Test
    public void test(){
        /*ApplicationContext :容器,配置文件,上下文*/
        //ApplicationContext:代表ioc容器(Inversion of Control,缩写为IoC,控制反转)
        //ClassPathXmlApplicationContext:当前应用的xml配置文件classpath下;
        //根据spring的配置文件得到ioc容器对象;
//        ApplicationContext ioc =  (ApplicationContext)new ClassPathXmlApplicationContext("src/ioc.xml");
        //容器帮我们创建好了对象;
        Person person1 = (Person)ioc.getBean("person1");
        System.out.println(person1);
    }


    //实验二:根据bean的类型从IOC容器中获取bean的实例;
    @Test
    public void test2(){

        ApplicationContext ioc02 = new FileSystemXmlApplicationContext("D:\\IderWorkspace_Spring\\src\\ioc.xml");
        Person person02 = ioc02.getBean(Person.class);
        System.out.println(person02);
        //报错:如果IOC容器中同种类型d的bean有多个,报错如下:
        // org.springframework.beans.factory.NoUnique(唯一的)BeanDefinition(定义)Exception:
        // No qualifying bean of type [com.atguigu.bean.Person] is defined:
        // expected single(单个) matching(匹配) bean but found 2: person1,person02
    }
    //实验二正确方法:(ioc.getBean("person02",Person.class);第一个参数为bean的id标识符,第二个为对象class)
    @Test
    public void test2True(){
        Person person02 = ioc.getBean("person02",Person.class);
        System.out.println(person02);
    }
    //实验三:通过构造器为bean的属性赋值(index,type属性介绍),通过p名称空间为bean赋值;
    @Test
    public void test3True(){
        Object obj = ioc.getBean("person03");
        System.out.println(obj);
    }
    @Test
    public void test3TwoTrue(){
        /*Object obj2 = ioc.getBean("person03.2");
        System.out.println(obj2);
        Object obj3 = ioc.getBean("person03.3");
        System.out.println(obj3);*/

        Object obj4 = ioc.getBean("person03.4");
        System.out.println(obj4);
        //没写type:三个参构造器...age
        //Person{lastName='03.4', age=19, gender='男', email='null'}
        //添加type:三个参构造器...email
        //Person{lastName='03.4', age=null, gender='男', email='19'}
    }
    @Test
    public void Test4(){
        Object person04 = ioc.getBean("person04");
        System.out.println(person04);
    }

}

  1. 报错总结
/*1、中文报错意思:初始化程序错误异常,原因就是我用的是文件路径,而其他地方用的时候,由于项目名不一样就会报错,建议使用ClassPathXmlApplicationContext()
java.lang.ExceptionInInitializerError
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from file [D:\IderWorkspace_Spring\src\ioc.xml]; nested exception is java.io.FileNotFoundException: D:\IderWorkspace_Spring\src\ioc.xml (系统找不到指定的路径。)
*/

 //2、报错:如果IOC容器中同种类型d的bean有多个,报错如下:
 // org.springframework.beans.factory.NoUnique(唯一的)BeanDefinition(定义)Exception:
 // No qualifying bean of type [com.atguigu.bean.Person] is defined:
 // expected single(单个) matching(匹配) bean but found 2: person1,person02

3、bean标签的id名字与测试文件getBean("id")不一致报错;
 报错如下:
org.springframework.beans.factory.NoSuch(如此的)BeanDefinition(定义)Exception:
No bean named 'person044' is defined

4、当创建了有参构造器,在使用bean配置文件的时候,如果报错,必须使用
<constructor-arg  value="03.4"></constructor-arg>;不可以使用property和命名空间
说明:你没有写无参构造器;
(相当于,你在实例化对象,new一个无参的对象再set,和new一个有参的对象)
报错如下:( Instantiation of bean failed(bean的实例化失败); nested exception is org.springframework.beans.BeanInstantiationException:
Could not instantiate bean class [com.atguigu.bean.Person]: No default constructor found(未找到默认构造函数);
nested exception(嵌套异常) is java.lang.NoSuchMethodException: com.atguigu.bean.Person.<init>()(初始化))

5、 报错:如果IOC容器中同种类型的bean有多个,报错如下:
org.springframework.beans.factory.NoUnique(唯一的)BeanDefinition(定义)Exception:
No qualifying bean of type [com.atguigu.bean.Person] is defined:
expected single(单个) matching(匹配) bean but found 2: person1,person02

6、来指定id名字;(特别注意:指定类名开头字母小写)
中文解释:bean配置constructor-arg构造元的时候,没有命名时候,变量和值变量不一致报错(不能解决匹配的构造函数,简单参数的参数,以避免类型歧义)
java.lang.ExceptionInInitializerError
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'person03.2' defined in file [D:\iderAllProject\IderWorkspace_Spring\src\ioc.xml]: Could not resolve matching constructor (hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)
解决方法,一一核对变量和变量值的对应关系(或者:index从0开始 为参数指定索引-->)

(二)正确的为各种属性赋值

  1. 再次沿用上面的实体类,其次,重新创建一个ioc2.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"

       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd" >
   <!--实验4:正确的为各种属性赋值
    1、测试使用null值;
    -->
    <bean id="car01" class="com.atguigu.bean.Car">
        <property name="carName" value="宝马"></property>
        <property name="color" value="绿色"></property>
        <property name="price" value="30000"></property>
    </bean>

  <bean id="person1" class="com.atguigu.bean.Person">
      <!--1、原本初始值为小明
      Person{lastName='小明', age=null, gender='null', email='null', car=null, books=null, map=null, properties=null}-->
      <!--value="null" 相当于lastName = "null" 是一个字符串null-->
      <!--<property name="lastName" value="null"></property>-->
      <property name="lastName">
          <!--进行复杂的赋值-->
          <null></null>

      </property>
      <!--2、引用类型赋值(引用外部的bean,引用内部的bean)-->
      <!--2.1 ref:引用   reference : 参考,引用   引用外部的bean-->
      <!--Object car01 = ioc2.getBean("car01");
      <property name="car" ref="car01"></property>-->

      <!--2.2:引用内部的bean:对象我们可以使用bean创建,相当于 car = new Car();不能被获取到,只能内部使用-->
      <property name="car">
          <bean class="com.atguigu.bean.Car" ><!--id="ccar"-->
              <property name="carName" value="单车"></property>
          </bean>
      </property>

  </bean>

    <bean id="bookyy" class="com.atguigu.bean.Book">
        <property name="author" value="刘奇2"></property>
        <property name="bookName" value="书3"></property>
    </bean>

  <bean id="person03" class="com.atguigu.bean.Person">
      <property name="books">
          <!--books = new ArrayList<Book>();-->
       <list>
           <!--list标签体中添加每一个元素-->
           <!--1、通过p名称空间为bean赋值,导入p名称空间-->
           <bean class="com.atguigu.bean.Book" ><!--p:bookName="书1"-->
               <!--2、引用内部的bean-->
               <property name="author" value="刘奇"></property>
               <property name="bookName" value="书2"></property>
           </bean>
           <!--3、引用外部的bean-->
           <ref bean="bookyy"/>
       </list>
      </property>

      <!--Map<String,Object> map;-->
      <property name="map">
         <!-- map = new LinkedHashMap<>{};-->
          <map>
              <!--entry(条目)  代表一个键值对-->
              <entry key="key01" value="张三"></entry>
              <!--value-ref:引用外部的bean配置-->
              <entry key="key02" value-ref="bookyy"></entry>
              <!--引用内部的bean配置-->
              <entry key="key03">
                  <bean class="com.atguigu.bean.Car">
                      <property name="carName" value="包马"></property>
                  </bean>
              </entry>
              <!--Map<String,Object> map;可以存所有-->
              <!--<entry key="key04">
                  <map></map>
              </entry>-->
          </map>
      </property>

  </bean>
    <!--entry:入口-->
    <!--util名称空间创建集合类型的bean:方便其他bean引用-->
    <!--报错原因:Error:(7, 45) java: 程序包org.graalvm.compiler.core.common.util不存在
    解决方法:点击项目名右击》Maven 专家》reimport:全部重新导入-->

<!--<bean id = "person04" class="com.atguigu.bean.Person">
    <property name="map" ref="mymap">
    </property>
</bean>-->
    <!--xmlns:util="http://www.springframework.org/schema/util"
    private Map<String,Object> map = new HashMap<String,Object>();
<util:map id="mymap">
    <entry key="01" value="liuqi1"></entry>
    <entry key="02" value="liuqi2"></entry>
    <entry key="03" value="liuqi3"></entry>
    <entry key="04">
        <bean class="com.atguigu.bean.Person">
            <property name="age" value="22"></property>
            <property name="lastName" value="liuqi4"></property>
        </bean>
    </entry>
    <entry key="05" value-ref="carc">

    </entry>
</util:map>-->
<bean id="carc" class="com.atguigu.bean.Car">
    <property name="carName" value="奇迹"></property>
    <property name="price" value="100"></property>
    <property name="color" value="红色"></property>
</bean>
    <bean id="person07" class="com.atguigu.bean.Person">
        <!--private Properties properties;-->
        <property name="properties">
      <!--      Properties properties = new Properties 所有的key和value都是String-->
            <props>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>
    <!--级联属性赋值:级联属性:属性的属性-->
    <bean id = "person5" class="com.atguigu.bean.Person">
        <property name="car" ref="car01"></property>
        <property name="car.price" value="90003"></property>
    </bean>

<!--实验6:通过继承实现bean配置信息的重用-->
<!--实验7:通过abstract属性创建一个模板bean-->
    <!--parent:继承于哪个bean-->
    <!--abstract="true" 这个bean配置是抽象的,不能获取它的实例,只能被别人继承-->
    <bean id = "person6" class="com.atguigu.bean.Person" abstract="true">
        <property name="lastName" value="liuqi"></property>
        <property name="age" value="5"></property>
        <property name="email" value="qq.com"></property>
    </bean>
<bean id="person7" class="com.atguigu.bean.Person" parent="person6">
    <property name="age" value="20"></property>
</bean>


</beans>
  1. 重新创建IOCTest2.class文件
package com.atguigu.test;


import com.atguigu.bean.Book;
import com.atguigu.bean.Car;
import com.atguigu.bean.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

import java.util.List;
import java.util.Map;

/**
 * @author liuqi
 * @create 2020--05--15--20:46
 */
public class IOCTest2 {
    ApplicationContext ioc2 = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\ioc2.xml");
   /*private static ApplicationContext ioc2 = new FileSystemXmlApplicationContext("D:\\IderWorkspace_Spring\\src\\ioc2.xml");*/

    @Test
    public void Test1(){

        Person person1 = (Person) ioc2.getBean("person1");
        System.out.println(person1.getLastName() == null);
        //return  true
        System.out.println(person1.getCar());
        //Car{carName='宝马', price='30000', color='绿色'}
        Car car = person1.getCar();
        Object car01 = ioc2.getBean("car01");
        System.out.println(car01);
        System.out.println(car == car01);
        // return true
    }
    @Test
    public  void  Test02(){
        Person person01 = (Person) ioc2.getBean("person1");
        Car car = person01.getCar();
        System.out.println(car);
        //Car{carName='单车', price='null', color='null'}
    }
    @Test
    public void  Test03(){
        Person person03 = (Person) ioc2.getBean("person03");
        List<Book> books = person03.getBooks();
        System.out.println(books);
        //没有使用内部bean [Book{bookName='书1', author='null'}, Book{bookName='书3', author='刘奇2'}]
        //没有用命名空间 [Book{bookName='书2', author='刘奇'}, Book{bookName='书3', author='刘奇2'}]

        //用命名空间同时使用了内部bean会报错
        //org.springframework.beans.factory.parsing.BeanDefinitionParsingException: an definition parsing
        //Offending resource: file [D:\IderWorkspace_Spring\src\ioc2.xml]Configuration problem: Unexpected failure during be
        //Bean 'person03'; nested exception is org.springframework.beans.factory.parsing(解析).BeanDefinitionParsingException: Configuration problem: Property 'bookName' is already defined using both <property> and inline(内联函数) syntax(语法). Only one approach(接近 方法) may be used per(线) property.
        //Offending resource: file [D:\IderWorkspace_Spring\src\ioc2.xml]

    }
    @Test
    public void Test04(){
        Object ccar = ioc2.getBean("ccar");
        System.out.println("---------"+ccar);
//        报错原因是:在bean配置中id为ccar没有被定义;
        /*报错代码:
        org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'ccar' is defined
        说明:内部bean不能用id获取*/
    }
@Test
    public void Test05(){
    Person bean = (Person)ioc2.getBean("person03");
    Map<String, Object> map = bean.getMap();
    System.out.println(map);


    /*{key01=张三, key02=Book{bookName='书3', author='刘奇2'},
    key03=Car{carName='包马', price='null', color='null'}}*/
}
@Test
    public void Test06(){
    Person person04 = (Person) ioc2.getBean("person04");
    Map<String, Object> map = person04.getMap();
    System.out.println(map);
}
/*级联属性可以修改属性的属性,注意:原来的bean值也会被修改*/
    @Test
    public void Test07(){
        Person person05 = (Person) ioc2.getBean("person5");
        Object o = ioc2.getBean("person5");
        Car map = person05.getCar();
        System.out.println(map);
        System.out.println(o);
    }
}

  1. 错误总结
1、用命名空间同时使用了内部bean会报错
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unexpected failure during bean definition parsing
Offending resource: file [D:\IderWorkspace_Spring\src\ioc2.xml]
Bean 'person03'; nested exception is org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Property 'bookName' is already defined using both <property> and inline syntax. Only one approach may be used per property.
Offending resource: file [D:\IderWorkspace_Spring\src\ioc2.xml]
2、引用内部的bean:对象我们可以使用bean创建,相当于 car = new Car();不能被获取到,只能内部使用-
报错,找不到id名字
3、引用util(工具)写名称空间创建集合类型的bean:方便其他bean引用
报错原因:Error:(7, 45) java: 程序包org.graalvm.compiler.core.common.util不存在
解决方法:点击项目名右击&#45;&#45;》Maven 专家&#45;&#45;》reimport:全部重新导入
4、引用util(工具)写名称空间创建集合类型的bean:方便其他bean引用时候,报错但无法找到元素 'util:map' 的声明。
报错原因:org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:
      Line 93 in XML document from file [D:\IderWorkspace_Spring\src\ioc2.xml] is invalid;
      nested exception is org.xml.sax.SAXParseException;
      lineNumber: 93; columnNumber: 22; cvc-complex-type.2.4.c:
      通配符的匹配很全面, 但无法找到元素 'util:map' 的声明。*/
解决方法:在Spring配置文件中定义util(工具)写名称空间创建集合类型的bean—和相应的schemaLocation(两个)相对应

(三)测试bean之间的依赖,作用域(单实例和多实例)、静态和实例工厂

  1. 继续使用前面的类并再添加一个包(Factory)和三个类(MyFactory RoomInstanceFactory RoomStaticFactory)

1.1 MyFactory

package com.atguigu.Factory;

import com.atguigu.bean.Book;
import org.springframework.beans.factory.FactoryBean;

public class MyFactory implements FactoryBean<Book> {
    //第一个获取对象,并传值
    public Book getObject() throws Exception {
        Book book = new Book();
        book.setBookName("刘奇自传");
        book.setAuthor("刘奇");
        return book;
    }
//获取对象的类型,并返回
    public Class<?> getObjectType() {
        return Book.class;
    }
//判断对象是否是单实例(true),还是多实例(false)
    //单实例:每次创建的对象都是一样的
    //多实例:每次创建的对象都是不一样的
    public boolean isSingleton() {
        return true;
    }
}

1.2 **RoomInstanceFactory **

package com.atguigu.Factory;

import com.atguigu.bean.Room;

/**
 * @author liuqi
 * @create 2020--06--16--8:19
 */
public class RoomInstanceFactory {
    public Room RoomsFactory(String dx){
        System.out.println("这是实例化建造房间工厂方法");
        Room room = new Room();
        room.setDx(dx);
        room.setCs("2");
        room.setGd("10m");
        room.setYs("蓝色");
        return room;
    }



}

1.3 **RoomStaticFactory **

package com.atguigu.Factory;

import com.atguigu.bean.Room;

/**
 * @author liuqi
 * @create 2020--06--16--8:19
 */
public class RoomStaticFactory {
    public static Room getRoom(String dx){
        System.out.println("这是静态的建造房间工厂方法");
        Room room = new Room();
        room.setDx(dx);
        room.setCs("3");
        room.setGd("20m");
        room.setYs("红色");
        return room;
    }
}

  1. 重新创建IOCTest3.class文件
package com.atguigu.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/**
 * @author liuqi
 * @create 2020--06--15--23:36
 */
public class IOCTest3{
    ApplicationContext  Ioc = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\ioc3.xml");

    public static void main(String[] args) {
        System.out.println("ss");
    }
    @Test
    public void Test1(){
        System.out.println("容器完成");
        //静态工厂方法在bean配置中声明会自动被调用;

        /*完成打印:这是静态的建造房间工厂方法
                容器完成*/

    }


    @Test
    public void Test2(){
    /*    bean配置没有必需的类型异常*/
//    org.springframework.beans.factory.BeanNotOfRequiredTypeException:
//    Bean named 'room' must be of type [com.atguigu.Factory.RoomStaticFactory],
//    but was actually of type [com.atguigu.bean.Room]

        Object bean = Ioc.getBean("room");
        System.out.println(bean);
/*类转换异常*/
//java.lang.ClassCast(投掷)Exception(类转换异常):
//class com.atguigu.bean.Room cannot be cast to class com.atguigu.Factory.RoomStaticFactory
//(com.atguigu.bean.Room and com.atguigu.Factory.RoomStaticFactory are in unnamed module of loader 'app')

    }
    @Test
    public void Test3(){
        Object roomInstanceRealize = Ioc.getBean("RoomInstanceRealize");
        System.out.println(roomInstanceRealize);
    }

    @Test
    public void Test4(){
        /*Object roomInstanceRealize = Ioc.getBean("MyFactory", MyFactory.class);
        System.out.println(roomInstanceRealize);*/
        //Ioc.getBean("MyFactory", MyFactory.class);中的参数类型不一致
        //org.springframework.beans.factory.BeanNotOfRequiredTypeException:
        // Bean named 'MyFactory' must be of type [com.atguigu.Factory.MyFactory],
        // but was actually of type [com.atguigu.bean.Book]

        Object roomInstanceRealize = Ioc.getBean("MyFactory");
        Object roomInstanceRealize2 = Ioc.getBean("MyFactory");
        System.out.println(roomInstanceRealize==roomInstanceRealize2);
    }
}

  1. 重新创建ioc3.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">
<!--实验8bean之间的依赖(只是改变创建顺序)
    原来是按照配置的顺序创建bean
    改变bean创建的顺序-->
    <bean id="car" class="com.atguigu.bean.Car" depends-on="person,book"></bean>
    <bean id="book" class="com.atguigu.bean.Book"></bean>
    <bean id="person" class="com.atguigu.bean.Person"></bean>
<!--实验9:测试bean的作用域,分别创建单实例和多实例的bean
    bean的作用于:指定bean是否单实例:xxx;默认:单实例的
    prototype(原型):多实例的
    1、容器启动默认不会去创建多实例bean
    2、获取的时候创建这个bean
    3、每次都会创建一个新的对象;

    singleton(单例模式):单实例的,默认

    1、在容器启动完成之前就已经创建好对象了,并保存在容器中;(无参构造方法就可以验证)
    2、任何获取d都是获取之前创建好的对象;

    request:在web环境下,同一次请 求创建一个bean实例;
    session:在web环境下,同一次会话创建一个bean实例;-->
    <bean id="book2" class="com.atguigu.bean.Book" scope="prototype"></bean>
<!--实验五:配置通过静态工厂方法创建的bean、实例工厂方法创建的bean、FactoryBean
    bean的创建默认就是框架利用反射new出来的bean实例
    工厂模式:工厂帮我们创建对象,有一个专门帮我们创建对象的类,这个类就是工厂;-->
     <!--类名 名称 = 类名Factory.get类名(属性 属性名)-->

    <!--
    静态工厂:工厂本身不用创建对象,通过静态方法调用,对象 = 工厂类.工厂方法名(属性 属性名);
    实例工厂:工厂本身需要创建对象,
                                  工厂类 对象 = new  工厂类();
                                  工厂对象.工厂方法名(属性 属性名)
                      两者的区别就是一个类的方法是static静态方法,一个不是-->

   <!-- class:指定静态工厂的全类名;
    factory-method:指定工厂方法
    constructor(构造函数 构造器)-arg:可以为方法指定参数;-->
<!--静态工厂(不需要创建工厂本身)factory—method=“getroom”:指定哪个方法是工厂方法;-->
    <bean id="room" class="com.atguigu.Factory.RoomStaticFactory" factory-method="getRoom">
    <!--可以为方法指定参数;-->
    <constructor-arg name="dx" value="100m"></constructor-arg>



</bean>
    <!-- 2、实例工厂-->
    <!-- factory-method:指定这个实例工厂中哪个方法是工厂方法;-->
    <bean id="RoomInstances" class="com.atguigu.Factory.RoomInstanceFactory"></bean>
    <!--factory-bean;指定当前对象创建使用哪个工厂;-->
    <!-- 1、先配置出实例工厂对象;
         2、先配置我们我们要创建的类 使用哪个工厂创建;
         1)、factory-bean:指定使用哪个工厂实例;
         2)、factory-method:使用哪个工厂方法;-->
 <bean id="RoomInstanceRealize" class="com.atguigu.bean.Room" factory-bean="RoomInstances" factory-method="RoomsFactory">

     <constructor-arg name="dx" value="200m"></constructor-arg>
 </bean>
  <!--  FactoryBean(是Spring规定的一个接口;)
    只要是这个接口的实现类,Spring都认为是一个工厂;
        1、ioc容器启动的时候不是创建实例
        2、FactoryBean:获取的时候才创建对象;-->
<bean id="MyFactory" class="com.atguigu.Factory.MyFactory">
</bean>

   <!-- 实验10:创建带有生命周期方法的bean
        生命周期:bean的创建(初始化)到销毁:
        ioc容器中注册的bean;
                1)、单例的bean,容器启动的时候就会创建好,容器关闭就会销毁创建的bean;
                2)、多实例的bean,需要获取的时候才能创建;
                我们可以为bean自定义一些生命周期方法;spring在创建或者销毁的时候就会调用指定的方法;
                自定义初始化方法和销毁方法;-->
<bean id="book01" class="com.atguigu.bean.Book" destroy-method="destroyBook" init-method="initBook"></bean>
   <!--scope="prototype":范围 作用域 适用范围:多实例-->
<bean id="book02" class="com.atguigu.bean.Book" destroy-method="destroyBook" init-method="initBook" scope="prototype"></bean>
<!--实验11:测试bean的后置处理器:BeanPostProcessor
Spring有一个接口:后置处理器:可以在bean的初始化前后调用方法;
-->
<bean id="BeanPostProcessor" class="com.atguigu.Importent.MyBeanPostProcess"></bean>
   <bean id="car01" class="com.atguigu.bean.Car"></bean>

<bean id="car01" class="com.atguigu.bean.Car">
    <property name="carName" value="${username}" ></property>
</bean>
    <bean id="car02" class="com.atguigu.bean.Car">
        <property name="carName" value="${username}"></property>
    </bean>
</beans>
  1. 错误总结
8、用的配置文件无效,嵌套异常,无法找到声明;
报错原因:org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:
      Line 26 in XML document from file
      [D:\iderAllProject\IderWorkspace_Spring\src\applicationContext03.xml] is invalid(无效的);
      nested(嵌套) exception is org.xml.sax.SAXParseException;
      lineNumber: 26; columnNumber: 57; cvc-complex-type.2.4.c: 通配符的匹配很全面, 但无法找到元素 'context:component-scan' 的声明。
解决方法:在Spring配置文件中定义context命名空间和相应的schemaLocation(两个)相对应
(xmlns:context="http://www.springframework.org/schema/context"
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd")

(四)创建带有生命周期的bean和测试bean的后置处理器

  1. 创建一个MyBeanPostProcess.class文件并继承bean的后置处理器:BeanPostProcessor
package com.atguigu.Importent;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcess implements BeanPostProcessor {
/*
* 1)、编写后置处理器的实现类;
* 2)、将后置处理器注册在【配置文件中
* */
  /*
    * postProcessBeforeInitialization:
    *           初始化之前调用
    *       Object bean:将要初始化的bean
    *       String s:bean在xml中配置的id
    * */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("["+beanName+"]"+"bean将要调用初始化方法了。。BeforeInitialization。"+"这个bean是这样的["+bean+"]");
        //返回传入的bean;
        return bean;
    }
/*
* postProcessAfterInitialization:
*           初始化方法之后调用
* */
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("["+beanName+"]"+"bean初始化方法之后调用完了。。AfterInitialization。"+"这个bean是这样的["+bean+"]");
        //初始化之后返回的bean;返回的是什么,容器中保存的就是什么;
        return bean;
    }
}

  1. 创建一个applicationContext.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">
   <!-- 实验10:创建带有生命周期方法的bean
        生命周期:bean的创建(初始化)到销毁:
        ioc容器中注册的bean;
                1)、单例的bean,容器启动的时候就会创建好,容器关闭就会销毁创建的bean;
                2)、多实例的bean,需要获取的时候才能创建;
                我们可以为bean自定义一些生命周期方法;spring在创建或者销毁的时候就会调用指定的方法;
                自定义初始化方法和销毁方法;-->
<bean id="book01" class="com.atguigu.bean.Book" destroy-method="destroyBook" init-method="initBook"></bean>
   <!--scope="prototype":范围 作用域 适用范围:多实例-->
<bean id="book02" class="com.atguigu.bean.Book" destroy-method="destroyBook" init-method="initBook" scope="prototype"></bean>
<!--实验11:测试bean的后置处理器:BeanPostProcessor
Spring有一个接口:后置处理器:可以在bean的初始化前后调用方法;
-->
<bean id="BeanPostProcessor" class="com.atguigu.Importent.MyBeanPostProcess"></bean>
   <bean id="car01" class="com.atguigu.bean.Car"></bean>
</beans>
  1. 创建一个测试类IocTest.class文件
package com.atguigu.Importent;

import com.atguigu.bean.Car;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class IocText {

//    ApplicationContext applicationContext =new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext.xml");
/*报错原因为:class文件找不到,用File方法一般都能找到*/
//    org.springframework.beans.factory.BeanDefinitionStoreException:
//    IOException parsing XML document from class path resource [D:/iderAllProject/IderWorkspace_Spring/src/applicationContext.xml];
//    nested exception is java.io.FileNotFoundException: class path resource [D:/iderAllProject/IderWorkspace_Spring/src/applicationContext.xml]
//    cannot be opened because it does not exist


//实验10:创建带有生命周期方法的bean

    //证明:
    /*单例Bean的生命周期
            (容器启动)构造器----》初始化方法---》(容器关闭)销毁方法(需要写close方法)

    多实例Bean的生命周期
            (获取bean)构造器----》初始化方法---》容器关闭也会调用bean的销毁方法(需要写close方法)*/
    @Test
    public void Experiment10 (){
        //创建ioc容器的时候,会直接调用init初始化方法:
        // (打印为:创建book的无参构造方法
        //这是initBook()方法,初始化方法)
        ConfigurableApplicationContext configurableApplicationContext =new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext.xml");
        Object book01 = configurableApplicationContext.getBean("book01");
        System.out.println("关闭了");
//        configurableApplicationContext.close();
    }
    @Test
    public void Experiment10two (){
        ConfigurableApplicationContext configurableApplicationContext =new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext.xml");
        Object book02 = configurableApplicationContext.getBean("book02");
        System.out.println("Experiment10two ()关闭了");
//        configurableApplicationContext.close();
        /*创建book的无参构造方法
        这是initBook()方法,初始化方法
        Experiment10two ()关闭了
        这是destroyBook()方法,销毁方法*/

    }
//实验11:测试bean的后置处理器:BeanPostProcessor
    //证明1:什么都不写,直接实现ioc容器,为:单实例会执行,多实例不会执行
    /*后置处理器的生命周期
            (容器启动)构造器----》后置处理器(postProcessBeforeInitialization)----》初始化方法---》后置处理器(postProcessAfterInitialization)----》bean初始化完成*/

    //证明2:多实例执行,除非是用ioc容器获取了它才会执行
    /*后置处理器的生命周期
            (获取bean)构造器----》后置处理器(postProcessBeforeInitialization)----》初始化方法---》后置处理器(postProcessAfterInitialization)----》bean初始化完成*/

    @Test
public  void  BeanPostProcessorTest(){

//结果为:
    /*    创建book的无参构造方法
                [book01]bean将要调用初始化方法了。。BeforeInitialization。这个bean是这样的[Book{bookName='null', author='null'}]
        这是initBook()方法,初始化方法
                [book01]bean初始化方法之后调用完了。。AfterInitialization。这个bean是这样的[Book{bookName='null', author='null'}]*/
}
//实验11:测试bean的后置处理器:BeanPostProcessor
//证明3:无论bean是否有初始化方法;后置处理器都会默认其有,还会继续工作;
@Test
public void CarTest1(){
    ConfigurableApplicationContext configurableApplicationContext =new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext.xml");
/*
结果为:
    [car01]bean将要调用初始化方法了。。BeforeInitialization。这个bean是这样的[Car{carName='null', price='null', color='null'}]
[car01]bean初始化方法之后调用完了。。AfterInitialization。这个bean是这样的[Car{carName='null', price='null', color='null'}]
*/


}
@Test
public void CarTest02(){
        ApplicationContext ioc = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext02.xml");
    Car car = ioc.getBean("car01", Car.class);
    System.out.println(car);
    //Car{carName='null', price='null', color='null'}
}

}

(五)运用注解来直接创建bean实例

  1. 创建Service包下两个类,分别是BookService.class和BookServiceExt.class,目的是为了验证同样的继承关系,在同样配置注解时,如何辨别和运用;
    (1)BookService.class
package com.atguigu.Service;

import com.atguigu.Dao.BookDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookService {
    @Autowired
    private BookDao bookDao;
    public void save(){
        System.out.println("bookservice....正在调用Dao保存图书");
        bookDao.saveBook();
    }
}

(2)BookServiceExt.class

package com.atguigu.Service;

import org.springframework.stereotype.Service;

@Service
public class BookServiceExt extends BookService {
    @Override
    public void save(){
        System.out.println("BookServiceExt......");
    }
}

  1. 创建一个Servlet包下BookServlet.class,主要是运用注解区分Dao、Servlet、Service层;辨识度高
package com.atguigu.Servlet;

import com.atguigu.Dao.BookDao;
import com.atguigu.Service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;


/*@Autowired:Spring会自动的为这个属性赋值;
一定是去容器中找到这个属性对应的组件*/

@Controller
public class BookServlet {
    /*servlet(控制器)*/
    /*自动装配*/
    /*@Qualifier(限定符 限定词 修饰符):指定一个名作为id,让spring别使用变量名作为id(前提是已经由@autowired注解查找属性时有多个)
    * 特别注意:指定类名开头字母小写*/
    @Qualifier("bookServiceggg")

    //这里多个BookService的本类和继承类,但是没有一个类名是bookServiceggg,所以,找不到,会报空指针异常;
    // 然后,又@Autowired(required=false),设置为false之后,没有强制去自动配置,如果找到则继续,没找到不会报错,变量为null

    @Autowired(required=false)
    private BookService bookServiceExt2;
    public void get(){
        //bookServiceExt2.save();
        System.out.println(".........使用required = false"+bookServiceExt2);
        /*结果为:.........使用required = false   null*/
    }
    /*
    * 方法上有@Autowired的话;
    * 1、这个方法也会在bean创建的时候自动运行
    * 2、这个方法上的每一个参数都会自动注入值
    *
    * */
    /*里面的变量和变量名一样遵循@Autowired原理:*/
    @Autowired
    public  void BookTest(BookDao bookDao, @Qualifier("bookServiceExt") BookService bookService){
        System.out.println("当bean创建的时候自动运行"+bookDao+"---->"+bookService);
    }

}

  1. 创建一个Dao包下的BookDao.class类,目的也是:主要是运用注解区分Dao、Servlet、Service层;辨识度高
package com.atguigu.Dao;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
/*<!--id默认就是类名首字母小写-->*/
@Repository("bookdaohh")
@Scope(value = "prototype")
//作用域为多实例
public class BookDao {
    /*Repository:资源库,仓库*/
    public void saveBook(){
        System.out.println("图书已经保存");
    }
}

  1. **创建applicationContext03.xml文件,特别注意现在属性字段上,方法,构造器,注解上等上面运用注解,其次再运用导包,并依赖context命名空间、最后再用 **<context:component-scan base-package="com.atguigu" ></context:component-scan> 来进行扫描基础包来运行自动配置
<?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-3.0.xsd">


    <!--实验15:通过注解分别创建Dao、Service、Controller(控制器:控制网站跳转逻辑Servlet)
    通过bean上添加某些注解,可以快速的将bean加入到ioc容器中
    某个类上添加上任何一个注解都能快速的将这个组件加入到ioc容器的管理中;
    @Controller:控制器,我们推荐给控制器层(servlet包下的这些)的组件加这个注解
    @Service:业务逻辑;我们推荐业务逻辑层的组件添加这个注解;
    @Repository(仓库,资源库):给数据库层(持久化层,Dao层)的组件添加这个注解
    @Component:给不属于以上几层的组件添加这个注解;

    注解可以随便加:Spring底层不会去验证你的组件;
    是否如你注解所说就是一个dao层或者就是一个servlet层的组件;
    我们推荐各自层加各自的注解,主要面对对象是给我们程序员看的;

    使用注解将组件快速的加入到容器中需要几步;
    1)、给要添加的组件上标四个注解的任何一个
    2)、告诉Spring,自动扫描加了注解的组件;依赖context名称空间
    3)、一定要导入aop包,支持加注解模式;
    context:component(组件)—scan(扫描):自动组件扫描
    base—package:指定扫描的基础包,把基础包以及他下面所有的包所有加了注解的类,自动的扫描进ioc容器-->
    <!--id默认就是类名首字母小写-->

   <!-- /*使用注解加入到容器中的组件,和使用配置加入到容器中的组件行为都是默认一样的;
    1、组件的id,默认就是组件类名的首字母小写
    2、组件的作用域,默认就是单例的;*/-->
    <context:component-scan base-package="com.atguigu" ></context:component-scan>
    <!--注解和bean配置相结合-->

    <!--实验17:使用<context:exclude-filter指定扫描包时不包含的类-->
    <!--扫描的时候可以排除一些不要的组件
    type="annotation":指定排除规则;这里是按照注解进行排除;标注了指定注解的组件不要
    expression="org.springframework.stereotype.Repository":注解的全类名
    type="assignable":指定排除某个具体的类,按照类排除
    expression="com.atguigu.Dao.BookDao":类的全类名-->
    <context:component-scan base-package="com.atguigu">
        <!--<context:exclude-filter type="assignable" expression="com.atguigu.Dao.BookDao"></context:exclude-filter>-->
    </context:component-scan>
    <!--实验16:使用<context:include-filter指定扫描包时要包含的类-->
    <!--1 、只扫描进入哪些组件;默认都是全部扫描进来
        2、一定要禁用掉默认的过滤规则才行;(use-default-filters="false")
    -->
 <!--   <context:component-scan base-package="com.atguigu" use-default-filters="false">
        <context:include-filter type="assignable" expression="com.atguigu.Dao.BookDao"></context:include-filter>
        <context:include-filter type="assignable" expression="com.atguigu.Service.BookService"></context:include-filter>
    </context:component-scan>-->
<!--DI(依赖注入Dependency Injection)-->
<!--实验18:使用@Autowired注解实现根据类型实现自动装配*-->
    <context:component-scan base-package="com.atguigu"></context:component-scan>
<!--实验19:如果资源类型的bean不止一个,
    默认根据@Autowired注解标记的成员变量名作为id查找bean,进行装配*-->
   <!-- @Autowired原理:
    @Autowired
    private BookDao bookDao;
    1)、先按照类型去容器中找到对应的组件;bookService = ioc.getBean(BookService)
        1)、找到一个:找到就赋值
        2)、 没找到:抛异常
        3)、 找到多个?装配上?
            1)、按照变量名作为id继续装配;BookService(bookService)、BookServiceExt(bookServiceExt)
            (例如:@Autowired
                    private BookService bookServiceExt;
                    按照这个变量名:bookServiceExt)

                    实验20:如果根据成员变量名作为id还是找不到bean,可以使用@Qualifier注解明确指定目标bean的id*
                    1、匹配上;装配
                    2、没有匹配?报错
                    原因:因为我们按照变量名作为id继续匹配的;
                        实验21:在方法的形参位置使用@Qualifier注解
                    使用@Qualifier("bookServiceExt")指定一个新id
                            1、找到:装配
                            2、找不到:报错;
                            实验22:@Autowired注解的required属性指定某个属性允许不被设置
    发现@Autowired标注的自动装配的属性默认是一定装配上的;
                找到就装配,找不到就拉倒;
@Autowired注解:特别注意不光可以用在变量上,也可以用在属性字段上,方法,构造器,注解上等上面    -->
    <!--@Autowired注解、@Resource、@Inject:都是自动装配的意思;
    @Autowired注解:
    优点:最强大;
    缺点:只适用于Spring框架自己的注解

     @Resource:javaee;java的标准;
     优点:扩展性更强,因为是java的标准;
     如果切换成另外一个容器框架,@Resource还是可以使用的,@Autowired就不行了




    -->



</beans>
  1. 创建IOCTest4.class文件来测试
package com.atguigu.test;

import com.atguigu.Service.BookService;
import com.atguigu.Servlet.BookServlet;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

/*
 *目的是:创建变量并给它一个@Autowired自动装配,在一个方法里面可以直接用(不用写ioc容器和ioc.get)
 * 使用Spring的单元测试;
 *    1、导包:Spring单元测试包spring-test-4.0.0.RELEASE.jar
 *    2、@ContextConfiguration(locations ="")使用它来指定Spring的配置文件的位置
 *    3、@RunWith指定用哪种驱动进行单元测试,默认就是junit
 * @RunWith(SpringJUnit4ClassRunner.class)
 * 使用Spring的单元测试模块来执行标了@Test注解的测试方法;
 * 以前的@Test注解只是由junit执行
 *好处:我们不用ioc.getbean()获取组件了;直接Autowired组件,Spring为我们自动装配
 * */
//@RunWith(SpringJUnit4ClassRunner.class)
//@ContextConfiguration(locations = "classpath:applicationContext03.xml")
/*严重: Caught exception while allowing TestExecutionListener [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@3e6fa38a] to prepare test instance [com.atguigu.test.IOCTest4@66a3ffec]
        java.lang.IllegalStateException: Failed to load ApplicationContext*/
public class IOCTest4 {
    ApplicationContext ioc = new FileSystemXmlApplicationContext("D:\\iderAllProject\\IderWorkspace_Spring\\src\\applicationContext03.xml");
//    ApplicationContext ioc = null;

    private BookService bookService;
    private BookServlet bookServlet;
    @Test
    public void UnitTest1(){
        System.out.println("bookService=="+bookService+","+"bookServlet=="+","+bookServlet);
    }


    /*使用注解加入到容器中的组件,和使用配置加入到容器中的组件行为都是默认一样的;
            1、组件的id,默认就是组件类名的首字母小写
                            @Repository("别名")
                            @Repository("bookdaohh")
            2、组件的作用域,默认就是单例的;
                            @Scope("prototype")*/

    @Test
    public void AnnotationTest1(){
        /*注解Annotation comment Note*/
        Object bookDao = ioc.getBean("bookdaohh");
        Object bookDao2 = ioc.getBean("bookdaohh");
        System.out.println(bookDao == bookDao2);
        /*返回true是单实例*/
    }
    @Test
    public void AutowiredTest1(){
        BookServlet bookServlet = (BookServlet)ioc.getBean("bookServlet");
        bookServlet.get();
    }
    @Test
    public void AutowiredTest2(){
        /*@Autowired自动装配注解可以放在方法上面*/

        /*打印结果为:当bean创建的时候自动运行com.atguigu.Dao.BookDao@a3d8174---->com.atguigu.Service.BookService@1ba9117e*/
    }
}

  1. 报错总结
1、用的配置文件无效,嵌套异常,无法找到声明;
报错原因:org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException:
      Line 26 in XML document from file
      [D:\iderAllProject\IderWorkspace_Spring\src\applicationContext03.xml] is invalid(无效的);
      nested(嵌套) exception is org.xml.sax.SAXParseException;
      lineNumber: 26; columnNumber: 57; cvc-complex-type.2.4.c: 通配符的匹配很全面, 但无法找到元素 'context:component-scan' 的声明。
解决方法:在Spring配置文件中定义context命名空间和相应的schemaLocation(两个)相对应
(xmlns:context="http://www.springframework.org/schema/context"
     http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-3.0.xsd")

2、中文解释:创建bean配置异常,不能自动装配private com.atguigu.Service.BookService com.atguigu.Servlet.BookServlet.bookServiceExt2;
在自动装配的时候有两个一样的变量,但是配置变量名bookServiceExt2异常
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'bookServlet':
Injection of autowired dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Could not autowire field: private com.atguigu.Service.BookService com.atguigu.Servlet.BookServlet.bookServiceExt2;
nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type [com.atguigu.Service.BookService] is defined: expected single matching bean but found 2: bookService,bookServiceExt
解决办法;面对这种情况,有两个一样的变量,则使用@Qualifier:指定一个名作为id,让spring别使用变量名作为id(前提是已经由@autowired注解查找属性时有多个)




这里就把基本的bean配置和到注解实验验证完毕;后面开始就需要学习AOP了哦!

如有不懂可以加我并练习哦;
个人也有免费大学生毕业网站和答辩项目总集;
并提供免费软件和教学视频;
QQ+2545062785

此文章的一部分图片和所用学习笔记,学习历程来源于B站的UP主雷Java-spring-springmvc-mybatis-雷丰阳版-ssm一站式学习-尚硅谷,点击该段话,跳转视频地址

把此作为笔记,如有侵权或者不允许截图等,会马上删除的,谢谢!


以上总结,当采纳和对你有帮助时;
🤞👣👀👇🤝🙌🍗
留下你的点赞足迹+你爱心的评论哦!
🉐(⓿_⓿)谢啦!!☆⌒(*^-゜)v

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章