Spring 6 第3章——容器:IoC

news2025/1/21 23:24:35

一、IoC容器

IoC是Inversion of Control的简写,翻译为“控制反转”.它不是一门技术,而是一种设计思想

Spring通过IoC容器来管理(1)所有Java对象的实例化和初始化,(2)控制对象与对象之间的依赖关系

我们将由IoC容器管理的Java对象称为Spring Bean,它与用关键字new创建的Java对象没有任何区别

即用IoC容器来放对象,并管理对象从创建到销毁的全部过程

IoC容器放对象,使用Map集合

(1)控制反转

  1. 控制反转是一种思想
  2. 控制反转是为了降低程序的耦合度,提高程序的扩展力
  3. 控制反转,反转的是什么:
    1. 将对象的创建权力交出去,交给IoC容器负责
    2. 将对象和对象之间关系的维护权交出去,交给IoC容器负责
  4. 控制反转这种思想如何实现呢?DI(Dependency Injection):依赖注入

(2)依赖注入

  1. 在配置文件中配置好,针对于某个类我们想要什么样的对象,把这个信息交给IoC。然后由IoC创建、返回对象
  2. DI(Dependency Injection):依赖注入,依赖注入体现了控制反转的思想(初始化)
  3. 依赖注入:是指Spring在创建对象的过程中,将对象的属性的通过配置进行注入
  4. 依赖注入常见的实现方式包括两种:
    1. 第一种:set注入
    2. 第二种:构造注入
  5. 结论:IoC是一种控制反转的思想,而DI是IoC的一种具体实现
  6. Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值

(3)IOC容器在Spring的实现

  1. Spring的IoC容器就是IoC思想的一个落地的产品实现。在创建bean之前,首先需要创建IoC容器
  2. Spring提供了实现IoC容器的两种方式:
    1. BeanFactory:这是IoC容器的基本实现,是Spring内部使用的接口。面向Spring本身,不提供给开发人员使用
    2. ApplicationContext:BeanFactory的子接口,提供了更多高级特性。面向Spring的使用者,几乎所有场合都使用ApplicationContext而不是BeanFactory
  3. ApplicationContext的主要实现类:
  4. ApplicationContext的主要实现类介绍:
    类型名简介
    ClassPathXMLApplicationContext读取类路径下的XML格式的配置文件创建IoC容器对象
    FileSystemXMLApplicationContext通过文件系统路径读取XML格式的配置文件创建IoC容器对象
    ConfigurableApplicationContextApplicationContext的子接口,包含一些扩展方法refresh()和close(),让ApplicationContext具有启动、关闭和刷新上下文的能力
    WebApplicationContext专门为Web应用准备,基于Web环境创建IoC容器对象,并将对象存入ServletContext域中

二、基于XML管理Bean

(1)搭建子模块spring-ioc-xml

  1. 我们把spring-first的依赖都让父工程管理(即将spring-first的pom.xml文件中的dependencies标签和该标签里的所有内容放到spring6的pom.xml文件中,然后刷新):
  2. 搭建好子模块spring-ioc-xml后发现:因为此时它继承了父模块的所有依赖项
  3. 要在模块中使用spring,就必须有spring的配置文件,所以我们在spring-ioc-xml的src/main/resources中创建bean.xml(名字可以随便起)
  4. 还要引入log4j2的配置文件:
  5. 在spring-ioc-xml的src/main/java下新建一个类

(2)实验一:获取bean

准备操作:

  1. 方式一:根据id获取
    1. id属性指定了bean的唯一标识
    2. 演示:
      package com.atguigu.spring6.iocxml;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestUser {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
              //获取bean
              User user = (User)context.getBean("user");
          }
      }

    3. Loaded 1 bean definitions from class path resource [bean.xml]意思是加载spring配置文件

    4. Creating shared instance of singleton bean 'user'意思是创建了一个单例对象

  2. 方式二:根据类型获取
    1. 此时根据id得到对象和根据类型得到对象,二者返回的是同一个对象(因为单例)
    2. 演示:
      package com.atguigu.spring6.iocxml;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestUser {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
              //1.根据id获取bean
              User user1 = (User)context.getBean("user");
              System.out.println("根据id获取bean:" + user1);
              //2.根据类型获取bean
              User user2 = context.getBean(User.class);
              System.out.println("根据类型获取bean:" + user2);
          }
      }

  3. 方式三:根据id和类型
    1. 演示:
      package com.atguigu.spring6.iocxml;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestUser {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
              //1.根据id获取bean
              User user1 = (User)context.getBean("user");
              System.out.println("根据id获取bean:" + user1);
              //2.根据类型获取bean
              User user2 = context.getBean(User.class);
              System.out.println("根据类型获取bean:" + user2);
              //3.根据id和类型获取bean
              User user3 = context.getBean("user", User.class);
              System.out.println("根据id和类型获取bean:" + user3);
          }
      }

    2. user1,user2和user3的地址值都是一样的
  4. 用后两种方式时,因为已经指定了类型,所以不需要我们强转 
  5. 注意:在bean.xml文件中给同一个类配置bean标签时,id值只能有一个
    1. 假如,我们给同一个类配置不同的id值,那么在用类型获取bean对象时就会报错
    2. 我们先把用id获取bean对象的代码注释掉,然后运行
    3. 但是我们发现,如果我们用id获取bean对象,或者用id和类型获取bean对象,就不会报错。因为根据id就可以精准定位
    4. expected single matching bean but found 2: user,user1该错误信息表示:期望获得一个单实例的bean,但是获取了两个
    5. 也就是说,一个bean标签对应着一个单实例的bean。此时我们对同一个类设置了两个bean标签,我们分别用它们的id来获取bean,可以看到,这确实是两个不同的bean
      package com.atguigu.spring6.iocxml;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      
      public class TestUser {
          public static void main(String[] args) {
              ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
              //1.根据id获取bean
              User user = (User)context.getBean("user");
              System.out.println("根据id获取bean:" + user);
              User user1 = (User)context.getBean("user1");
              System.out.println("根据id获取bean:" + user1);
          }
      }

  6. 扩展知识:
    1. 如果一个接口有一个实现类,我们可以根据该接口得到bean吗
    2. 如果一个接口有多个实现类,我们可以根据该接口得到bean吗
  7. 我们写一个接口UserDao,再写一个类UserDaoImpl,让它实现UserDao
  8. 这么写就类似于new UserDaoImpl,因为接口是不能new的
  9. 在新建类里测试一下,根据接口类型获取实现类的对象:上面四张图是代码,然后我们运行main方法,发现可以通过接口类型得到实现类的对象:
  10. 如果一个接口有多个实现类,我们能通过接口类型得到实现类的对象吗
  11. 运行main方法发现,如果一个接口有多个实现类对象,那就无法通过接口类型获取实现类的对象了

