# IOC 底层原理

IOC 是什么?

  1. 控制反转,把对象创建和对象之间的调用过程,交给 Sprign 进行管理
  2. 使用 IOC 目的:为了耦合度降低

IOC 底层 使用到了,xml 解析工厂模式反射 做到 IOC 的流程

画图讲解 IOC 底层原理:

image-20230609154447677

# IOC 接口

  1. IOC 思想基于 IOC 容器完成,IOC 容器底层就是对象工厂。

  2. Spring 提供 IOC 容器实现两种方式:(两个接口)

    1. BeanFactory
      • IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用。
    2. ApplicationContext
      • BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用。
    3. BeanFactory 和 ApplicationContext 的区别:
      • BeanFactory
        • 加载配置文件 ClassPathxmlApplicationContext ("*.xml") 的时候不会创建对象,在获取对象 (使用)getBean() 的时候才去创建对象。
      • ApplicationContext
        • 加载配置文件 ClassPathxmlApplicationContext ("*.xml") 时候就会把在配置文件对象进行创建。
  3. ApplicationContext 接口实现类:

    image-20230609160050706

    • FileSystemXmlApplicationContext
      • 配置文件路径写为系统盘的路径也就是绝对路径
    • ClassPathXmlApplicationContext
      • 当前工程的类路径

# IOC 操作 Bean 管理

1,什么是 Bean 管理 (概念)

Bean 管理指的是两个操作:

  1. Spring 创建对象
  2. Spring 注入属性

2,Bean 管理操作有两种方式

  1. 基于 XML 配置文件方式实现
  2. 基于注解方式实现

# IOC 操作 Bean 管理 (基于 xml 方式)

# 1,基于 xml 方式创建对象

<bean id="user" class="com.dkx.UserDao"></bean>
  1. 在 Spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
  2. bean 标签有很多属性,介绍常用的属性:
    1. id 属性:唯一标识
    2. class 属性:创建对象类所在的全路径
  3. 创建对象时候,默认也是执行无参构造方法完成对象创建

# 2,基于 xml 方式注入属性

1,DI:依赖注入,就是注入属性

# 第一种注入方式:使用 set 方法进行注入
  1. 创建类,定义属性对应的 set 方法

    public class Book {
    //    创建属性
        private String uame;
    //    创建属性对应的 set 方法
        public void setName(String uame){
            this.uame = uame;
        }
       public void getName(){
            System.out.println("名字: "+uame);
        }
    }
  2. 在 Spring 配置文件配置对象创建,配置属性注入.

    <!-- 配置 book 对象创建 -->
    <bean id="book" class="com.dkx.Book">
       <!-- 属性注入 name 对应 set 方法去掉 set 首字母小写 value 赋值 -->
       <!-- 多个属性注入则写多个 property 来进行注入 -->
       <property name="name" value="张三"></property>
    </bean>
  3. 测试代码:

    public class TestSpring5 {
        @Test
        public void test(){
    //        1. 加载 spring 配置文件
            ApplicationContext context = new ClassPathXmlApplicationContext
                    ("application.xml");
    //        2. 获取配置创建的对象
            Book book = context.getBean("book", Book.class);
            book.getName();
        }
    }

    测试结果:

    名字: 张三
    
# 第二种注入方式:使用有参构造进行注入
  1. 创建类,定义属性,创建属性对应有参构造方法:

    public class Orders {
        //TODO aame
        private String aame;
        private String address;
        public Orders(String name, String address) {
            this.aame = name;
            this.address = address;
        }
        public void getOut(){
            System.out.println("名称: "+aame+"店名: "+address);
        }
    }
  2. 在 Spring 的配置文件中,进行配置

    <!-- 有参构造注入属性 -->
    <bean id="orders" class="com.dkx.Orders">
       <!--name 通过构造器中的参数名来查找的 -->
       <constructor-arg name="name" value="张三"></constructor-arg>
       <constructor-arg name="address" value="张三牌-板面"></constructor-arg>
    </bean>
  3. 测试代码:

    public class TestSpring5 {
        @Test
        public void test(){
    //        1. 加载 spring 配置文件
            ApplicationContext context = new ClassPathXmlApplicationContext
                    ("application.xml");
    //        2. 获取配置创建的对象
            Orders orders = context.getBean("orders", Orders.class);
            orders.getOut();
        }
    }

    测试结果:

    名称: 张三店名: 张三牌-板面
    

# 3,p 名称空间注入 (了解)

1. 使用 p 名称空间注入,可以简化基于 xml 配置方式

第一步,添加 p 名称空间在配置文件中。

image-20230609170848984

第二步,进行属性注入,在 bean 标签里面进行操作

<!--set 方法注入属性 -->
<bean id="book" class="com.dkx.Book" p:name="张三"></bean>

测试代码:

public class TestSpring5 {
    @Test
    public void test(){
//        1. 加载 spring 配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
//        2. 获取配置创建的对象
        Book book = context.getBean("book", Book.class);
        book.getName();
    }
}

