IOC容器

1. IOC基本概念:

  1. 控制反转(Inversion of Control,缩写为IoC
  2. 使用IOC目的是为了降低耦合度

2. IOC底层原理

  1. xml解析、工厂模式、反射

3. IOC(接口)

1. BeanFactory

IOC容器的基本实现,是Spring内部的使用接口,不提供开发人员进行使用。
区别:(加载配置文件时不创建对象,在获取对象(使用时)才创建对象)

2. ApplicationContext(一般用这种方式):

BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用。
区别:(加载配置文件时就会把配置文件对象进行创建)

3. IOC操作Bean管理

1. 什么是Bean管理

  • Spring创建对象
  • Spring注入属性

2. Spring 有两种类型的 bean

  1. 普通bean:在配置文件中定义的bean类型就是返回类型。(定义什么返回什么)

    1. 创建类,创建配置文件

      <!--创建类对象-->
      <bean id="mybean" class="com.wnaoii.spring5.factorybean.Mybean"></bean>
      
    2. 测试类测试

      public class TestDemo {
          @Test
          public void testDemo() {
              ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
              // 普通bean:创建什么类型返回什么类型
              Mybean myBean = context.getBean("mybean",Mybean.class);
              System.out.println(myBean);
          }
      }
      
  2. 工厂bean(FactoryBean):在配置文件中定义的bean类型可以和返回的类型不一样(多态?)

    1. 创建类,让这个类作为工厂bean,实现接口 FactoryBean
    2. 实现接口里面的方法,在实现的方法中定义返回的bean类型

3. Bean管理的实现方式

1. 基于 xml 配置文件方式实现
  1. 创建对应的bean.xml文件中使用bean标签,标签里添加对应的属性,即可实现对象的创建。

  2. 创建对象的时候也是默认执行无参构造器完成对象创建。

  3. x 1<!--配置User对象创建-->2<bean id="user" class="com.wnaoii.User"/>
    
  4. 在Bean标签中有许多属性,这里介绍下常用属性

    • id属性:唯一标识,在bean中生成对象的别名。
    • class属性:类全路径(包类路径)
2. Bean管理 xml 方式(注入属性)
  • xml 的注入方式也是通过get/set方法注入
  1. 使用set方法注入

    1. 常规方式

      public class Book {
          // 创建属性
          private String bname;
      	// 属性对应的set方法
          public void setBname(String bname) {
              this.bname = bname;
          }
      
          public static void main(String[] args) {
              // 建对象
              Book book = new Book();
              // 注入值
              book.setBname("xiaoming");
              System.out.println(book.bname);
          }
      }
      
    2. xml配置文件方式

      • 写好xml配置文件

        <!--配置User对象创建-->
        <bean id="book" class="com.wnaoii.Book">
            <!--
            在bean标签中使用property完成属性注入
            name:类里属性的名字
            value:需要注入的值
            -->
            <property name="bname" value="xiaoming"></property>
        </bean>
        
      • 调用xml配置文件

        public class TestSpring5 {
            @Test
            public void testAdd() {
                // 1.加载spring配置文件
                ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        
                // 2.获取配置创建的对象
                Book book = context.getBean("book",Book.class); // getBean中”book“为xml配置的对象,Book.class表示转换的类型
        
                book.pringtName();
                System.out.println(book);
            }
        }
        
  2. 有参构造注入

    1. 常规方式

      public class Book {
          // 创建属性
          private String bname;
      	
          public Book() {
          }
      	// 有参构造
          public Book(String bname) {
              this.bname = bname;
          }
      
          public static void main(String[] args) {
              // 建对象,有参构造注入值
              Book book = new Book("xiaogang");
              System.out.println(book.bname);
          }
      }
      
    2. xml配置文件方式

      1. 创建类,定义属性,创建对应的有参构造器

        public class orders {
            private String oname;
            private String address;
            
        	// 无参构造不写也行?
            public orders() {
            }
        	
            // 有参构造
            public orders(String oname, String address) {
                this.oname = oname;
                this.address = address;
            }
        }
        
      2. 配置好xml配置文件里的Bean标签

        <!--
            在bean标签中使用constructor-arg完成属性注入
            name:类里属性的名字
            value:需要注入的值
        -->
        <bean id="orders" class="com.wnaoii.Orders">
            <constructor-arg name="oname" value="手机"></constructor-arg>
            <constructor-arg name="address" value="中国"></constructor-arg>
        </bean>
        
      3. 测试类中测试

        public class TestSpring5 {
            @Test
            public void testOrders() {
                // 1.加载spring配置文件
                ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        
                // 2.获取配置创建的对象
                Orders orders = context.getBean("orders", Orders.class);
        
                orders.testOrders();
                System.out.println(orders);
            }
        }
        
  3. P名称空间注入(了解)

    1. 使用 p 名称空间注入,可以简化基于 xml 配置方式
3. Bean管理 xml 方式(注入其他类型属性)
1. 字面量
  1. null 值

    • 不注入值也为属性的值也为null,写了增加程序的可读性。大概?

    • xml 配置文件中不设值添加<null/>标签

      <!--null值-->
      <property name="address">
          <null/>
      </property>
      
    • address 属性中注入的值就设置为null(空)

  2. 属性包含特殊符号

    • 两种方法:

      1. 将特殊符号进行转义&lt; &gt;,再注入。

      2. 将带特殊符号的内容写到CDATA

        <!--注入"<<上海>>"这个值-->
        <property name="address">
            <value><![CDATA[<<上海>>]]></value>
        </property>
        
4. Bean管理 xml 方式(注入外部Bean)
1. 注入属性-外部bean
  1. 创建两个类service类和dao

    1. service

      public class UserService {
      
          private UserDao userDao;
      
          public void setUserDao(UserDao userDao) {
              this.userDao = userDao;
          }
      }
      
    2. dao

      public class UserDaoImp implements UserDao{
      
          @Override
          public void update() {
              System.out.println("UserDao Update已运行!");
          }
      }
      
  2. service调用dao里面的方法

    public class UserService {
    
        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
            this.userDao = userDao;
        }
    
        public void printUserService(){
            // 调dao里的方法
            userDao.update();
            System.out.println("UserService已运行!");
        }
    }
    
  3. 在Spring配置文件中进行配置

    <!--配置User对象创建-->
    <bean id="userDao" class="com.wnaoii.dao.UserDaoImp"></bean>
    <bean id="userService" class="com.wnaoii.service.UserService">
        <!--
            注入userDao对象
            name属性:类里面属性的名称
            ref:刚创建的userDao对象的bean标签的id值
        -->
        <property name="userDao" ref="userDao"></property>
    </bean>
    
  4. 在测试类中测试

    public class TestBean {
        @Test
        public void Test(){
            // 1.加载spring配置文件
            ApplicationContext context = new ClassPathXmlApplicationContext("Bean2.xml");
            // 2.获取配置文件中创建的对象
            UserService userService = context.getBean("userService",UserService.class);
            userService.printUserService();
        }
    }
    