(3)实验二:依赖注入之setter注入

  1. 类有属性,创建对象的过程中,给属性设置值
    1. 第一种方式:基于set方法完成
    2. 第二种方式:基于构造器完成
  2. 创建一个Book类:
    package com.atguigu.spring6.iocxml.di;
    
    public class Book {
        private String bname;
        private String author;
    
        //生成set方法
        public void setBname(String bname) {
            this.bname = bname;
        }
    
        public void setAuthor(String author) {
            this.author = author;
        }
    
        //生成有参数的构造器
        public Book(String bname, String author) {
            this.bname = bname;
            this.author = author;
        }
    
        //生成无参数的构造器
        public Book() {
        }
        
        //toString方法
        @Override
        public String toString() {
            return "Book{" +
                    "bname='" + bname + '\'' +
                    ", author='" + author + '\'' +
                    '}';
        }
    
        public static void main(String[] args) {
            //set方法注入
            Book book = new Book();
            book.setBname("java");
            book.setAuthor("尚硅谷");
    
            //构造器注入
            Book book1 = new Book("c++","尚硅谷");
        }
    }
  3. 配置bean标签时为属性赋值(此时我们重新建了一个配置文件,名字可以随便起。Spring相关的配置文件都要放在src/main/resources下面):name对应类的属性名、value对应类的属性值
  4. 测试代码如下,因为我们此时使用的是bean-di.xml文件,所以文件名别填错
    package com.atguigu.spring6.iocxml.di;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestBook {
        @Test
        public void testSetter(){
            ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
            Book book = context.getBean(Book.class);
            System.out.println(book);
        }
    }
  5. 可以看到,通过setter注入成功(所谓注入,其实就是给属性赋值)
  6. 基于setter注入的前提是类中有无参构造器和setter方法。基于setter注入,其实就等价于使用类中的setter方法

(4)实验三:依赖注入之构造器注入

  1. 基于构造器注入的前提是类中有无参构造器。基于构造器注入,其实就等价于使用类中的有参构造器
  2. 构造器注入,要这么写配置文件中的bean标签(可以用name也可以用index,index=0表示第一个属性,index=1表示第二个属性......)
  3. 为了测试效果更明显,我们在Book类的setter方法中加一条语句:
  4. 测试代码:
    package com.atguigu.spring6.iocxml.di;
    
    import org.junit.jupiter.api.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestBook {
        @Test
        public void testConstructor(){
            ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
            //因为现在Book类有两个id,所以我们不能根据类型获取bean了
            Book book = (Book)context.getBean("bookCon");
            System.out.println(book);
        }
    }

  5. 可以看到,在bean标签里使用constructor-arg标签,等价于调用有参构造器来初始化对象
  6. 总结:在Spring的配置文件中一旦使用bean标签就等价于给类创建了一个实例对象(id有点像实例对象的名字)。如果在bean标签中,使用了property标签,就等于通过类里的setter方法给对象的属性赋值(先用无参构造器创建对象,再用setter方法给属性赋值)。如果在bean标签中,使用了constructor标签,就等于调用了类里的有参构造器

(5)实验四:特殊值处理

  1. 字面量赋值:字面量就是数据本身。例如,int a = 10;10就是字面量
  2. 使用value属性给bean的属性赋值时,Spring会把给value属性的值看作字面量。比如,这个“前端开发”就是字面量
  3. 如果我们此时,给Book类再添加一个属性,并为这个属性设置setter方法
  4. 如果我们在注入时,给该属性赋null,该怎么做呢?
  5. xml实体:小于号在XML文档中是用来定义标签的开始的,不能随便使用。假如我们想给属性赋的值中出现了<该怎么办呢?例如
  6. 解决xml实体的方式一:转义,小于号(<)用&lt;表示,大于号(>)用&gt;表示。这样就不会报错了
  7. 解决xml实体的方式二:CDATA区。XML解析器看到CDATA区就知道这里是纯文本,就不会当作XML标签或属性来解析,所以在CDATA区中写什么符号都可以
  8. 在<![CDATA[在这里面写什么符号都可以]]>
  9. 测试一下,发现成功

(6)实验五:为对象类型属性赋值

