Spring理解1 ioc
阅读原文时间:2023年07月11日阅读:3

Spring

Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器(框架)。

需要了解

ioc容器

IOC底层原理

IOC接口 BeanFactory

Bean的作用域

IOC操作Bean管理(基于xml)

IOC操作Bean管理(基于注解)

IOC概念和原理

控制反转 降低代码之间的耦合度

把对象创建和对象之间调用过程全交给spring 管理

使用ioc目的是降低耦合度

在Java基础中 我们通常创建多个类,在一个类中调用其他的类的方法需要实现一下方式

创建UserDao接口

public interface UserDao {
    public  void Trick();
}

创建一个实现接口的类

public class UserDaoImpl implements UserDao{

    @Override
    public void Trick() {
        System.out.println("我是石大炮 我想trick....");

    }
}

再创建另一个UserService接口

public interface UserService {
    public  void  cick();
}

实现接口方法

public class UserServiceImpl implements UserService {
    UserDao userDao=new UserDaoImpl();
    @Override
    public void cick() {
        userDao.Trick();
    }
}

最后添加测试类

public class TestService {
    @Test
    public  void Test1(){
        UserService userService=new UserServiceImpl();
        userService.cick();
    }
}

结果:我们在UserServiceImpl实现类中成功调取了UserDaoImpl中的方法

这种方式耦合度太高 ,一旦一个类的方法或属性发生改变,其他的类也需要更改,正所谓牵一发而全身,我们是否可以解决这个问题呢?

IOC容器的概念和原理

IOC 叫做控制反转其实和DI 依赖注入的功能相同,如果我们将对象的创建交给第三方组件来管理,当我创建的某个类需要另外的对象的时候,我们直接利用第三方组件来对他进行创建交给他。

Spring容器(ioc)就是一个容器组件负责帮我们管理。当UserDaoImpl类需要UserServiceImpl类中的对象时,如果UserServiceImpl类已经声明了交给Spring容器管理的情况下,那么程序在运行到类UserDaoImpl类需要UserServiceImpl类时候,Spring容器就通过依赖注入的方式将器对象注入到另一个类中来协助完成任务。

我们通过第三方的依赖注入,对象就不需要自行的创建和管理类与类之间的关系。

对象的创建依赖注入有多种:接口注入 ,构造方法注入,setter方法注入等等来减少代码组件中的耦合度

所谓ioc的控制反转其实就是当初是我来实现创建和管理对象之间的关系的,而现在出现了ioc容器,那我就可以直接当撒手掌柜,将这份权力交给ioc容器,让他实现我当初要干的苦活累活。这就是所谓的控制反转---控制权的反转。

IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,新版本的Spring也可以零配置实现IoC。

Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。

IOC说到底就是一个容器,但是如何向容器中放入我们的需要让他给我们管理的对象呢?涉及到Spring的应用上下文!

应用上下文  即是spring容器的抽象化表述。Spring核心是容器但是容器并不唯一,我们需要实现容器,所以需要应用上下文的存在

ioc容器底层就是对象工厂

                       spring提供了ioc容器的实现两种方式(两个接口)

               (1)BeanFactory ioc容器最基本的实现spring内部自带的接口 不提供开发人员使用

               (2)ApplicationContext BeanFactory的一个子接口 提供了更强大的功能 面向开发人员使用

此处只讨论第二个,第一个用的不多。ApplicationContext从一个或多个基于java配置类中加载上下文定义,适用于java注解方式

以下是不同常见下选择的应用上下文来对于容器的实现:

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

ioc实现步骤:

第一步 导入jar包maven

第二步 xml配置文件 配置创建的对象

第三步 有Service和Dao类 创建工程类

第四步将我们需要管理的对象(我们称之为bean)bean之间协作关系配置好,然后利用配置上下文加载到我们的Spring容器 容器就能给我们提供服务了

演示:

首先创建一个类

public class Person {
    String name;
    int age;
    String gender;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
    public  void Cry(){
        System.out.println("我为我叫石大炮而感到悲伤....");
    }
}

第二步在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:p="http://www.springframework.org/schema/beans/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    创建对象-->
    <bean id="person" class="com.atqijie.spring5.collectiontype.Person">