2. 注入属性-内部Bean
  1. 一对多关系:部门和员工

    • 一个部门包含多个员工
    • 一个员工属于一个部门
  2. 在实体类中表示一对多的关系

    • 部门类

      // 部门类
      public class Dept {
          private String dName;
      
          public void setdName(String dName) {
              this.dName = dName;
          }
      }
      
    • 员工类

      // 员工类
      public class Emp {
          private String eName;
          private String 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;
          }
      }
      
  3. 在 spring 配置文件中进行配置

    <!--员工类对象创建-->
    <bean id="emp" class="com.wnaoii.bean.Emp">
        <!--设置两个普通的属性-->
        <property name="eName" value="小明"></property>
        <property name="gender" value="男"></property>
        <!--设置对象类型的属性-->
        <property name="dept">
            <!--内部再嵌套一个对象-->
            <bean id="dept" class="com.wnaoii.bean.Dept">
                <property name="dName" value="保安部"></property>
            </bean>
        </property>
    </bean>
    
3. 注入属性-级联赋值
  • 和外部bean的区别就是在外部bean中赋值再传入

    <!--级联赋值-->
    <bean id="emp" class="com.wnaoii.bean.Emp">
        <!--设置两个普通的属性-->
        <property name="eName" value="小明"></property>
        <property name="gender" value="男"></property>
        <!--级联赋值-->
        <property name="dept" ref="dept"></property>
    </bean>
    <!--创建外部bean并赋值-->
    <bean id="dept" class="com.wnaoii.bean.Dept">
        <property name="dName" value="财务部"></property>
    </bean>
    