测试结果:

名字: 张三

# IOC 操作 Bean 管理 (xml 注入其它类型属性)

# 1. 字面量

  1. null 值

    public class Book {
    //    创建属性
        private String uame;
        private String address;
    //    创建属性对应的 set 方法
        public void setName(String uame) {
            this.uame = uame;
        }
        public void setAddress(String address) {
            this.address = address;
        }
        public void getName(){
            System.out.println("名字: "+uame+"地址: "+address);
        }
    }
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--set 方法注入属性 -->
        <bean id="book" class="com.dkx.Book" p:name="张三">
            <property name="address">
                <null/>
            </property>
        </bean>
    </beans>

    测试代码:

    public class TestSpring5 {
        @Test
        public void test(){
    //        1. 加载 spring 配置文件
            ApplicationContext context = new ClassPathXmlApplicationContext
                    ("application.xml");
    //        2. 获取配置创建的对象
            Book book = context.getBean("book", Book.class);
            book.getName();
        }
    }

    测试结果:

    名字: 张三地址: null
    
  2. 属性值包含特殊符号

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--set 方法注入属性 -->
        <!-- 属性值包含特殊符号
            1. 把 & lt;> 进行转义
            2. 把带特殊符号内容写到 xml 的 CDATA 语法中
        -->
        <bean id="book" class="com.dkx.Book" p:name="张三">
            <property name="address">
                <value><![CDATA[<<南京>>]]></value>
            </property>
        </bean>
    </beans>

    测试结果:

    名字: 张三地址: <<南京>>
    

# 2. 注入属性 - 外部 Bean

  1. 创建两个类 service 类和 dao 类

    image-20230609195756054

  2. 在 service 调用 dao 里面的方法

    • service
    public class UserService {
        private UserDao userDao;
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
        public void add(){
            userDao.update();
            System.out.println("service add ...");
        }
    }
    • dao
    public interface UserDao {
        void update();
    }
    • daoImpl
    public class UserDaoImpl implements UserDao {
        @Override
        public void update(){
            System.out.println("Dao update ...");
        }
    }
  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"
           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">
        <bean id="userDao" class="com.dkx.dao.impl.UserDaoImpl"></bean>
        <!--
            name 属性:类里面 set 方法去掉 set 首字母小写的名称 setUserDao -> userDao
            ref 属性:创建 userDao 对象 bean 标签 id 值
        -->
        <bean id="userService" class="com.dkx.service.UserService">
            <property name="userDao" ref="userDao"></property>
        </bean>
    </beans>

    测试代码:

    public class TestSpring5 {
        @Test
        public void test(){
    //        1. 加载 spring 配置文件
            ApplicationContext context = new ClassPathXmlApplicationContext
                    ("application.xml");
    //        2. 获取配置创建的对象
            UserService service = context.getBean("userService", UserService.class);
            service.add();
        }
    }

    测试结果:

    Dao update ...
    service add ...
    

# 3. 注入属性 - 外部 Bean

  1. 一对多关系:部分和员工

一个部门有多个员工,一个员工属于一个部门

部门是一,员工是多

  1. 在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
/**
 * 部门类
 */
public class Dept {
    private String dname;
    public void setDname(String dname) {
        this.dname = dname;
    }
    @Override
    public String toString() {
        return dname;
    }
}
/**
 * 员工类
 */