<!--       配置属性注入-->
        <property name="name" value="石大炮"/>
        <property name="age" value="22"></property>
        <property name="gender" value="男"></property>

    </bean>

</beans>

第三步利用应用上下文将配置加载到ioc容器中让spring替我们管理对象 ,在我们需要对象的时候再通过容器中获取就可

package Test;

import com.alibaba.druid.sql.ast.ClusteringType;
import com.atqijie.spring5.collectiontype.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test2 {
@Test
    public void TestPerson(){
    //    提供应用上下文将配置加载到ioc容器 让Spring替我们管理对象 待我们需要对象的时候直接从从容器中获取即可
    ApplicationContext context= new ClassPathXmlApplicationContext("bean1.xml");
//    我们从容器中获取我们想要的对象
    Person person=context.getBean("person", Person.class);
      person.Cry();
     int personAge= person.getAge();
    String personName=person.getName();
    String personGender=person.getGender();
    System.out.println(personName);
    System.out.println(personGender);
    System.out.println(personAge);
}
}

结果:

由上我们实现了在spring中创建对象,对象的属性同样由容器配置。我们将对象创建的主动性交给了spring容器,程序被动的接受了对象并没有像往常一样创建对象 即 实现了控制反转 也称控制权反转(个人理解)

重点细节:

IOC管理bean的两种方式(创建需要的对象和对其属性进行配置)

1 xml配置文件方式来实现(上述即xml配置文件方式实现)//用的不多建议 听说面试问的比你用的多?

2基于注解方式来实现

3创建对象注入属性方式有多种 构造方法,使用set等创建对象和属性初始化

1xml配置文件方式实现:

1.1 利用xml配置文件来创建对象

<bean id="person" class="com.atqijie.spring5.collectiontype.Person">

1.1.2基于xml方式注入属性

!--       配置属性注入-->
        <property name="name" value="石大炮"/>
        <property name="age" value="22"></property>
        <property name="gender" value="男"></property>

依赖注入:通过构造方法和set方法来进行依赖注入(设置属性初始化)

1构造方法的方式进行依赖注入

1无参构造

创建Animal类

package com.atqijie.spring5.collectiontype;

public class Animal {
    String name;
    int age;

    public Animal() {
        System.out.println("这是一个无参构造的方法");
    }

    public  void Do(){
        System.out.println("我是胖虎你是静香吗.....?");
    }

    public void setName(String name) {
        this.name = name;
    }

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

创建对象

<bean id="animal" class="com.atqijie.spring5.collectiontype.Animal">
    <property name="name" value="胖虎"></property>
    <property name="age" value="22"></property>
</bean>

利用应用上下文将我们的配置加载ioc容器中,测试一下

@Test
    public  void TestAnimal(){
    ApplicationContext context=new ClassPathXmlApplicationContext("bean1.xml");
    Animal animal=context.getBean("animal",Animal.class);
    animal.Do();
}

结果

我们知道了在我们调取Do方法之前,我们的无参构造方法已经创建了Animal对象

xml创建对象的时候默认也是执行无参构造造的方法

2有参构造来创建

public class Dog {
    String name;
    int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Dog() {
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
    public  void check(){
        System.out.println("我是静香啊..."+name);
    }
}

xml编写 分几种

第一种 根据名称来设置属性

<bean id="dog" class="com.atqijie.spring5.collectiontype.Dog">
    <constructor-arg name="name" value="胖虎"></constructor-arg>

第二种根据index 下标设置属性

<!--index =0是第一个值 index=1 是第二个值 都是判断第几个的 一般直接使用名称来找 -->
<!--        <constructor-arg index="0" value="胖虎"/>-->

第三种根据参数类型设置属性

<!-- 第三种根据参数类型设置 -->
<bean id="userT" class="com.atqijie.spring5.collectiontype.Dog">
    <constructor-arg type="java.lang.String" value="小夫"/>
</bean>

测试一下

@Test
    public  void TestDog(){
    ApplicationContext context =new ClassPathXmlApplicationContext("bean1.xml");
    Dog dog=context.getBean("dog",Dog.class);
    dog.check();
}

结果

bean属性

 在spring配置文件中 使用bean标签 标签里面添加对应属性 就可以实现对象创建

在bean标签中有许多属性介绍的常用属性