5.Bean管理 xml 方式(注入集合类型属性)
1. 注入数组类型属性
  • xml配置文件中创建对象

  • 使用<array>标签注入

    <bean id="创建的对象名" class="类路径">
        <property name="courses">
            <array>
                <!--填写注入的值-->
                <value>注入的值</value>
            </array>
        </property>
    </bean>
    
2. 注入 List 集合类型属性
  • 同上大同小异,List集合类型就用List标签注入

    <bean id="创建的对象名" class="类路径">
        <property name="courses">
            <list>
                <!--填写注入的值-->
                <value>注入的值</value>
            </list>
        </property>
    </bean>
    
3. 注入 Map 集合类型
  • 使用标签注入

    <bean id="创建的对象名" class="类路径">
        <property name="courses">
            <map>
                <!--填写注入的值-->
                <entry key="" value=></entry>
            </map>
        </property>
    </bean>
    
4. 在集合里面设置对象类型值

(用上再看)

5. 把集合注入部分提取出来
  • 使用util标签

    <util:list id="list1">
        <value>java</value>
        <value>python</value>
        <value>jsp</value>
    </util:list>
    
  • 创建好后直接在xml配置文件创建的对象中应用

    <bean id="student" class="com.wnaoii.spring5.collectiontype.student">
        <property name="courses" ref="list1"></property>
    </bean>
    
6. 基于注解方式实现
  1. 什么是注解

    1. 注解是代码的特殊标记,格式:@注解名称(属性名称=属性值,属性名称=属性值......)
    2. 使用注解,注解作用在类上面,方法上面,属性上面
    3. 注解的目的:简化 xml 配置
  2. Spring针对Bean管理中创建对象提供的注解

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

    以上四个注解实现的功能是一样的,都可以用来创建Bean的实例,名称只是用来区分在哪个层

  3. 基于注解的方式创建对象

    1. 引入依赖

      image-20210917001454927

    2. 开启组件扫描

      • 使用注解创建一定要配置开启扫描

      • 在 xml 配置文件中开启

        <context:component-scan base-package="com.wnaoii.spring5.testDemo"></context:component-scan>
        
      • base-package的值是扫描的包路径,扫描的包可以添加逗号隔开,也可以扫描整个包路径。

    3. 创建对象

      1. 创建一个类的开头添加注解

        @Service(value = "userServic")
        public class UserService {
        
            public void testDemo(){
                System.out.println("testDemo运行中-----");
            }
        }
        
        • value的值就相当于xml配置文件中<bean>标签里的id值
        • value的值不写默认为类名首字母小写
      2. 测试类中测试

        public class TestDemo {
            @Test
            public void testService() {
                ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        
                UserService userServic = context.getBean("userServic", UserService.class);
                
                userServic.testDemo();
                System.out.println(userServic);
            }
        }
        
  4. 基于注解的方式注入属性

    1. 常用的注入属性的注解

      • @AutoWired:根据属性类型进行自动装配

        1. 把 service 和 dao 对象创建,在 service 和 dao 类添加创建对象的注解

          • UserService

            @Repository
            public class UserService {
                public void testDemo(){
                    System.out.println("testDemo运行中-----");
                }
            }
            
          • UserDao

            @Repository
            public class UserDaoImpl implements UserDao{
                @Override
                public void add() {
                    System.out.println("add方法正在运行-----");
                }
            }
            
        2. 在 service 注入 dao 对象

          • 在 service 类添加 dao 类型的属性,在属性上面使用注解

            @Service(value = "userServic")
            @Repository
            public class UserService {
            
                // 定义dao类型属性
                // 不需要添加set方法
                // 添加注入属性注解
                @Autowired
                private UserDao userDao;
            
                public void testDemo(){
                    System.out.println("testDemo运行中-----");
                    // 调dao里的方法
                    userDao.add();
                }
            }
            
      • @Qualifier:根据属性名称进行注入

        • 这个注解得和上面的@AutoWired注解一起使用

        • @AutoWired注解根据类型注入,如果一个接口有多个实现类,@Qualifier就能指定名称注入指定的实现类

          @Service(value = "userServic")
          @Repository
          public class UserService {
          
              @Autowired
              @Qualifier(value = "注入实现类的名称")	// 根据名称注入
              private UserDao userDao;
          
              public void testDemo(){
                  System.out.println("testDemo运行中-----");
                  // 调dao里的方法
                  userDao.add();
              }
          }
          
      • @Resource:可以根据属性类型注入,也可以根据名称注入

        • 根据类型注入

          @Service(value = "userServic")
          @Repository
          public class UserService {
          	// 和@AutoWired注解使用方法一致
              @Resource
              private UserDao userDao;
          
              public void testDemo(){
                  System.out.println("testDemo运行中-----");
                  userDao.add();
              }
          }
          
        • 根据名称注入

          @Service(value = "userServic")
          @Repository
          public class UserService {
          	// 参考@Qualifier注解的使用,只不过value改为name
              @Resource(name = "userDaoImpl1")
              private UserDao userDao;
          
              public void testDemo(){
                  System.out.println("testDemo运行中-----");
                  userDao.add();
              }
          }
          
        • @Resource注解集合了@AutoWired@Qualifier注解

        • @Resource注解不是Spring官方包里的,是javax包中的,官方更推荐使用@AutoWired@Qualifier注解

      • @Value:注入普通类型属性

        • 在需要注入的地方上加上注解

          @Value(value = "小名")
          private String name;
          
        • @Value注解有点脱裤子放屁的感觉?直接赋值不香?

  5. 纯注解开发

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

      • @Configuration注解可以标识这个类为配置类
      • @ComponentScan注解代替xml配置文件的开启组件扫描
      @Configuration  // 设置为配置类,替代xml配置文件
      @ComponentScan(basePackages = {"com.wnaoii"})	// 需要扫描包的路径
      public class SpringConfig {
      }
      
    2. 编写测试类

      • AnnotationConfigApplicationContext里的值是配置类的名称
      public class TestDemo {
          @Test
          public void testService() {
              // 加载配置类
              ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
      
              UserService userServic = context.getBean("userServic", UserService.class);
              userServic.testDemo();
              System.out.println(userServic);
          }
      }
      