public class Emp {
    private String  ename;
    private String gender;
//    员工属于一个部门,使用对象形式表示
    private Dept dept;
    public void setDept(Dept dept) {
        this.dept = dept;
    }
    public void setEname(String ename) {
        this.ename = ename;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public void getOut(){
        System.out.println("名称: "+ename+", 性别: "+gender+", 部门: "+dept);
    }
}
  1. 在 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"
       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">
    <bean id="emp" class="com.dkx.bean.Emp" p:ename="张三" p:gender="">
        <property name="dept">
            <bean id="dept" class="com.dkx.bean.Dept" p:dname="程序员"></bean>
        </property>
    </bean>
</beans>

测试代码:

public class TestSpring5 {
    @Test
    public void test(){
//        1. 加载 spring 配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
//        2. 获取配置创建的对象
        Emp emp = context.getBean("emp", Emp.class);
        emp.getOut();
    }
}

测试结果:

名称: 张三, 性别: 男, 部门: 程序员

# 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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="emp" class="com.dkx.bean.Emp" p:ename="张三" p:gender="">
        <property name="dept" ref="dept"></property>
    </bean>
    <bean id="dept" class="com.dkx.bean.Dept" p:dname="程序员"></bean>
</beans>

第二种写法:

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

生成 Dept 的 get 方法

/**
 * 员工类
 */
public class Emp {
    private String  ename;
    private String gender;
//    员工属于一个部门,使用对象形式表示
    private Dept dept;
    public Dept getDept() {
        return dept;
    }
    public void setDept(Dept dept) {
        this.dept = dept;
    }
    public void setEname(String ename) {
        this.ename = ename;
    }
    public void setGender(String gender) {
        this.gender = gender;
    }
    public void getOut(){
        System.out.println("名称: "+ename+", 性别: "+gender+", 部门: "+dept);
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="emp" class="com.dkx.bean.Emp" p:ename="张三" p:gender="">
        <!-- 需要依赖注入 dept 不能省略否则会报错 -->
        <property name="dept" ref="dept"></property>
        <!-- 注意: 需要在 emp 中生成 dept 的 get 方法否则无法调用 -->
        <!-- 通过 emp 中的 getDept 获取 dept 对象调用 dname 并 value 赋值 -->
        <property name="dept.dname" value="程序员"></property>
    </bean>
    <bean id="dept" class="com.dkx.bean.Dept"></bean>
</beans>

测试代码:

public class TestSpring5 {
    @Test
    public void test(){
//        1. 加载 spring 配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
//        2. 获取配置创建的对象
        Emp emp = context.getBean("emp", Emp.class);
        emp.getOut();
    }
}

测试结果:

名称: 张三, 性别: 男, 部门: 程序员

# IOC 操作 Bean 管理 (xml 注入集合属性)

# 1. 注入数组类型属性

# 2. 注入 List 集合类型属性

# 3. 注入 Map 集合

  1. 创建类,定义数组,List,Map,Set 类型属性,并且生成对应的 Set 方法
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Stu {
//    数组类型属性
    private String[] courses;
//    List 集合类型属性
    private List<String> list;
//    Map 集合类型属性
    private Map<String,String> map;
//    Set 集合类型属性
    private Set<String> set;
    public void setCourses(String[] courses) {
        this.courses = courses;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public void setSet(Set<String> set) {
        this.set = set;
    }
    public void getOut(){
        System.out.println("courses: "+ Arrays.toString(courses));
        System.out.println("list: "+list);
        System.out.println("map: "+map);
        System.out.println("set: "+set);
    }
}
  1. 在 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"
       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">
    <bean id="stu" class="com.dkx.Stu">
        <!-- 数组类型属性注入 -->
        <property name="courses">
            <array>
                <value>Java课程</value>
                <value>数据库课程</value>
            </array>
        </property>
        <!--List 集合属性注入 -->
        <property name="list">
            <list>
                <value>list-张三</value>
                <value>list-李四</value>
                <value>list-刘桑</value>
            </list>
        </property>
        <!--Map 集合属性注入 -->
        <property name="map">
            <map>
                <entry key="第一名" value="刘桑"></entry>
                <entry key="第二名" value="张三"></entry>
                <entry key="第三名" value="李四"></entry>
            </map>
        </property>
        <!--Set 集合属性注入 -->
        <property name="set">
            <set>
                <value>set-张三</value>
                <value>set-李四</value>
                <value>set-刘桑</value>
            </set>
        </property>
    </bean>
</beans>

3. 测试代码:

public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
        Stu s = context.getBean("stu", Stu.class);
        s.getOut();
    }
}

测试结果:

courses: [Java课程, 数据库课程]
list: [list-张三, list-李四, list-刘桑]
map: {第一名=刘桑, 第二名=张三, 第三名=李四}
set: [set-张三, set-李四, set-刘桑]

# 4. 在集合中设置对象类型值

  1. 创建一个新的类
/**
 * 课程类
 */
public class Course {
    private String cname;
    public void setCname(String cname) {
        this.cname = cname;
    }
    @Override
    public String toString(){
        return cname;
    }
}
  1. 添加一个值类型是对象的 List 集合
public class Stu {
//    数组类型属性
    private String[] courses;
//    List 集合类型属性
    private List<String> list;
//    Map 集合类型属性
    private Map<String,String> map;
//    Set 集合类型属性
    private Set<String> set;
//    对象集合类型属性
    private List<Course> courseList;
    public void setCourses(String[] courses) {
        this.courses = courses;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public void setSet(Set<String> set) {
        this.set = set;
    }
    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }
    public void getOut(){
        System.out.println("courses: "+ Arrays.toString(courses));
        System.out.println("list: "+list);
        System.out.println("map: "+map);
        System.out.println("set: "+set);
        System.out.println("list-course: "+courseList);
    }
}
  1. 在 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"
       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">
    <bean id="stu" class="com.dkx.Stu">
        <!-- 数组类型属性注入 -->
        <property name="courses">
            <array>
                <value>Java课程</value>
                <value>数据库课程</value>
            </array>
        </property>
        <!--List 集合属性注入 -->
        <property name="list">
            <list>
                <value>list-张三</value>
                <value>list-李四</value>
                <value>list-刘桑</value>
            </list>
        </property>
        <!--Map 集合属性注入 -->
        <property name="map">
            <map>
                <entry key="第一名" value="刘桑"></entry>
                <entry key="第二名" value="张三"></entry>
                <entry key="第三名" value="李四"></entry>
            </map>
        </property>
        <!--Set 集合属性注入 -->
        <property name="set">
            <set>
                <value>set-张三</value>
                <value>set-李四</value>
                <value>set-刘桑</value>
            </set>
        </property>
        <!-- 注入 List 集合类型,值是对象 -->
        <property name="courseList">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
                <ref bean="course3"></ref>
            </list>
        </property>
    </bean>
    <bean id="course1" class="com.dkx.Course" p:cname="学生A"></bean>
    <bean id="course2" class="com.dkx.Course" p:cname="学生B"></bean>
    <bean id="course3" class="com.dkx.Course" p:cname="学生C"></bean>
</beans>
  1. 测试代码:

    public class AppTest {
        @Test
        public void test(){
            ApplicationContext context = new ClassPathXmlApplicationContext
                    ("application.xml");
            Stu s = context.getBean("stu", Stu.class);
            s.getOut();
        }
    }

    测试结果:

    courses: [Java课程, 数据库课程]
    list: [list-张三, list-李四, list-刘桑]
    map: {第一名=刘桑, 第二名=张三, 第三名=李四}
    set: [set-张三, set-李四, set-刘桑]
    list-course: [学生A, 学生B, 学生C]
    

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

  1. 创建 Book 类
public class Book {
    private List<String> list;
    public void setList(List<String> list) {
        this.list = list;
    }
    public void getOut(){
        System.out.println(list);
    }
}
  1. 在 Spring 配置文件中引入名称空间:util 不是 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:p="http://www.springframework.org/schema/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">
    <!-- 提取 List 集合类型属性注入 -->
    <util:list id="bookList">
        <value>红楼梦</value>
        <value>山海经</value>
        <value>西游记</value>
    </util:list>
    <!-- 提取 list 集合类型属性注入使用 -->
    <bean id="book" class="com.dkx.Book">
        <!--name 对应 set 方法 -->
        <property name="list" ref="bookList"></property>
    </bean>
</beans>
  1. 测试代码:
public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application1.xml");
        Book book = context.getBean("book", Book.class);
        book.getOut();
    }
}

测试结果:

[红楼梦, 山海经, 西游记]

# IOC 操作 Bean 管理 (FactoryBean)

# 1.Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean (FactoryBean)

  1. 普通 bean:在配置文件中定义 bean 类型就是返回类型
<bean id="book" class="com.dkx.Book"></bean>
public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application1.xml");
        Book book = context.getBean("book", Book.class);
    }
}
  1. 工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样

    1. 第一步:创建类,让这个类作为工厂 bean,实现接口 FactoryBean

      import com.dkx.Course;
      import org.springframework.beans.factory.FactoryBean;
      public class MyBean implements FactoryBean<Course> {
         
      }
    2. 第二步:实现接口里面的方法,在实现的方法中定义返回的 bean 类型

      import com.dkx.Course;
      import org.springframework.beans.factory.FactoryBean;
      public class MyBean implements FactoryBean<Course> {
      //    定义返回 Bean
          @Override
          public Course getObject() throws Exception {
              Course c = new Course();
              c.setCname("张三");
              return c;
          }
          @Override
          public Class<?> getObjectType() {
              return null;
          }
          @Override
          public boolean isSingleton() {
              return FactoryBean.super.isSingleton();
          }
      }
    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"
             xmlns:p="http://www.springframework.org/schema/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">
          <bean id="myBean" class="com.dkx.factorybean.MyBean"></bean>
      </beans>
    4. 测试代码:

      public class AppTest {
          @Test
          public void test(){
              ApplicationContext context = new ClassPathXmlApplicationContext
                      ("application2.xml");
              Course myBean = context.getBean("myBean", Course.class);
              System.out.println(myBean);
          }
      }

      测试结果:

      张三
      

# IOC 操作 Bean 管理 (bean 作用域)

  1. 在 Spring 里面,设置创建 bean 实例是单实例还是多实例

  2. 在 Spring 里面,默认情况下,bean 是单实例对象

    <bean id="book" class="com.dkx.Book"></bean>
    public class AppTest {
        @Test
        public void test(){
            ApplicationContext context = new ClassPathXmlApplicationContext
                    ("application1.xml");
            Book book = context.getBean("book", Book.class);
            Book book1 = context.getBean("book",Book.class);
            System.out.println(book);
            System.out.println(book1);
        }
    }

    结果:两个对象是相同的。

    com.dkx.Book@fe18270
    com.dkx.Book@fe18270
    
  3. 如何设置单实例还是多实例

    1. 在 Spring 配置文件 bean 标签里面有属性用于设置单实例还是多实例
    2. scope 属性值
      1. 默认值:singleton,表示单实例对象
      2. 可选值:prototype,表示多实例对象

    将配置设置为多实例对象:

    <bean id="book" class="com.dkx.Book" scope="prototype"></bean>

    测试结果:不是同一个对象了

    com.dkx.Book@2fd66ad3
    com.dkx.Book@5d11346a
    
    1. singleton 和 prototype 区别:

      1. singleton 单实例,prototype 多实例
      2. 设置 scope 值是 singleton 时候,加载 spring 配置文件时候 ClassPathXmlApplicationContext ("application1.xml"); 就会创建单实例对象
      3. 设置 scope 值是 prototype 时候,不是在加载 spring 配置文件时候创建对象,在调用 getBean 方法时候创建多实例对象
      ApplicationContext context = new ClassPathXmlApplicationContext("application1.xml");
      // 到 getBean 的时候才会创建对象所以每次获取的时候都是不同的对象
      Book book = context.getBean("book", Book.class);