方式一:引用外部bean

  1. 准备两个类,员工类和部门类
  2. 代码:
    package com.atguigu.spring6.iocxml.ditest;
    
    //员工类
    public class Emp {
        //对象类型的属性 员工属于某个部门
        private Dept dept;
        //员工名称
        private String ename;
        //员工年龄
        private Integer age;
    
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    
        public void setEname(String ename) {
            this.ename = ename;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public void work(){
            System.out.println(ename+"emp work..."+age);
            dept.info();
        }
    }
    package com.atguigu.spring6.iocxml.ditest;
    
    //部门类
    public class Dept {
        private String dname;
    
        public void setDname(String dname) {
            this.dname = dname;
        }
    
        public void info(){
            System.out.println("部门名称:" + dname);
        }
    }
  3. 我们新建一个Spring配置文件(文件名称可以随意,但是Spring配置文件必须放在src/main/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">
    
        <!--
            1.创建两个类对象emp和dept
            2.在emp的bean标签里,用property引入dept的bean
        -->
        <bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
            <property name="dname" value="安保部"></property>
        </bean>
        <bean id="emp" class="com.atguigu.spring6.iocxml.ditest.Emp">
            <!--基本类型属性注入-->
            <property name="ename" value="lucy"></property>
            <property name="age" value="50"></property>
            <!--对象类型属性注入-->
            <property name="dept" ref="dept"></property>
        </bean>
    
    </beans>

  4. 为对象类型的属性注入,不要用value,而是用ref。ref后面跟的是,要注入的对象的id
  5. 测试一下,成功

方式二:内部bean

  1. 内部bean方式代码演示:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--第二种方式:内部bean注入-->
        <bean id="emp2" class="com.atguigu.spring6.iocxml.ditest.Emp">
            <property name="ename" value="mary"></property>
            <property name="age" value="20"></property>
            <property name="dept">
                <bean id="dept2" class="com.atguigu.spring6.iocxml.ditest.Dept">
                    <property name="dname" value="财务部"></property>
                </bean>
            </property>
        </bean>
    
    </beans>

  2. 测试一下,发现成功
  3. 内部bean就是在bean标签里再定义一个bean
  4. 外部bean就是在bean标签里用到在它外面定义的bean

方式三:级联属性赋值

  1. 级联赋值代码演示:
    package com.atguigu.spring6.iocxml.ditest;
    
    //员工类
    public class Emp {
        //对象类型的属性 员工属于某个部门
        private Dept dept;
        //员工名称
        private String ename;
        //员工年龄
        private Integer age;
    
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    
        public void setEname(String ename) {
            this.ename = ename;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public Dept getDept() {
            return dept;
        }
    
        public String getEname() {
            return ename;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void work(){
            System.out.println(ename+"emp work..."+age);
            dept.info();
        }
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--第三种方式:级联赋值-->
        <bean id="dept3" class="com.atguigu.spring6.iocxml.ditest.Dept">
            <property name="dname" value="技术研发部"></property>
        </bean>
        <bean id="emp3" class="com.atguigu.spring6.iocxml.ditest.Emp">
            <property name="ename" value="tom"></property>
            <property name="age" value="30"></property>
            <property name="dept" ref="dept3"></property>
            <property name="dept.dname" value="测试部"></property>
        </bean>
    
    </beans>
  2. 测试一下,发现成功:
  3. 需注意级联赋值必须为对象类型的属性提供getter方法!!!我们可以理解为,(1)先通过getter方法得到该对象,(2)然后再通过该对象所属的类中提供的setter方法为该对象的属性赋值

(7)实验六:为数组类型属性赋值

  1. 修改Emp类的代码,为员工类添加一个新属性,该属性为数组类型
    package com.atguigu.spring6.iocxml.ditest;
    
    import java.util.Arrays;
    
    //员工类
    public class Emp {
        //对象类型的属性 员工属于某个部门
        private Dept dept;
        //员工名称
        private String ename;
        //员工年龄
        private Integer age;
        //爱好
        private String[] loves;
    
        public void setDept(Dept dept) {
            this.dept = dept;
        }
    
        public void setEname(String ename) {
            this.ename = ename;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public void setLoves(String[] loves) {
            this.loves = loves;
        }
    
        public Dept getDept() {
            return dept;
        }
    
        public String getEname() {
            return ename;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void work(){
            System.out.println(ename+"emp work..."+age);
            dept.info();
            System.out.println(Arrays.toString(loves));
        }
    }
  2. 为了方便,我们再创建一个Spring配置文件
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!--注入数组类型的属性-->
        <bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
            <property name="dname" value="技术部"></property>
        </bean>
        <bean id="emp" class="com.atguigu.spring6.iocxml.ditest.Emp">
            <!--普通类型的属性-->
            <property name="ename" value="lucy"></property>
            <property name="age" value="20"></property>
            <!--对象类型的属性-->
            <property name="dept" ref="dept"></property>
            <!--数组类型的属性-->
            <property name="loves">
                <array>
                    <value>吃饭</value>
                    <value>睡觉</value>
                    <value>敲代码</value>
                </array>
            </property>
        </bean>
    </beans>

  3. 测试一下,发现成功:

(8)实验七:为集合类型属性赋值

  1. 为List集合类型属性赋值:首先我们修改部门类,为它添加一个List集合类型的属性
    package com.atguigu.spring6.iocxml.ditest;
    
    import java.util.List;
    
    //部门类
    public class Dept {
    
        //一个部门有很多员工
        private List<Emp> empList;
    
        private String dname;
    
        public String getDname() {
            return dname;
        }
        public void setDname(String dname) {
            this.dname = dname;
        }
    
        public List<Emp> getEmpList() {
            return empList;
        }
    
        public void setEmpList(List<Emp> empList) {
            this.empList = empList;
        }
    
        public void info() {
            System.out.println("部门名称:"+dname);
            for (Emp emp:empList) {
                System.out.println(emp.getEname());
            }
        }
    }

    然后我们新建一个Spring配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="empone" class="com.atguigu.spring6.iocxml.ditest.Emp">
            <property name="ename" value="lucy"></property>
            <property name="age" value="20"></property>
        </bean>
        <bean id="emptwo" class="com.atguigu.spring6.iocxml.ditest.Emp">
            <property name="ename" value="mary"></property>
            <property name="age" value="30"></property>
        </bean>
        <bean id="dept" class="com.atguigu.spring6.iocxml.ditest.Dept">
            <property name="dname" value="技术部"></property>
            <property name="empList">
                <list>
                    <ref bean="empone"></ref>
                    <ref bean="emptwo"></ref>
                </list>
            </property>
        </bean>
    </beans>
  2. 测试一下,发现成功:

  3. 为Map集合类型属性赋值(先创建两个类,Student类和Teacher类,然后配置一个Spring的xml文件):
    package com.atguigu.spring6.iocxml.dimap;
    
    import java.util.Map;
    
    //学生类
    public class Student {
        private Map<String,Teacher> teacherMap;
        private String sid;
        private String sname;
    
        public String getSid() {
            return sid;
        }
    
        public void setSid(String sid) {
            this.sid = sid;
        }
    
        public String getSname() {
            return sname;
        }
    
        public void setSname(String sname) {
            this.sname = sname;
        }
    
        public Map<String, Teacher> getTeacherMap() {
            return teacherMap;
        }
    
        public void setTeacherMap(Map<String, Teacher> teacherMap) {
            this.teacherMap = teacherMap;
        }
    
        public void run(){
            System.out.println("学生编号:" + sid + "学生名称:" + sname);
            System.out.println(teacherMap);
        }
    }
    package com.atguigu.spring6.iocxml.dimap;
    
    //老师类
    public class Teacher {
        private String teacherId;
        private String teacherName;
    
        public String getTeacherId() {
            return teacherId;
        }
    
        public void setTeacherId(String teacherId) {
            this.teacherId = teacherId;
        }
    
        public String getTeacherName() {
            return teacherName;
        }
    
        public void setTeacherName(String teacherName) {
            this.teacherName = teacherName;
        }
    
        @Override
        public String toString() {
            return "Teacher{" +
                    "teacherId='" + teacherId + '\'' +
                    ", teacherName='" + teacherName + '\'' +
                    '}';
        }
    }
    <?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">
    
        <!--
            1.创建两个对象
            2.注入普通类型属性
            3.在学生bean注入map集合类型属性
        -->
        <bean id="teacherone" class="com.atguigu.spring6.iocxml.dimap.Teacher">
            <!--注入普通类型属性-->
            <property name="teacherId" value="100"></property>
            <property name="teacherName" value="西门讲师"></property>
        </bean>
        <bean id="teachertwo" class="com.atguigu.spring6.iocxml.dimap.Teacher">
            <!--注入普通类型属性-->
            <property name="teacherId" value="200"></property>
            <property name="teacherName" value="上官讲师"></property>
        </bean>
        <bean id="student" class="com.atguigu.spring6.iocxml.dimap.Student">
            <!--注入普通类型属性-->
            <property name="sid" value="2000"></property>
            <property name="sname" value="张三"></property>
            <!--注入Map集合类型属性-->
            <property name="teacherMap">
                <map>
                    <entry>
                        <key>
                            <value>10010</value>
                        </key>
                        <ref bean="teacherone"></ref>
                    </entry>
                    <entry>
                        <key>
                            <value>
                                10086
                            </value>
                        </key>
                        <ref bean="teachertwo"></ref>
                    </entry>
                </map>
            </property>
        </bean>
    </beans>
  4. 测试一下,发现成功:
  5. 如果集合里面的元素是基本数据类型或String类型,那么就用value。如果集合里面的元素是对象数据类型,那么就用ref
  6. 这是xml文件的约束,写明了xml文件中能用哪些标签,标签里能用哪些属性
  7. 使用util:list和util:map前,必须引入相应的命名空间,可以通过IDEA的提示功能选择
    <?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"
           xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/beans/spring-util.xsd
                               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                              ">
  8. 注入List集合和Map集合的第二种方式(util:list和util:map的id可以随便写,只是ref的时候是根据id来的):
    <?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"
           xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                              ">
            <!--
                1.创建三个对象
                2.注入普通类型属性
                3.使用util:类型 定义
                4.在学生bean引入
            -->
        <bean id="lessonone" class="com.atguigu.spring6.iocxml.dimap.Lesson">
            <property name="lessonName" value="java开发"></property>
        </bean>
        <bean id="lessontwo" class="com.atguigu.spring6.iocxml.dimap.Lesson">
            <property name="lessonName" value="前端开发"></property>
        </bean>
        <bean id="teacherone" class="com.atguigu.spring6.iocxml.dimap.Teacher">
            <property name="teacherId" value="100"></property>
            <property name="teacherName" value="西门讲师"></property>
        </bean>
        <bean id="teachertwo" class="com.atguigu.spring6.iocxml.dimap.Teacher">
            <property name="teacherId" value="200"></property>
            <property name="teacherName" value="欧阳讲师"></property>
        </bean>
        <bean id="student" class="com.atguigu.spring6.iocxml.dimap.Student">
            <property name="sid" value="10000"></property>
            <property name="sname" value="lucy"></property>
            <!--注入list和map类型的属性-->
            <property name="lessonList" ref="lessonList"></property>
            <property name="teacherMap" ref="teacherMap"></property>
        </bean>
        <util:list id="lessonList">
            <ref bean="lessonone"></ref>
            <ref bean="lessontwo"></ref>
        </util:list>
        <util:map id="teacherMap">
            <entry>
                <key>
                    <value>10010</value>
                </key>
                <ref bean="teacherone"></ref>
            </entry>
            <entry>
                <key>
                    <value>10086</value>
                </key>
                <ref bean="teachertwo"></ref>
            </entry>
        </util:map>
    </beans>
  9. 其实使用util的方式,就是把原本写在bean标签里的list和map,写到bean标签外面来了
  10. 注意:按照上面的图写的xml文件写错了,有个地方要注意一下。就是我们要把beans的地方全换成util,有个地方漏了
  11. 测试一下,发现成功:

(9)实验八:p命名空间

  1. p命名空间是指这种(灰色部分):
  2. 注意:xsi:schemaLocation部分就不用像util一样修改了
  3. p命名空间注入:
    <?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:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
                               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                              ">
            <!--
                1.创建三个对象
                2.注入普通类型属性
                3.使用util:类型 定义
                4.在学生bean引入
            -->
        <bean id="lessonone" class="com.atguigu.spring6.iocxml.dimap.Lesson">
            <property name="lessonName" value="java开发"></property>
        </bean>
        <bean id="lessontwo" class="com.atguigu.spring6.iocxml.dimap.Lesson">
            <property name="lessonName" value="前端开发"></property>
        </bean>
        <bean id="teacherone" class="com.atguigu.spring6.iocxml.dimap.Teacher">
            <property name="teacherId" value="100"></property>
            <property name="teacherName" value="西门讲师"></property>
        </bean>
        <bean id="teachertwo" class="com.atguigu.spring6.iocxml.dimap.Teacher">
            <property name="teacherId" value="200"></property>
            <property name="teacherName" value="欧阳讲师"></property>
        </bean>
        <bean id="student" class="com.atguigu.spring6.iocxml.dimap.Student">
            <property name="sid" value="10000"></property>
            <property name="sname" value="lucy"></property>
            <!--注入list和map类型的属性-->
            <property name="lessonList" ref="lessonList"></property>
            <property name="teacherMap" ref="teacherMap"></property>
        </bean>
        <util:list id="lessonList">
            <ref bean="lessonone"></ref>
            <ref bean="lessontwo"></ref>
        </util:list>
        <util:map id="teacherMap">
            <entry>
                <key>
                    <value>10010</value>
                </key>
                <ref bean="teacherone"></ref>
            </entry>
            <entry>
                <key>
                    <value>10086</value>
                </key>
                <ref bean="teachertwo"></ref>
            </entry>
        </util:map>
    
        <!--p命名空间注入-->
        <!--lessonList-ref后面跟的lessonList和teacherMap-ref后面跟的teacherMap都是id-->
        <bean id="studentp" class="com.atguigu.spring6.iocxml.dimap.Student"
            p:sid="100" p:sname="mary" p:lessonList-ref="lessonList" p:teacherMap-ref="teacherMap">
        </bean>
    </beans>

(10)实验九:引入外部属性文件

  1. 加入数据库相关依赖(在pom.xml文件中,加入后记得刷新):
     <!-- MySQL驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>
    
    <!-- 数据源 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.15</version>
    </dependency>
  2. 创建外部属性文件(在src/main/resources中创建),properties格式
    jdbc.user=root
    jdbc.password=atguigu
    jdbc.url=jdbc:mysql://localhost:3306/spring?serverTimezone=UTC
    jdbc.driver=com.mysql.cj.jdbc.Driver
  3. 在src/main/resources中创建一个Spring的配置文件,并引入context命名空间,注意,此时还要添加xsi:schemaLocation的部分
    <?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
                              ">
    
    </beans>

  4. 还要引入外部属性文件:
    <?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
                              ">
    
        <!--引入外部属性文件-->
        <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    
    </beans>
  5. 完成数据库信息的注入:
    <?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
                              ">
    
        <!--引入外部属性文件-->
        <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
        <!--完成数据库信息注入-->
        <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="url" value="${jdbc.url}"></property>
            <property name="username" value="${jdbc.user}"></property>
            <property name="password" value="${jdbc.password}"></property>
            <property name="driverClassName" value="${jdbc.driver}"></property>
        </bean>
    
    </beans>
  6. 测试代码:
    package com.atguigu.spring6.iocxml.jdbc;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.junit.jupiter.api.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestJdbc {
        @Test
        public void demo1(){
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setUrl("jdbc:mysql://localhost:3306/spring?serverTimezone=UTC");
            dataSource.setUsername("root");
            dataSource.setPassword("atguigu");
            dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        }
    
        @Test
        public void demo2(){
            ApplicationContext context = new ClassPathXmlApplicationContext("bean-jdbc.xml");
            DruidDataSource druidDataSource = context.getBean(DruidDataSource.class);
            System.out.println(druidDataSource.getUrl());
        }
    }

  7. 总结:首先要配置相关依赖(MySQL驱动和数据源)→编写properties文件→编写Spring的配置文件(写context命名空间、通过context引入properties文件、将properties文件的值注入DruidDataSource对象)
  8. druidDataSource的属性有:username、password、url、driverClassName

(11)实验十:bean的作用域

  1. 在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围,scope的取值含义参见下表:
    取值含义创建对象的时机
    singleton(默认在IoC容器中,这个bean的对象始终为单实例IoC容器初始化时
    prototype这个bean在IoC容器中有多个实例获取bean时
  2. 如果是在WebApplicationContext环境下,还会有另外几个作用域(但不常用):
    取值含义
    request在一个请求范围内有效
    session在一个会话范围内有效
  3. scope的取值为singleton,测试(三个文件的代码)
    package com.atguigu.spring6.iocxml.scope;
    
    public class Orders {
    }
    <?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">
    
        <!--通过scope属性能配置单实例还是多实例-->
        <bean id="orders" class="com.atguigu.spring6.iocxml.scope.Orders" scope="singleton"></bean>
    </beans>
    package com.atguigu.spring6.iocxml.scope;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestOrders {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean-scope.xml");
            Orders orders = context.getBean("orders", Orders.class);
            System.out.println(orders);
        }
    }

    Creating shared instance of singleton bean 'orders'代表创建了一个单实例对象

  4. 我们再获取一个bean看运行结果可以发现,当scope是singleton时,bean标签创建的就是一个单实例对象
  5. scope的取值为prototype,测试(我们只修改了Spring的xml文件,将scope的取值改成了prototype)可以看到,获取的两个bean其实是不同的对象
  6. 并且通过比较可以发现,scope的取值是singleton时,bean会在IoC容器初始化时就创建好。scope的取值是prototype时,bean是在它被获取时才创建好。看日志文件就可以发现

(12)实验十一:bean生命周期

  1. 具体的生命周期过程:
    1. bean对象创建(调用无参构造器)
    2. 给bean对象设置属性
    3. bean的后置处理器(初始化之前)
    4. bean对象初始化(调用指定的初始化方法
    5. bean的后置处理器(初始化之后)
    6. bean对象创建完成了,可以使用了
    7. bean对象销毁(配置指定销毁的方法
    8. IoC容器关闭了
  2. 创建User类:
    package com.atguigu.spring6.iocxml.life;
    
    public class User {
        private String name;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            System.out.println("2.给bean对象设置属性值");
            this.name = name;
        }
    
        //无参数构造
        public User() {
            System.out.println("1.bean对象创建,调用无参数构造");
        }
    
        //初始化方法
        public void initMethod(){
            System.out.println("4.bean对象的初始化,会调用指定的初始化的方法");
        }
        //销毁方法
        public void destroyMethod(){
            System.out.println("7.bean对象销毁,调用指定的销毁方法");
        }
    }
  3. 编写Spring的配置文件:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="user" class="com.atguigu.spring6.iocxml.life.User"
              scope="singleton" init-method="initMethod" destroy-method="destroyMethod">
            <property name="name" value="lucy"></property>
        </bean>
    </beans>
  4. 测试类:
    package com.atguigu.spring6.iocxml.life;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestUser {
        public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-life.xml");
            User user = context.getBean("user", User.class);
            System.out.println("6.bean对象创建完成了,可以使用了");
            System.out.println(user);
            //该方法表示会进行销毁
            context.close();
        }
    }
  5. 进行测试(注意:要想使用close方法,就不能用ApplicationContext接口了):
  6. bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,并且配置到IoC容器中,需要注意的是,bean后置处理器并不淡出针对某一个bean生效,而是针对IoC容器中所有的bean生效
  7. 创建bean的后置处理器:
    package com.atguigu.spring6.iocxml.life;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyBeanPost implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("3.后置处理器在初始化之前执行");
            System.out.println(beanName + "::" + bean);
            return bean;
        }
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("5.后置处理器在初始化之后执行");
            System.out.println(beanName + "::" + bean);
            return bean;
        }
    }
  8. 在IoC容器中配置后置处理器:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="user" class="com.atguigu.spring6.iocxml.life.User"
              scope="singleton" init-method="initMethod" destroy-method="destroyMethod">
            <property name="name" value="lucy"></property>
        </bean>
        
        <bean id="myBeanPost" class="com.atguigu.spring6.iocxml.life.MyBeanPost"></bean>
    </beans>
  9. 加了后置处理器以后的测试效果:

(13)实验十二:FactoryBean

  1. FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候,得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值
  2. 创建一个User类:
    package com.atguigu.spring6.iocxml.factorybean;
    
    public class User {
    }
  3. 创建一个实现FactoryBean接口的类:
    package com.atguigu.spring6.iocxml.factorybean;
    
    import org.springframework.beans.factory.FactoryBean;
    
    public class MyFactoryBean implements FactoryBean<User> {
        @Override
        public User getObject() throws Exception{
            return new User();
        }
        @Override
        public Class<?> getObjectType(){
            return User.class;
        }
    }
  4. 编写一个Spring的配置文件:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="user" class="com.atguigu.spring6.iocxml.factorybean.MyFactoryBean"></bean>
    </beans>
  5. 编写一个测试类:
    package com.atguigu.spring6.iocxml.factorybean;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestUser {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean-factorybean.xml");
            User user = (User)context.getBean("user");
            System.out.println(user);
        }
    }
  6. 根据测试效果可以发现,虽然我们在配置bean时,对class的配置是myFactoryBean,但是得到的bean并不是这个类的对象,而是该类中的getObject方法返回的对象

(14)实验十三:基于xml自动装配

  1. 基本环境准备:创建三个软件包(controller、service、dao),controller里面创建一个类UserController。service里面创建一个类UserServiceImpl、一个接口UserService,dao里面创建一个类UserDaoImpl、一个接口UserDao
    package com.atguigu.spring6.iocxml.auto.controller;
    
    import com.atguigu.spring6.iocxml.auto.service.UserService;
    import com.atguigu.spring6.iocxml.auto.service.UserServiceImpl;
    
    public class UserController {
        public void addUser(){
            System.out.println("controller方法执行了...");
            UserService userService = new UserServiceImpl();
            userService.addUserService();
        }
    }
    package com.atguigu.spring6.iocxml.auto.service;
    
    public interface UserService {
        public void addUserService();
    }
    package com.atguigu.spring6.iocxml.auto.service;
    
    import com.atguigu.spring6.iocxml.auto.dao.UserDao;
    import com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl;
    
    public class UserServiceImpl implements UserService{
        @Override
        public void addUserService() {
            System.out.println("userService方法执行了");
            UserDao userDao = new UserDaoImpl();
            userDao.addUserDao();
        }
    }
    package com.atguigu.spring6.iocxml.auto.dao;
    
    public interface UserDao {
        public void addUserDao();
    }
    package com.atguigu.spring6.iocxml.auto.dao;
    
    public class UserDaoImpl implements UserDao{
        @Override
        public void addUserDao() {
            System.out.println("userDao方法执行了");
        }
    }

    addUser方法里调用了addUserService方法、addUserService方法里调用了addUserDao方法

  2. 修改代码(UserController和UserServiceImpl):
    package com.atguigu.spring6.iocxml.auto.controller;
    
    import com.atguigu.spring6.iocxml.auto.service.UserService;
    import com.atguigu.spring6.iocxml.auto.service.UserServiceImpl;
    import org.junit.jupiter.api.Test;
    
    public class UserController {
        private UserService userService;
    
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    
        @Test
        public void addUser(){
            System.out.println("controller方法执行了...");
            userService.addUserService();
    //        UserService userService = new UserServiceImpl();
    //        userService.addUserService();
        }
    }
    package com.atguigu.spring6.iocxml.auto.service;
    
    import com.atguigu.spring6.iocxml.auto.dao.UserDao;
    import com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl;
    
    public class UserServiceImpl implements UserService{
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public void addUserService() {
            System.out.println("userService方法执行了");
            userDao.addUserDao();
    //        UserDao userDao = new UserDaoImpl();
    //        userDao.addUserDao();
        }
    }
  3. 在resources中创建配置文件(这么写就是手动装配)
  4. 自动装配怎么写呢?
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="userController" class="com.atguigu.spring6.iocxml.auto.controller.UserController" 
              autowire="byType">
        </bean>
        <bean id="userService" class="com.atguigu.spring6.iocxml.auto.service.UserServiceImpl" 
              autowire="byType">
        </bean>
        <bean id="userDao" class="com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl">
        </bean>
    </beans>
  5. 测试代码:
    package com.atguigu.spring6.iocxml.auto;
    
    import com.atguigu.spring6.iocxml.auto.controller.UserController;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestUser {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean-auto.xml");
            UserController userController = context.getBean("userController", UserController.class);
            userController.addUser();
        }
    }

  6. 也就是说,我们原本是根据外部bean的方式注入对象类型的属性的,现在通过自动装配的方式进行
  7. 使用bean标签的autowire属性设置自动装配效果。自动装配方式:byType
  8. byType:根据类型匹配IoC容器中的某个兼容类型的bean,为属性自动赋值(比如在UserController这个类中,有一个属性是UserService类型的,那么在IoC容器中找到UserService接口的实现类的对象,就会为该属性自动赋值)
  9. 若在IoC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值默认为null
  10. 若在IoC中,有多个兼容类型的bean能够为属性赋值,则抛出异常:NoUniqueBeanDefinitionException
  11. 根据名称装配:byName。比如UserController类中有个UserService类的属性,叫userService,那么如果在IoC容器中找到一个id为userService的对象,就会进行自动装配
  12. 我们根据代码测试一下:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="userController" class="com.atguigu.spring6.iocxml.auto.controller.UserController"
              autowire="byName">
        </bean>
        <bean id="userService" class="com.atguigu.spring6.iocxml.auto.service.UserServiceImpl"
              autowire="byName">
        </bean>
        <bean id="userDao" class="com.atguigu.spring6.iocxml.auto.dao.UserDaoImpl">
        </bean>
    </beans>

  13. 当我们改变xml文件中对象的id,就可以发现不能自动装配成功了(因为UserController类中,UserService类型的属性名字叫userService,但是我们此时的对象id不是userService了,而是userServiceImpl。UserServiceImpl类中,UserDao类型的属性名字叫userDao,但是我们此时的对象id不是userDao了,而是userDaoImlp)可以看到爆红

三、基于注解管理Bean(⭐)

从Java5开始,Java增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息

Spring从2.5版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化Spring的XML配置

Spring通过注解实现自动装配的步骤如下:

  1. 引入依赖
  2. 开启组件扫描
  3. 使用注解定义bean
  4. 依赖注入

(1)搭建子模块spring6-ioc-annotation

  1. 引入日志模块log4j2.xml
  2. 创建一个Spring的配置文件
  3. 因为依赖已经在父模块中引入过,通过依赖的继承机制,子模块就不需要重复引入了

(2)开启组件扫描

  1. Spring默认不使用注解装配Bean,因此我们在Spring的XML文件中,通过context:component-scan元素开启Spring Beans的自动扫描功能。开启此功能后,Spring会自动扫描指定的包(base-package属性设置)及其子包下所有的类,如果类上使用了@Component注解,就将该类装配到容器中
  2. 情况一:最基本的扫描方式:
  3. 情况二:指定要排除的组件
    <context:component-scan base-package="com.atguigu.spring6">
        <!-- context:exclude-filter标签:指定排除规则 -->
        <!-- 
     		type:设置排除或包含的依据
    		type="annotation",根据注解排除,expression中设置要排除的注解的全类名
    		type="assignable",根据类型排除,expression中设置要排除的类型的全类名
    	-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
            <!--<context:exclude-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
    </context:component-scan>

    (1)<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>表示Controller这个注解就不进行扫描(2)<context:exclude-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>表示UserController这个类就不进行扫描

  4. 情况三:仅扫描指定组件
    <context:component-scan base-package="com.atguigu" use-default-filters="false">
        <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
        <!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
        <!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 -->
        <!-- 
     		type:设置排除或包含的依据
    		type="annotation",根据注解排除,expression中设置要排除的注解的全类名
    		type="assignable",根据类型排除,expression中设置要排除的类型的全类名
    	-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    	<!--<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>-->
    </context:component-scan>

    (1)<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>表示只扫描Controller这个注解(2)<context:include-filter type="assignable" expression="com.atguigu.spring6.controller.UserController"/>表示只扫描UserController这个类

(3)使用注解定义bean

  1. Spring提供了多个注解,这些注解可以直接标注在Java类上,将它们定义成Spring Bean
    注解说明
    @Component该注解用于描述Spring中的Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如Service层、Dao层等。使用时只需将该注解标注在相应的类上即可
    @Repository该注解用于将Dao层(数据访问层)的类标识为Spring中的Bean,其功能和@Component相同
    @Service该注解用于将Service层(业务层)的类标识为Spring中的Bean,其功能和@Component相同
    @Controller该注解用于将Controller层(控制层)的类标识为Spring中的Bean,其功能和@Component相同
  2. 使用举例:value可以不写,比如类名为User,如果不写value的话,value的值默认为user
  3. 建一个User类,建一个TestUser类
    package com.atguigu.spring6.bean;
    
    import org.springframework.stereotype.Component;
    
    @Component(value="user")//<bean id="user" class="...">
    public class User {
    }
    package com.atguigu.spring6.bean;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestUser {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
            User user = context.getBean(User.class);
            System.out.println(user);
        }
    }
  4. 配置文件:
    <?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
                              ">
            <!--开启组件扫描-->
            <context:component-scan base-package="com.atguigu.spring6"></context:component-scan>
    
            
    </beans>
  5. 测试效果:
  6. 说明在User类上加了@Component注解,等价于创建了一个User类的对象

(4)实验一:@Autowired注入

单独使用@Autowired注解,默认根据类型装配

@Autowired注解源码:

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

源码中有两处需要注意:

  1. 第一处:该注解可以标注在哪里:
    1. 构造方法上
    2. 方法上
    3. 属性上
    4. 形参上
    5. 注解上
  2. 第二处: 该注解有一个required属性,默认值是true。表示在注入的时候要求被注入的bean是必须存在的,如果不存在则报错。如果required属性设置为false,表示被注入的bean存在或不存在都没关系,存在的话就注入,不存在也不报错

3.4.1场景一:属性注入

  1. 属性注入就是根据类型找到对象,进行注入的。类似于,基于XML的自动装配
  2. 创建三个软件包(controller、service、dao)。分别在这几个包中创建实现类和接口
  3. 代码:
    package com.atguigu.spring6.autowired.controller;
    
    import com.atguigu.spring6.autowired.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class UserController {
        //注入service
        //第一种方式:属性注入
        @Autowired //根据类型找到对应的对象,完成注入
        private UserService userService;
        public void add(){
            System.out.println("controller......");
            userService.add();
        }
    }
    package com.atguigu.spring6.autowired.service;
    
    public interface UserService {
        public void add();
    }
    package com.atguigu.spring6.autowired.service;
    
    import com.atguigu.spring6.autowired.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserServiceImpl implements UserService{
        //注入dao
        @Autowired
        private UserDao userDao;
        @Override
        public void add(){
            System.out.println("service......");
            userDao.add();
        }
    }
    package com.atguigu.spring6.autowired.dao;
    
    public interface UserDao {
        public void add();
    }
    package com.atguigu.spring6.autowired.dao;
    
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class UserDaoImpl implements UserDao{
        @Override
        public void add(){
            System.out.println("dao执行...");
        }
    }
  4. 创建测试类:
    package com.atguigu.spring6.autowired;
    
    import com.atguigu.spring6.autowired.controller.UserController;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestUserController {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
            UserController userController = context.getBean(UserController.class);
            userController.add();
        }
    }

  5. 解释:根据注解创建了三个bean(UserController、UserServiceImpl、UserDaoImpl),然后根据类型装配,UserController类中有一个Userservice类型的属性→给userService装配UserServiceImpl对象,UserServiceImpl中有一个UserDao类型的属性→给userDao装配UserDaoImlp对象