 1 id属性:对对象起一个别名 唯一的标识 与前者对应 属于唯一的标识

 2 class属性

     类的全路径(包 类路径)类似前端的imgsrc的相对路径

     name属性 name=“ ”和id作用一样 用的少

 3 import

2利用Set方法进行属性注入(注入依赖)

要求被注入的属性 , 必须有set方法 , 如果属性是boolean类型 , 没有set方法 , 是 is .

  2.1(xml注入其他类型属性)

     1null 空值

     2属性值包含特殊符号

     1null空值

   2使用值中包含特殊符号

结果:

2.2如何注入属性

    2.2.1外部bean

<bean id="UserService " class="com.atqijie.spring5.Service.UserService ">
    <!-- 在service层中注入userDao对象 name 是类里面的属性名称 ref属性指的是创建UserDao对象bean标签的id值-->
    <!--        用到ref表示把外部bean注入进来表示把其他对象进行注入-->
    <property name="userDao" ref="UserDao1"></property>

</bean>
<!-- 2创建dao对象       -->
<bean id="UserDao1" class="com.atqijie.spring5.Dao.UserDaoImpl">

</bean>

属性注入 一般set方法的属性注入式但此时是对外部类进行属性注入属于外部bean 所以需要ref来调 ref的值必须与创建的id的值相同

 2.2.2内部bean

   (1)一对多关系:部门和员工:   一个部门多个员工 一个员工属于一个部门

    (2)在实体类中表示一对多的关系:员工表示所属部门 使用对象类型属性进行表示

//部门类
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}

//员工类
public class Emp {
private  String ename;
private  String egender;
//员工属于某一个部门 使用对象形式表示
private  Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setEgender(String egender) {
this.egender = egender;
}
}

<bean id="emp" class="com.atqijie.spring5.bean.Emp">
<!--设置属性 前两个是基本属性 第三个是对象属性    -->
<property name="ename"  value="石晨霖"></property>
<property name="egender" value="女"></property>
<!--对象类型属性   在对象里边嵌套做定义 在一个bean里面嵌套定义另一个bean对象 -->
<property name="dept" >
    <bean id="dept" class="com.atqijie.spring5.bean.Dept">
        <property name="danme" value="保安部"></property>
    </bean>
</property>
</bean>

2.2.3级联赋值

同时向和你有关的类中进行赋值   多个对象之间的映射赋值

  1第一种级联赋值的方法

    在外部bean中注入属性后再引用

        <!--级联赋值  -->
<bean id="emp" class="com.atqijie.spring5.bean.Emp">
<!--设置属性 前两个是基本属性 第三个是对象属性    -->
<property name="ename"  value="石晨霖"></property>
<property name="egender" value="女"></property>
<!--级联赋值 1先在外部bean中注入属性后,再引用-->
<property name="dept" ref="dept"></property>
</bean>
        //再外部bean中先注入属性给dept中的普通属性赋值
        再在员工类中进行引用 调用外部类的方法是ref 与上述的外部bean注入属性一样
<bean id="dept" class="com.atqijie.spring5.bean.Dept">
<property name="dname" value="财务部"></property>
</bean>

2表达式形式 直接引用外部bean的形式

    dept是emp的属性

    dname是dept的属性

<bean id="emp" class="com.atqijie.spring5.bean.Emp">
<!--设置属性 前两个是基本属性 第三个是对象属性    -->
<property name="ename"  value="石晨霖"></property>
<property name="egender" value="女"></property>
<!--级联赋值 1先在外部bean中注入属性后,再引用-->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="法务部"></property>
</bean>
<bean id="dept" class="com.atqijie.spring5.bean.Dept">
</bean>

有一个注意点,该方式必须在emp实体类中生成dept属性的get方法,否则会报dept属性找不到 就不能赋值

private Dept dept;
//生成dept的get方法,必不可少
public Dept getDept(){
return dept;
}

dept是private 修饰 得到她需要get方法

以上是基于xml方式做bean管理的操作

                    用xml方式创建对象

                    注入属性

                    注入外部bean

                    内部bean

                    级联赋值

 3(xml注入集合类型属性)