# IOC 操作 Bean 管理 (bean 生命周期)

  1. 生命周期
    1. 从对象创建到对象销毁的过程
  2. Bean 生命周期
    1. 通过构造器创建 Bean 实例 (无参构造)
    2. 为 Bean 的属性设置值和其它 Bean 引用 (调用 set 方法)
    3. 调用 Bean 的初始化的方法 (需要进行配置初始化的方法)
    4. Bean 可以使用了 (对象获取到了)
    5. 当容器关闭时候,调用 Bean 的销毁的方法 (需要进行配置销毁的方法)
  3. 演示 Bean 生命周期
public class Orders {
    private String oname;
    public Orders(){
        System.out.println("第一步 Orders 无参构造执行了...");
    }
    public void setOname(String oname) {
        this.oname = oname;
        System.out.println("第二步 Orders set方法执行了...");
    }
//    创建初始化执行的方法
    public void initMethod(){
        System.out.println("第三步 Orders initMethod初始化方法执行了...");
    }
//    创建执行的销毁的方法
    public void destroyMethod(){
        System.out.println("第五步 Orders destroyMethod销毁方法执行了...");
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="orders" class="com.dkx.bean.Orders" p:oname="手机" init-method="initMethod" destroy-method="destroyMethod"></bean>
</beans>

测试代码:

public class AppTest {
    @Test
    public void test(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext
                ("application3.xml");
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println("第四步 获取创建bean实例对象:=> "+orders);
//        手动让 Bean 实例销毁
        context.close();
    }
}

测试结果:

第一步 Orders 无参构造执行了...
第二步 Orders set方法执行了...
第三步 Orders initMethod初始化方法执行了...
第四步 获取创建bean实例对象:=> com.dkx.bean.Orders@8e24743
第五步 Orders destroyMethod销毁方法执行了...
  1. Bean 的后置处理器,加载后置处理器 Bean 生命周期共有 7 步操作

    1. 通过构造器创建 Bean 实例 (无参构造)
    2. 为 Bean 的属性设置值和其它 Bean 引用 (调用 set 方法)
    3. <font style="color:red"> 把 Bean 实例传递 Bean 后置处理器的方法 </font>.
      • 初始化前会执行:postProcessBeforeInitialization 方法
    4. 调用 Bean 的初始化的方法 (需要进行配置初始化的方法)
    5. <font style="color:red"> 把 Bean 实例传递 Bean 后置处理器的方法 </font>.
      • 初始化后会执行:postProcessAfterInitialization 方法
    6. Bean 可以使用了 (对象获取到了)
    7. 当容器关闭时候,调用 Bean 的销毁的方法 (需要进行配置销毁的方法)
  2. 演示添加后置处理器效果

    1. 创建类,实现接口 BeanPostProcessor,创建后置处理器

      public class MyBeanPost implements BeanPostProcessor {
          @Override
          public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              System.out.println("在初始化之前执行的方法");
              return bean;
          }
          @Override
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              System.out.println("在初始化后执行的方法");
              return bean;
          }
      }
    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"
             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">
          <bean id="orders" class="com.dkx.bean.Orders" p:oname="手机" init-method="initMethod" destroy-method="destroyMethod"></bean>
          <!-- 配置后置处理器 -->
          <bean id="myBeanPost" class="com.dkx.bean.MyBeanPost"></bean>
      </beans>
    3. 测试代码:

      public class AppTest {
          @Test
          public void test(){
              ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext
                      ("application3.xml");
              Orders orders = context.getBean("orders", Orders.class);
              System.out.println("第四步 获取创建bean实例对象:=> "+orders);
      //        手动让 Bean 实例销毁
              context.close();
          }
      }

      测试结果:

      第一步 Orders 无参构造执行了...
      第二步 Orders set方法执行了...
      在初始化之前执行的方法
      第三步 Orders initMethod初始化方法执行了...
      在初始化后执行的方法
      第四步 获取创建bean实例对象:=> com.dkx.bean.Orders@43738a82
      第五步 Orders destroyMethod销毁方法执行了...
      

# IOC 操作 Bean 管理 (xml 自动装配)