3.4.2场景二:set注入

  1. 修改代码(UserController和UserServiceImpl的):
    package com.atguigu.spring6.autowired.controller;
    
    import com.atguigu.spring6.autowired.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class UserController {
        private UserService userService;
    
        @Autowired
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    
        public void add(){
            System.out.println("controller......");
            userService.add();
        }
    }
    package com.atguigu.spring6.autowired.service;
    
    import com.atguigu.spring6.autowired.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserServiceImpl implements UserService{
        private UserDao userDao;
    
        @Autowired
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public void add(){
            System.out.println("service......");
            userDao.add();
        }
    }
  2. 测试效果:
  3. 个人理解:还是通过类型找到对象,然后对象通过setter方法赋值

3.4.3场景三:构造方法注入

  1. 修改代码(UserController和UserServiceImpl的):
    package com.atguigu.spring6.autowired.controller;
    
    import com.atguigu.spring6.autowired.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class UserController {
        private UserService userService;
    
        @Autowired
        public UserController(UserService userService) {
            this.userService = userService;
        }
    
        public void add(){
            System.out.println("controller......");
            userService.add();
        }
    }
    package com.atguigu.spring6.autowired.service;
    
    import com.atguigu.spring6.autowired.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserServiceImpl implements UserService{
        private UserDao userDao;
    
        @Autowired
        public UserServiceImpl(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public void add(){
            System.out.println("service......");
            userDao.add();
        }
    }
  2. 测试效果:
  3. 个人理解:还是通过类型找到对象,然后对象通过构造器赋值

3.4.4场景四:形参上注入

  1. 就是不在构造器上加@Autowired,但是把@Autowired加在构造器形参上
  2. 修改代码(UserController和UserServiceImpl的):
    package com.atguigu.spring6.autowired.controller;
    
    import com.atguigu.spring6.autowired.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class UserController {
        private UserService userService;
        
        public UserController(@Autowired UserService userService) {
            this.userService = userService;
        }
    
        public void add(){
            System.out.println("controller......");
            userService.add();
        }
    }
    package com.atguigu.spring6.autowired.service;
    
    import com.atguigu.spring6.autowired.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserServiceImpl implements UserService{
        private UserDao userDao;
    
        public UserServiceImpl(@Autowired UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public void add(){
            System.out.println("service......");
            userDao.add();
        }
    }
  3. 测试效果:
  4. 个人理解:还是通过类型找到对象,然后对象通过构造器赋值

3.4.5场景五:只有一个构造函数,无注解

  1. 当有参数的构造方法只有一个时,@AutoWired注解可以省略
  2. 修改代码:
    package com.atguigu.spring6.autowired.controller;
    
    import com.atguigu.spring6.autowired.service.UserService;
    import org.springframework.stereotype.Controller;
    
    @Controller
    public class UserController {
        private UserService userService;
    
        public UserController(UserService userService) {
            this.userService = userService;
        }
    
        public void add(){
            System.out.println("controller......");
            userService.add();
        }
    }
    package com.atguigu.spring6.autowired.service;
    
    import com.atguigu.spring6.autowired.dao.UserDao;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserServiceImpl implements UserService{
        private UserDao userDao;
    
        public UserServiceImpl(UserDao userDao) {
            this.userDao = userDao;
        }
    
        @Override
        public void add(){
            System.out.println("service......");
            userDao.add();
        }
    }
  3. 测试通过:

3.4.6场景六:@Autowired注解和@Qualifier注解联合

  1. 比如,当接口UserDao有两个实现类UserDaoImpl和UserRedisDaoImpl时,由于这两个类上都加了@Repository注解,因此会生成它们各自对应的bean。当只根据类型查找时,会发现满足UserDao的对象有两个,这时就会报错(expected single matching bean but found 2: userDaoImpl,userRedisDaoImpl)
  2. 针对该问题,解决方案是:使用两个注解,根据名称注入
    package com.atguigu.spring6.autowired.service;
    
    import com.atguigu.spring6.autowired.dao.UserDao;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.stereotype.Service;
    
    @Service
    public class UserServiceImpl implements UserService{
        @Autowired
        @Qualifier(value = "userRedisDaoImpl")
        private UserDao userDao;
    
        @Override
        public void add(){
            System.out.println("service......");
            userDao.add();
        }
    }

  3. 个人理解:@Autowired就是根据类型找对象,@Qualifier就是在类型相同的情况下再根据对象名选择 

(5)实验二:@Resource注入

@Resource注解也可以完成属性注入。那么它和@Autowired注解有什么区别呢?

  1. @Resource注解是JDK扩展包中的,也就是说它是JDK中的一部分。所以该注解是标准注解,更加具有通用性
  2. @Autowired注解是Spring框架自己的
  3. @Resource注解默认(1)根据名称装配byName,(2)未指定name时,使用属性名作为name。(3)通过name找不到的话,会自动启动通过类型byType装配
  4. @Autowired注解默认根据类型装配byType,如果想根据名称装配,则需要配合@Qualifier注解一起使用
  5. @Resource注解用在属性和setter方法上
  6. @Autowired注解用在属性、方法、构造器、形参上

@Resource注解属于JDK扩展包,所以不在JDK中,当然需要额外引入以下依赖:(如果是JDK8的话不需要额外引入依赖。高于JDK11或低于JDK8需要引入以下依赖 

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

3.5.1根据name注入

  1. 如果@Resource后面没有跟(name="..."),那么默认value的值就是类中定义的属性名,然后根据属性名去找叫这个名字的对象。对象名是在@Component/@Controller/@Service/@Repository后面用(value="...")指定的,如果不指定,默认值是(比如类名叫UserController,那么默认值就是userController)
  2. 测试代码:
    package com.atguigu.spring6.resource.controller;
    
    import com.atguigu.spring6.resource.service.UserService;
    import jakarta.annotation.Resource;
    import org.springframework.stereotype.Controller;
    
    @Controller(value = "myUserController")
    public class UserController {
        @Resource(name="myUserService")
        private UserService userService;//此时,指定了名称,那么我们就要找到名为myUserService的对象
    
        public void add(){
            System.out.println("controller......");
            userService.add();
        }
    }
    package com.atguigu.spring6.resource.service;
    
    import com.atguigu.spring6.resource.dao.UserDao;
    import jakarta.annotation.Resource;
    import org.springframework.stereotype.Service;
    
    @Service(value = "myUserService")
    public class UserServiceImpl implements UserService {
        @Resource
        private UserDao myUserDao;
    
        @Override
        public void add(){
            System.out.println("service......");
            myUserDao.add();
        }
    }
    package com.atguigu.spring6.resource.dao;
    
    import org.springframework.stereotype.Repository;
    
    @Repository(value = "myUserDao")
    public class UserDaoImpl implements UserDao {
        @Override
        public void add(){
            System.out.println("dao执行...");
        }
    }
    package com.atguigu.spring6.resource.dao;
    
    import org.springframework.stereotype.Repository;
    
    @Repository(value = "myUserRedisDao")
    public class UserRedisDaoImpl implements UserDao {
        @Override
        public void add() {
            System.out.println("dao redis......");
        }
    }
    package com.atguigu.spring6.resource;
    
    import com.atguigu.spring6.resource.controller.UserController;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class TestUserController {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
            UserController userController = context.getBean("myUserController",UserController.class);
            userController.add();
        }
    }
    package com.atguigu.spring6.resource.service;
    
    public interface UserService {
        public void add();
    }
    package com.atguigu.spring6.resource.dao;
    
    public interface UserDao {
        public void add();
    }
  3. 测试成功
  4. 如果根据name没有找到,就会根据类型找
  5. 我们修改一下UserController中的代码,把UserService类型的属性的属性名改成“userService”。由于此时@Resource也没有给name显式赋值,因此根据属性名“userService”来找对象,而此时没有叫userService的对象,所以它会根据类型来找

3.5.2name未知注入

  1. 当name没有显式指定时,name就是该属性的属性名
  2. 演示看3.5.1

3.5.3其他情况

  1. 当name没有显式指定时,name就是该属性的属性名。当根据属性名也找不到对应的对象时,我们就根据该类型的类型来找,找到可以兼容该类型的对象
  2. 演示看3.5.1

(6)Spring全注解开发

  1. 上面我们虽然用了注解来生成对象和给属性进行注入,但是我们还是写了一个配置文件来开启组件扫描的。全注解开发就是不再使用Spring配置文件来开启组件扫描了,而是写了一个配置类来代替配置文件
  2. 用配置类来代替配置文件,开启组件扫描。配置类写在src/main/java中
    package com.atguigu.spring6.config;
    
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan("com.atguigu.spring6")
    public class SpringConfig {
    
    }

    配置类上有两个注解,一个是@Configuration,一个是@ComponentScan。@Configuration说明这是一个配置类,@ComponentScan("包名")和配置文件中<context:component-scan base-package="com.atguigu.spring6"></context:component-scan>作用一样

  3. 在测试程序中进行修改,把加载配置文件改成加载配置类
    package com.atguigu.spring6.resource;
    
    import com.atguigu.spring6.config.SpringConfig;
    import com.atguigu.spring6.resource.controller.UserController;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class TestUserController {
        public static void main(String[] args) {
            //加载配置类
            ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
            UserController userController = context.getBean("myUserController",UserController.class);
            userController.add();
        }
    }

    把原来的ClassPathXMLApplicationContext改成AnnotationConfigApplicationContext

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2280057.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker:基于自制openjdk8镜像 or 官方openjdk8镜像,制作tomcat镜像

一、制作openjdk8基础镜像【基于自定义alpine-3.18.0:v1 】 docker pull maven:3.5.0-jdk-8-alpine 78.56 MB https://hub.docker.com/_/maven/tagspage8&namealpine openjdk二进制下载地址 https://blog.csdn.net/fenglllle/article/details/124786948 https://adoptope…

数据结构漫游记:动态实现栈(stack)

嘿&#xff0c;各位技术潮人&#xff01;好久不见甚是想念。生活就像一场奇妙冒险&#xff0c;而编程就是那把超酷的万能钥匙。此刻&#xff0c;阳光洒在键盘上&#xff0c;灵感在指尖跳跃&#xff0c;让我们抛开一切束缚&#xff0c;给平淡日子加点料&#xff0c;注入满满的pa…

鸿蒙系统 将工程HarmonyOS变成OpenHarmony

DevEco Studio软件创建工程后需要修改两个地方&#xff1a; 修改第二个build-profile.json5文件 将原先内容&#xff1a; {"app": {"signingConfigs": [],"products": [{"name": "default","signingConfig": &q…

MySQL 事务及MVCC机制详解

目录 什么是事务 事务的隔离级别 数据库并发的三种场景 读-写 什么是事务 事务就是一组DML语句组成&#xff0c;这些语句在逻辑上存在相关性&#xff0c;这一组DML语句要么全部成功&#xff0c;要么全部失败&#xff0c;是一个整体。MySQL提供一种机制&#xff0c;保证我们…

将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch(3.纯python的实惠版)

前情&#xff1a; 将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch&#xff08;1.标准版&#xff09;-CSDN博客 将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch&#xff08;2.换掉付费的Event Hubs&#xff09;-CSDN博客 python脚本实现 厉害的…

什么是三高架构?

大家好&#xff0c;我是锋哥。今天分享关于【什么是三高架构?】面试题。希望对大家有帮助&#xff1b; 什么是三高架构? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 “三高架构”通常是指高可用性&#xff08;High Availability&#xff09;、高性能&#xff…

[微服务]注册中心优化

环境隔离 企业实际开发中&#xff0c;往往会搭建多个运行环境&#xff0c;例如&#xff1a; 开发环境测试环境预发布环境生产环境 这些不同环境之间的服务和数据之间需要隔离。 还有的企业中&#xff0c;会开发多个项目&#xff0c;共享nacos集群。此时&#xff0c;这些项目…

uniapp——App 监听下载文件状态,打开文件(三)

5 实现下载文件并打开 这里演示&#xff0c;导出Excel 表格 文章目录 5 实现下载文件并打开DEMO监听下载进度效果图为什么 totalSize 一直为0&#xff1f; 相关Api&#xff1a; downloader DEMO 提示&#xff1a; 请求方式支持&#xff1a;GET、POST&#xff1b;POST 方式需要…

地图:nuxt3高德地图简单使用 / nuxt2 + amap

一、官方网站 JS API 安全密钥使用-基础-进阶教程-地图 JS API 2.0 | 高德地图API 二、使用 2.1、创建应用 2.2、添加key&#xff0c;得到key值 2.3、nuxt3项目 引入amap 2.4、pages/map.vue <template><div class"container"><div id"map-co…

Java面试专题——面向对象

面向过程和面向对象的区别 面向过程&#xff1a;当事件比较简单的时候&#xff0c;利用面向过程&#xff0c;注重的是事件的具体的步骤/过程&#xff0c;注重的是过程中的具体的行为&#xff0c;以函数为最小单位&#xff0c;考虑怎么做。 面向对象&#xff1a;注重找“参与者…

Flowable 管理各业务流程:流程设计器 (获取流程模型 XML)、流程部署、启动流程、流程审批、流程挂起和激活、任务分配

文章目录 引言I 表结构主要表前缀及其用途核心表II 流程设计器(Flowable BPMN模型编辑器插件)Flowable-UIvue插件III 流程部署部署步骤例子:根据流程模型ID部署IV 启动流程启动步骤ACT_RE_PROCDEF:流程定义相关信息例子:根据流程 ID 启动流程V 流程审批审批步骤Flowable 审…

VIVADO ILA IP进阶使用之任意设置ILA的采样频率

VIVADO ILA IP进阶使用之任意设置ILA的采样频率 VIVADO ILA IP和VIO IP结合使用任意设置ILA的采样频率 目录 前言 一、VIO IP的配置 二、ILA IP的配置 三、测试代码 四、测试结果 总结 前言 VIVADO中编写完程序上板测试时经常会用到viavdo自带的ILA逻辑分析仪IP核&#x…

【机器学习实战入门】使用LSTM机器学习预测股票价格

机器学习在股票价格预测中有重要的应用。在这个机器学习项目中&#xff0c;我们将讨论如何预测股票的收益。这是一个非常复杂的任务&#xff0c;充满了不确定性。我们将会把这个项目分成两部分进行开发&#xff1a; 首先&#xff0c;我们将学习如何使用 LSTM 神经网络预测股票…

DilateFormer: Multi-Scale Dilated Transformer for Visual Recognition 中的空洞自注意力机制

空洞自注意力机制 文章目录 摘要1. 模型解释1.1. 滑动窗口扩张注意力1.2. 多尺度扩张注意力 2. 代码3. 流程图3.1. MultiDilatelocalAttention3.2. DilateAttention3.3. MLP 摘要 本文针对DilateFormer中的空洞自注意力机制原理和代码进行详细介绍&#xff0c;最后通过流程图梳…

大模型GUI系列论文阅读 DAY2续:《一个具备规划、长上下文理解和程序合成能力的真实世界Web代理》

摘要 预训练的大语言模型&#xff08;LLMs&#xff09;近年来在自主网页自动化方面实现了更好的泛化能力和样本效率。然而&#xff0c;在真实世界的网站上&#xff0c;其性能仍然受到以下问题的影响&#xff1a;(1) 开放领域的复杂性&#xff0c;(2) 有限的上下文长度&#xff…

Qt按钮美化教程

前言 Qt按钮美化主要有三种方式&#xff1a;QSS、属性和自绘 QSS 字体大小 font-size: 18px;文字颜色 color: white;背景颜色 background-color: rgb(10,88,163); 按钮边框 border: 2px solid rgb(114,188,51);文字对齐 text-align: left;左侧内边距 padding-left: 10…

云IDE:开启软件开发的未来篇章

敖行客一直致力于将整个研发协作流程线上化&#xff0c;从而打破物理环境依赖&#xff0c;让研发组织模式更加灵活、自由且高效&#xff0c;今天就来聊聊AT Work&#xff08;一站式研发协作平台&#xff09;的重要组成部分-云IDE。 在科技领域&#xff0c;历史常常是未来的风向…

AI agent 在 6G 网络应用,无人机群控场景

AI agent 在 6G 网络应用,无人机群控场景 随着 6G 时代的临近,融合人工智能成为关键趋势。借鉴 IT 行业 AI Agent 应用范式,提出 6G AI Agent 技术框架,包含多模型融合、定制化 Agent 和插件式环境交互理念,构建了涵盖四层结构的框架。通过各层协同实现自主环境感知等能力…

【Linux 重装】Ubuntu 启动盘 U盘无法被识别,如何处理?

背景 U盘烧录了 Ubuntu 系统作为启动盘&#xff0c;再次插入电脑后无法被识别 解决方案&#xff08;Mac 适用&#xff09; &#xff08;1&#xff09;查找 USB&#xff0c;&#xff08;2&#xff09;格式化&#xff08;1&#xff09;在 terminal 中通过 diskutil list 查看是…

【优选算法篇】2----复写零

---------------------------------------begin--------------------------------------- 这道算法题相对于移动零&#xff0c;就上了一点点强度咯&#xff0c;不过还是很容易理解的啦~ 题目解析&#xff1a; 这道题如果没理解好题目&#xff0c;是很难的&#xff0c;但理解题…