4. Bean 的作用域

  1. 在 Spring 里面,默认创建单实例对象。(每次获取该对象都是同一地址)

  2. 在 Spring 里面,可以设置创建bean实例是单实例还是多实例(每次获取该对象都是不同的地址,创个新的)

    1. 在 Spring 配置文件bean标签里面有属性scope用于设置单实例还是多实例

    2. scope属性值(常用值)

      • singleton(默认值):表示单实例对象,

      • prototype:表示多实例对象,

        <!--添加 scope 属性值就是一个多实例对象-->
        <bean id="mybean" class="com.wnaoii.spring5.factorybean.Mybean" scope="prototype"></bean>
        
  3. singletonprototype的区别

    • scope值为singleton时,加载spring配置文件时就会创建对象
    • scope值为prototype时,加载spring配置文件时不会创建对象,在调用 getBean 方法的时候才创建多实例对象

5. bean 生命周期

  1. 生命周期
    • 从对象创建到对象销毁的过程
  2. bean 生命周期
    1. 通过构造器创建 bean 实例(无参构造)
    2. 为 bean 的属性设置值和对其他 bean 的应用(调用 set 方法)
    3. 调用 bean 的初始化的方法(需要进行配置初始化的方法)
    4. bean 可以使用了(获取到对象)
    5. 当容器关闭的时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)

6. XML 自动装配

  1. 什么是自动装配

    • 根据指定装配额规则(属性名称或者属性类型), Spring 自动将匹配的属性进行注入
  2. 使用autowire属性实现自动装配

    <bean id="emp" class="com.wnaoii.spring5.autowire.Emp" autowire="byName">
    
  3. autowire属性常用值:

    • byName:根据属性名称注入(注入值bean的id值要和类属性的名称一致)
    • byType:根据属性类型注入
posted @ 2021-09-10 21:04  WNAOII  阅读(146)  评论(0)    收藏  举报