        public class Stu {
        //数组类型属性
        private  String[] coursers;
        //创建List集合类型属性
        private List<String> list;
//Map集合类型属性
private Map<String,String> maps;
//定义set集合类型属性
private Set<String> set;

    public void setList(List<String> list) {
        this.list = list;
        }

        public void setMaps(Map<String, String> maps) {
        this.maps = maps;
        }

        public void setCoursers(String[] coursers) {
        this.coursers = coursers;
        }
        public void setSet(Set<String> set) {
            this.set = set;
            }

            }


        <!--1 集合属性类型属性注入-->
<bean id="stu" class="com.atqijie.spring5.collectiontype.Stu">
<!--    数组类型的属性注入  value是一个值 但是现在是数组-->
<property name="coursers" >
    <!--    用list 和array都可以-->
    <array>
        <value>java课程</value>
        <value>数据库课程</value>
    </array>
</property>
<!--    list集合类型注入-->
<property name="list">
    <list>
        <value> 张三</value>
        <value> 小三</value>
    </list>

</property>
<!--    Map类型属性注入 map key value 和之前的list只有value不同-->
<property name="maps">
    <map>

        <entry key="JAVA" value="java"></entry>
        <entry key="PHP" value="php"></entry>
    </map>
</property>
<!--    Set集合类型属性-->
<property name="set">
    <set>
        <value>mysql</value>
        <value>redis</value>
    </set>
</property>

</bean>

4在集合内设置对象类型值

        <!--    注入的是list集合类型 值是对象的形式 此时是对象类型值 不在是之前的普通string类型 需要用到ref-->
<property name="courselist">
<list>
    <ref bean="course1"></ref>
    <ref bean="course2"></ref>
</list>
</property>

        </bean>
        <!--创建多个course对象-->
<bean id="course1" class="com.atqijie.spring5.collectiontype.Course">
<property name="cname" value="Spring5框架"></property>
</bean>
<bean id="course2" class="com.atqijie.spring5.collectiontype.Course">
<property name="cname" value="Mybatics框架"></property>
</bean>

5 把集合注入部分提取出来。

     让他作为公共部分,别的对象也能使用

    1 在spring配置文件中先引入名称空间uti

 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/beans/p"
       xmlns:util="http://www.springframework.org/schema/util"
       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">

      2使用util标签 完成List集合注入提取

        <!--1提取list集合类型注入 -->
<util:list id="booklist" >
<value><![CDATA[三国演义]]></value>
<value><![CDATA[红楼梦]]></value>
<value><![CDATA[水浒传]]></value>
</util:list>
        <!--    提取list集合注入的使用-->
<bean id="book" class="com.atqijie.spring5.collectiontype.Book">
<property name="list" ref="booklist"></property>
</bean>

     3p命名和c命名注入

       P命名空间注入 : 需要在头文件中加入约束文件

     导入约束 : xmlns:p="http://www.springframework.org/schema/p"

        <!--P(属性: properties)命名空间 , 直接注入属性-->
<bean id="user" class="com.atqijie.spring5.collectiontype.Monkey" p:name="scl" p:age="18"/>

        c 命名空间注入 : 需要在头文件中加入约束文件

        导入约束 : xmlns:c="http://www.springframework.org/schema/c"
        <!--C(构造: Constructor)命名空间 , 使用构造器注入-->
<bean id="user" class="com.atqijie.spring5.collectiontype.Monkey" c:name="scl" c:age="18"/>

Bean的作用域

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象

几种作用域中,request、session作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于web的Spring ApplicationContext环境。

Singleton(单例模式)

    1在spring中可以设置bean实例时单实例还是多实例

    2在spring默认情况下创建的bean是一个单实例对象 但是可以设置从多实例对象

当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:

<bean id="monkey" class="com.atqijie.spring5.collectiontype.Monkey" scope="singleton">
    <property name="name" value="大雄"/>
</bean>


@Test
public void TestMonkey() {
    ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
    Monkey monkey1 =  context.getBean("monkey", Monkey.class);
    Monkey monkey2=context.getBean("monkey",Monkey.class);
    System.out.println(monkey1);
    System.out.println(monkey2);
}

由此可见在单例模式下只要id与其匹配ioc容器创建的bean的对象就是同一个。

Prototype(原型模式)

我们是否可以创建多个不同的对象?答案当然是可以的

当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:

<bean id="monkey" class="com.atqijie.spring5.collectiontype.Monkey" scope="prototype">

Request

当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