1. 什么是自动装配

  1. 根据指定装配规则 (属性名称或属性类型),Spring 自动将匹配的属性值进行注入

2. 演示自动装配过程

  1. 根据属性名称自动装配
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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">
    <!--
		实现自动装配
 		bean 标签属性 autowire,配置自动装配
		autowire 属性常用两个值:
			byName:根据属性名称注入,注入值 bean 的 id 值和类属性名称一样
			byType:根据属性类型注入
     -->
    <bean id="emp" class="com.dkx.autowire.Emp" autowire="byName"></bean>
    <bean id="dept" class="com.dkx.autowire.Dept"></bean>
</beans>
  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"
       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">
   <!--
		实现自动装配
 		bean 标签属性 autowire,配置自动装配
		autowire 属性常用两个值:
			byName:根据属性名称注入,注入值 bean 的 id 值和类属性名称一样
			byType:根据属性类型注入
     -->
    <bean id="emp" class="com.dkx.autowire.Emp" autowire="byType"></bean>
    <bean id="dept" class="com.dkx.autowire.Dept"></bean>
    <!-- 根据类型注入当有两个同样类型就会报错 -->
    <bean id="dept1" class="com.dkx.autowire.Dept"></bean>
</beans>

# IOC 操作 Bean 管理 (外部属性文件)

1. 直接配置数据库信息

  1. 引入德鲁伊连接池依赖 jar 包

    image-20230610204426396

  2. 配置德鲁伊连接池

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置连接池 -->
    <!--DruidDataSource druid = new DruidDataSource();-->
    <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
        <!--set 方法注入 druid.setDriverClassName ("com.mysql.cj.jdbc.Driver");-->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&amp;serverTimezone=UTC&amp;useUnicode=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="dkx"></property>
    </bean>
</beans>

2. 引入外部属性文件配置数据库连接池

  1. 创建外部属性文件,properties 格式文件,写数据库信息

    jdbc.driverClass=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&serverTimezone=UTC&useUnicde=true
    jdbc.username=root
    jdbc.password=dkx
  2. 把外部 properties 属性文件引入到 Spring 配置文件中

    引入 context 名称空间

    <?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>

    在 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"
           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"/>
        <!-- 配置连接池 -->
        <!--DruidDataSource druid = new DruidDataSource();-->
        <bean id="druid" class="com.alibaba.druid.pool.DruidDataSource">
            <!--set 方法注入 druid.setDriverClassName ("com.mysql.cj.jdbc.Driver");-->
            <property name="driverClassName" value="${jdbc.driverClass}"></property>
            <property name="url" value="${jdbc.url}"></property>
            <property name="username" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>
    </beans>

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

# 1. 什么是注解

  1. 注解是代码特殊标记,格式:@注解名称 (属性名称 = 属性值,属性名称 = 属性值)
  2. 使用注解,注解作用在类上面,方法上面,属性上面
  3. 使用注解目的:简化 xml 配置

# 2.Spring 针对 Bean 管理中创建对象提供注解

  1. @Component
  2. @Service
  3. @Controller
  4. @Repository

上面四个注解功能是一样的,都可以用来创建 Bean 实例,但是不同的注解代表不同的含义

# 3. 基于注解方式实现对象创建

  1. 第一步 引入依赖

image-20230610213635945