 <bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。

Session

当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

 <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。

  虽然容器功能强大,但容器本身只是个空壳,需要我们主动放入装配对象,并告诉它对象之间的协作关系,然后容器才能按照我们的指示发挥它的魔力,完成装配bean的使命。

  这里,我们把Spring创建应用对象之间的协作关系的行为成为装配。Spring提供了很多装配bean的方式供我们在开发中选择。

  我们常用到的有三种装配机制:自动装配Java注解XML配置。通常我们将第一种称为隐式的装配机制,后面两种为显示的装配机制。

  实际应用中,基于便利性考虑,首选的肯定是隐式的自动化装配机制,只有当需要注入的bean的源码不是由自己的程序来维护,而是引入第三方的应用组件的时候,才考虑显示的方式装配bean。当然,各种装配方式在实际应用中是可以自由选择搭配的,编码过程中也不必拘泥哪一种,适用就好。

  • 自动装配是使用spring满足bean依赖的一种方法
  • spring会在应用上下文中为某个bean寻找其依赖的bean。
  1. 在xml中显式配置;
  2. 在java中显式配置;
  3. 隐式的bean发现机制和自动装配。

Spring的自动装配需要从两个角度来实现,或者说是两个操作:

  1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;
  2. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

组件扫描和自动装配组合发挥巨大威力,使得显示的配置降低到最少。

推荐不使用自动装配xml配置 , 而使用注解  在实际开发中目前的绝大多数都是使用注解来实现自动装配.

xml的自动配置

演示自动装配过程

//手动装配注入外部bean

    !--创建对象-->
<bean id="emp" class="com.atqijie.spring5.collectiontype.autowire.Emp">
<property name="dep" ref="dep"></property>
</bean>
<bean id="dep" class="com.atqijie.spring5.collectiontype.autowire.Dep"></bean>
        </beans>

自动装配

 <!--创建对象-->
        <!--   实现自动装配
         bean标签中属性 autowire
         属性常用两个值
          byName根据属性名称注入 注入的id的值 要和类属性名称一样
         byType更具属性类型注入
         -->
<bean id="emp" class="com.atqijie.spring5.collectiontype.autowire.Emp" autowire="byName">
<!--    <property name="dep" ref="dep"></property>-->
</bean>
<bean id="dep" class="com.atqijie.spring5.collectiontype.autowire.Dep">

</bean>

1byName根据属性名称自动注入

<bean id="user" class="com.kuang.pojo.User" autowire="byName"> <property name="str" value="qinjiang"/> </bean>

当一个bean节点带有 autowire byName的属性时。

2byType根据属性类型自动注入

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。

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

<bean id="user" class="com.kuang.pojo.User" autowire="byType">
&nbsp; &nbsp;<property name="str" value="qinjiang"/>
</bean>

如果有多个外部bean 需要使用byName 否则会报错

再实际中用的很少 崩溃^^

以上是bean创建对象和注入属性

-----------------------------------------------------------------------------  这是一个不知名的分隔符----------------------------------------------------------------------------------------------------

Bean管理的第二种方式 :注解

1什么是注解

        1代码特殊标记格式:@注解名称 (属性名称=属性值。属性名属性值)

2使用注解 注解作用在类上面 方法上,属性上

3 使用注解目的是 简化xml配置

2 Spring针对Bean管理创建对象提供注解()

1)@Component

           普通组件

  (2)@Service

           业务逻辑层

(3)@Controller

            web层

(4)@Repository

            dao层

*四个注解功能相同都可以用来创建bean实例

基于注解方式实现对象创建:

准备工作:利用注解的方式注入属性。

1、在spring配置文件中引入context文件头

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

开启属性注解支持

<context:annotation-config/>

第一步:引入依赖 导入jar包

第二步:开启组件扫描

告诉spring容器 哪个里面有注解 然后扫描

context

<context:component-scan base-package="Service,com.atqijie.spring5.collectiontype"></context:component-scan>

   <!--引入名称空间-->
        <!--    开启组件扫描看哪个包哪个类中有注解 此标签是组件扫描 basepackage 是包的名称-->
        <!--  1  扫描多个包使用逗号隔开
              2只写扫描包的上层目录

        -->
        <!--    <context:component-scan base-package="com.atqijie.spring5.collectiontype.Service,com.atqijie.spring5.collectiontype.dao"></context:component-scan>-->
<context:component-scan base-package="com.atqijie"></context:component-scan>

第三步创建类 在类上面添加创建对象注解

在注解中value值可以不写  默认值是类名称首字母小写

     import org.springframework.stereotype.Component;
        //使用注解方式创建对象(value属性值可以省略)
        //默认值是类名称 首字母小写  UserSservice------userService
        @Component(value = "userService")//<bean id="userService" class="...">
public class UserService {
public  void add(){
System.out.println("service add..........");
}

第四步 开启组件扫描的细节配置

看懂即可

   !--    <context:component-scan base-package="com.atqijie.spring5.collectiontype.Service,com.atqijie.spring5.collectiontype.dao"></context:component-scan>-->
<context:component-scan base-package="com.atqijie"></context:component-scan>
        <!--    use-default-filters="false表示不使用默认filters自己配置filter 过滤器
        context:include-filter 扫描那些内容 annotation 根据注解来扫描  只扫描带controller来扫描
        -->
<context:component-scan base-package="com.atqijie" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>

基于注解方式实现属性注入

假设我们需要在service层中调用dao层的方法 此时用注解的方法

@AutoWired

根据属性类型进行自动装配注入:

自动装配注解只能用于带参数的方法:

第一步 把service 和dao对象创建 ,在service 和dao类添加创建对象注解

@Service
public interface PeopleDao {

    public void add();

}


@Repository
public class PeopleDaoImpl implements PeopleDao{
    @Override
    public void add() {

        System.out.println("我scl会上不去白银?");
    }
}

第二步 在service中注入dao的对象 在service类中添加dao类型属性 在属性上使用注解 不需要添加set方法

//被注解的java类当作bean实例
@Service(value ="peopleServiceImpl")
public class PeopleServiceImpl {
//    装配bean
@Autowired//根据类型进行注入
    private  PeopleDao peopleDao;

    public void play() {
        System.out.println("我是小夫");
      peopleDao.add();
                          }
}

测试

public class TestService2 {
    @Test
    public void TestPeopleServiceImpl() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
        PeopleServiceImpl peopleServiceImpl = context.getBean("peopleServiceImpl", PeopleServiceImpl.class);
        peopleServiceImpl.play();
    }
}

结果

@Qualifier

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

  • @Qualifier不能单独使用。

  • 一个接口可以有多个实现类 但是如果我们需要一个接口某个特定的实现类,光靠AutoWired根据类的类型注入就不行了。需要具体到某个类名

  • 名称可以不写 默认首字母小写

  • //被注解的java类当作bean实例
    @Service(value ="peopleServiceImpl")
    public class PeopleServiceImpl {
    // 装配bean
    @Autowired//根据类型进行注入
    @Qualifier(value = "SCL")
    private PeopleDao peopleDao;

        public void play() {
            System.out.println("我是小夫");
          peopleDao.add();
                              }
    }

@Resource

既可以根据类型注入 也可以根据属性注入

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

注意Resource 是javax包中的

@Value 注入普通属性

小结

@Autowired与@Resource异同:

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

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

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

它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

作用域

@scope

  • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。

  • prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收

    @Controller("user")
    @Scope("prototype")
    public class User {
    @Value("scl")
    public String name;
    }

纯(完全)注解开发

1创建配置类 替代xml配置文件 放到配置类中

@Configuration//此注解的作用是 让下面的配置类来替代xml配置文件
@ComponentScan(basePackages = {"com.atqijie"})
public class SpringConfig {

}

2 编写测试类

实际开发中使用springBoot来实现完全注解开发

@Test//涉及到SpringBoot
public void testService2() {
    ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    UserService userService = context.getBean("userService", UserService.class);//不写默认第一个字母小写 与id一样
    System.out.println(userService);
    userService.add();

}

本人(学生)也在自学ing,定期写一些博客总结近期的感悟与体会^^

从最基本的开始 加油!

2022年2月20日