image-20230610213753487

  1. 第二步 开启组件扫描

    1. 1 使用 context 名称空间,引入外部属性
    <?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>
    <?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">
        <!--
            开启组件扫描
            1. 如果扫描多个包,多个包之间使用逗号隔开,如下:
            com.dkx.dao,com.dkx.service
            2. 直接扫描它们两个的父级目录,如下 (不建议因为会扫描我们并不想扫描的东西):
            com.dkx
        -->
        <context:component-scan base-package="com.dkx.dao,com.dkx.service"></context:component-scan>
    </beans>
  2. 第三步 创建类,在类上面添加创建对象注解

    /**
     * 在注解里面 value 属性值可以省略不写
     * 默认值是类名称,首字母小写 UserService -> userService
     */
    @Component(value = "userService") //<bean id="userService" class="..">
    public class UserService {
        public void add(){
            System.out.println("service add ... ");
        }
    }
  3. 测试代码:

    public class AppTest {
    @Test
    public void test(){
          ApplicationContext context = new ClassPathXmlApplicationContext
             ("application.xml");
          UserService service = context.getBean("userService", UserService.class);
          service.add();
    }

    测试结果:

    service add ... 
    
  4. 过程解释:Spring 配置扫描,扫描指定的包路径,找到被扫描到的注解后将该对象进行实例 Bean 管理然后就可以通过 getBean 来获取 IOC 容器中的对象,然后获得对象后调用方法

  5. <font style="color:red"> 开启组件扫描细节配置 </font>.

    • use-default-filters="false" 不扫描所有配置,如果为 true 则扫描全部但是可以排除使用 exclude

    • include:包含哪些扫描配置

    • exclude:不包含哪些扫描配置

    <!--
            use-default-filters="false" 表示现在不使用默认 filters,自己配置 filter
            context:include-filter: 设置扫描哪些内容
        -->
    <context:component-scan base-package="com.dkx.dao,com.dkx.service" use-default-filters="false">
       <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

# 4. 基于注解方式实现属性注入

# 1.@Autowired

  • 根据属性类型进行自动装配
  1. 第一步 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象注解
/**
 * dao 接口
 */
public interface UserDao {
    public void add();
}
/**
 * dao 实现类
 */
@Repository
public class UserDaoImpl implements UserDao{
    public void add(){
        System.out.println("UserDao add 执行了...");
    }
}
/**
 * service 类
 * 在注解里面 value 属性值可以省略不写
 * 默认值是类名称,首字母小写 UserService -> userService
 */
@SuppressWarnings("all")
@Component(value = "userService") //<bean id="userService" class="..">
public class UserService {
    public void add(){
        System.out.println("service add ... ");
    }
}
  1. 第二步 把 service 注入 dao 对象,在 service 类添加 dao 类属性,在属性上面使用注解
/**
 * 在注解里面 value 属性值可以省略不写
 * 默认值是类名称,首字母小写 UserService -> userService
 */
@SuppressWarnings("all")
@Component(value = "userService") //<bean id="userService" class="..">
public class UserService {
    // 定义 dao 类型属性
    // 不需要添加 Set 方法,@Autowired 底层已经帮我们实现了
    // 添加注入属性注解
    @Autowired
    private UserDao userDao;
    public void add(){
        System.out.println("service add ... ");
        userDao.add();
    }
}
  1. 测试代码:
public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
        UserService service = context.getBean("userService", UserService.class);
        service.add();
    }
}

测试结果:

service add ... 
UserDao add 执行了...

# XML 方式

/**
 * 在注解里面 value 属性值可以省略不写
 * 默认值是类名称,首字母小写 UserService -> userService
 */
@SuppressWarnings("all")
@Component //<bean id="userService" class="..">
public class UserService {
   private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void add(){
        System.out.println("service add ... ");
        userDao.add();
    }
}
// 指定创建对象注解的名称
@Repository
public class UserDaoImpl implements UserDao {
    public void add(){
        System.out.println("UserDao add 执行了...");
    }
}
<?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">
    <!--
        use-default-filters="false" 表示现在不使用默认 filters,自己配置 filter
        context:include-filter: 设置扫描哪些内容
    -->
    <context:component-scan base-package="com.dkx.dao,com.dkx.service" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
    <bean id="service" class="com.dkx.service.UserService" autowire="byType"></bean>
    <!-- 因为上面扫描注解已经创建了 Bean 了不需要再配置 Bean 了否则是多个 Bean 按类型注入会报错 -->
<!--    <bean id="userDao" class="com.dkx.dao.impl.UserDaoImpl"></bean>-->
</beans>

测试代码:

public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
        UserService service = context.getBean("service", UserService.class);
        service.add();
    }
}

测试结果:

service add ... 
UserDao add 执行了...

# 2.@Qualifier

  • 根据属性名称进行注入
  • 这个 @Qualifier 注解的使用需要和上面的 @Autowired 一起使用
  • 解决的场景:一个接口可以有多个实现类,如果按照类型注入则会不知道具体注入哪个实现类导致报错,在 Dao 实现类的 @Repository 创建对象注解中进行添加该 Bean 的名称比如:@Repository (value = "名称")
// 指定创建对象注解的名称
@Repository(value = "userDaoImpl")
public class UserDaoImpl implements UserDao{
    public void add(){
        System.out.println("UserDao add 执行了...");
    }
}
/**
 * 在注解里面 value 属性值可以省略不写
 * 默认值是类名称,首字母小写 UserService -> userService
 */
@SuppressWarnings("all")
@Component(value = "userService") //<bean id="userService" class="..">
public class UserService {
    // 定义 dao 类型属性
    // 不需要添加 Set 方法,@Autowired 底层已经帮我们实现了
    // 添加注入属性注解
    @Autowired
    // 根据名称进行注入,需要配合 Autowired 使用
    @Qualifier(value = "userDaoImpl")
    private UserDao userDao;
    public void add(){
        System.out.println("service add ... ");
        userDao.add();
    }
}

测试代码:

public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
        UserService service = context.getBean("userService", UserService.class);
        service.add();
    }
}

测试结果:

service add ... 
UserDao add 执行了...

# XML 方式

/**
 * 在注解里面 value 属性值可以省略不写
 * 默认值是类名称,首字母小写 UserService -> userService
 */
@SuppressWarnings("all")
@Component //<bean id="userService" class="..">
public class UserService {
   private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void add(){
        System.out.println("service add ... ");
        userDao.add();
    }
}
// 指定创建对象注解的名称
@Repository
public class UserDaoImpl implements UserDao {
    public void add(){
        System.out.println("UserDao add 执行了...");
    }
}
<?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">
    <!--
        use-default-filters="false" 表示现在不使用默认 filters,自己配置 filter
        context:include-filter: 设置扫描哪些内容
    -->
    <context:component-scan base-package="com.dkx.dao,com.dkx.service" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
    <bean id="service" class="com.dkx.service.UserService" autowire="byName"></bean>
    <!-- 必须要配置一个需要注入的 bean 因为按照配置的 bean 来找的 -->
    <bean id="userDao" class="com.dkx.dao.impl.UserDaoImpl"></bean>
    <!-- 配置多个同样 bean 不会报错,不配置则报错空指针 -->
    <bean id="userDao1" class="com.dkx.dao.impl.UserDaoImpl"></bean>
</beans>

测试代码:

public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
        UserService service = context.getBean("service", UserService.class);
        service.add();
    }
}

测试结果:

service add ... 
UserDao add 执行了...

# 3.@Resource

  • 可以根据类型注入,可以根据名称注入
  • 在不指定名称 name 属性的情况下就是按类型注入,指定了 name 属性则按名称注入
  • 需要注意:@Resource 包:javax.annotation.Resource ,是 Java 扩展包中的而不是 Spring 中的 Spring 官方建议还是使用 @Autowired 和 @Qualifier 来进行注入。
/**
 * 在注解里面 value 属性值可以省略不写
 * 默认值是类名称,首字母小写 UserService -> userService
 */
@SuppressWarnings("all")
@Component(value = "userService") //<bean id="userService" class="..">
public class UserService {
    // 根据类型注入
//    @Resource
    // 根据名称注入
    @Resource(name = "userDaoImpl")
    private UserDao userDao;
    public void add(){
        System.out.println("service add ... ");
        userDao.add();
    }
}

测试代码:

public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
        UserService service = context.getBean("userService", UserService.class);
        service.add();
    }
}

测试结果:

service add ... 
UserDao add 执行了...

# 4.@Value

  • 注入普通类型属性
/**
 * 在注解里面 value 属性值可以省略不写
 * 默认值是类名称,首字母小写 UserService -> userService
 */
@SuppressWarnings("all")
@Component(value = "userService") //<bean id="userService" class="..">
public class UserService {
    // 普通类型注入
    @Value(value = "张三")
    private String name;
    public void add(){
        System.out.println("service add ... "+name);
    }
}

测试代码:

public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
        UserService service = context.getBean("userService", UserService.class);
        service.add();
    }
}

测试结果:

service add ... 张三

# XML 方式

/**
 * 在注解里面 value 属性值可以省略不写
 * 默认值是类名称,首字母小写 UserService -> userService
 */
@SuppressWarnings("all")
@Component //<bean id="userService" class="..">
public class UserService {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    public void add(){
        System.out.println("service add ... "+name);
    }
}
<?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
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <!--
        use-default-filters="false" 表示现在不使用默认 filters,自己配置 filter
        context:include-filter: 设置扫描哪些内容
    -->
    <context:component-scan base-package="com.dkx.dao,com.dkx.service" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
    <bean id="service" class="com.dkx.service.UserService" p:name="张三"></bean>
    <!-- 或者 -->
    <bean id="service" class="com.dkx.service.UserService">
        <property name="name" value="李四"/>
    </bean>
</beans>

测试代码:

public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext
                ("application.xml");
        UserService service = context.getBean("service", UserService.class);
        service.add();
    }
}

测试结果:

service add ... 李四

# 6. 完全注解开发

0. 将 xml 配置文件删除或者.back 掉

image-20230611024902517

1. 创建配置类,替代 xml 配置文件

@Configuration // 作为配置类,替代 xml 配置文件
@ComponentScan(basePackages = {"com.dkx.dao","com.dkx.service"}) // 扫描配置类
public class SpringConfig {
}

2.service 类

/**
 * 在注解里面 value 属性值可以省略不写
 * 默认值是类名称,首字母小写 UserService -> userService
 */
@SuppressWarnings("all")
@Component(value = "userService") //<bean id="userService" class="..">
public class UserService {
    @Autowired
    @Qualifier(value = "userDaoImpl")
    private UserDao userDao;
    public void add(){
        System.out.println("service add ... ");
        userDao.add();
    }
}

3.dao 接口和实现类

/**
 * dao 接口
 */
public interface UserDao {
    public void add();
}
/**
 * dao 实现类
 */
// 指定创建对象注解的名称
@Repository(value = "userDaoImpl")
public class UserDaoImpl implements UserDao {
    public void add(){
        System.out.println("UserDao add 执行了...");
    }
}

4. 测试代码:

public class AppTest {
    @Test
    public void test(){
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService service = context.getBean("userService", UserService.class);
        service.add();
    }
}

测试结果:

service add ... 
UserDao add 执行了...