Spring5 学习笔记: IOC容器原理与bean管理方式详解

4 篇文章 0 订阅
3 篇文章 0 订阅

1, IOC概念和原理

1)什么是IOC?

  • 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理。
  • 使用IOC目的,为了耦合度降低。
  • 做入门案例就是IOC实现。

2)IOC底层原理

  • xml解析,工厂模式,反射

3)IOC(接口)

  • IOC思想基于IOC容器完成,IOC容器底层就是对象工厂。
  • Spring提供IOC容器实现两种方式:(两个接口)
    • BeanFactory: IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用。
      注:加载配置文件的时候不会创建对象,而在获取对象的时候才去创建对象
    • ApplicationContext:BeanFactory接口的子接口,提供更多强大的功能,一般由开发人员进行使用。
      注:加载配置文件的时候就可以创建对象

4)bean管理操作方式:

  • 基于xml配置文件方式实现
  • 基于注解方式实现

2,IOC容器-Bean管理XML方式— 注入(Injection)

2.1, 什么是注入

1,通过Spring工厂及配置文件,为所创建对象的成员变量赋值。

2.2, 为什么需要注入?

1,通过编码的方式,为成员变量进行赋值,存在耦合

public static void test6(){
         ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
         User user = ctx.getBean("User", User.class);
         //以下代码存在耦合
         user.setAge(4);
         user.setName("夏木"); 
     }

2.3, 如何进行注入【开发步骤】

  • 类为成员变量提供set, get方法
  • 配置Spring的配置文件
<bean id="User" name="U,u" class="User">
        <property name="age">
              <value>12</value>
        </property>
        <property name="name">
            <value>王八犊子</value>
        </property>
</bean>

SpringFactory

 public static void test7(){
         ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
         User user = ctx.getBean("User", User.class);

         System.out.println("user = " + user);
     }

2.4, 注入好处

1, 解耦合

3,创建对象和set的方式注入属性

3.1,针对不同类型的成员变量,在标签,需要嵌套其他标签

1) 八种基本类型:

<property name="property"></property>

2) 数组或List集合

<property name="property">
   <list>
        <value></value>或其他
   </list>
</property>

3) Set集合

<property name="proterty">            
     <set> 
      <value></value>或者<bean id="id" Class="classPath"/> 或者其他
     </set>
 </property>

4) Map集合

<property name="proterty">
   <map>
     <entry>
        <key><value> key </value></key>
             <value> value </value>
     </entry>
   </map>
</property>

5) properties类型

<property name="proterty">
     <props>
         <prop key="key1">value1</prop>
         <prop key="key2">value2</prop>
    </props>
</property>

6) 复杂JDK类型

需要程序员自定义类型转换器。。。`

7)用户自定义类型

<bean id="userDao" class="XXX.userDaoImpl"/>
                                   
<bean id="userService" class="XXX.userServiceImpl">
      <property name="userDao"><ref bean="userDao"/></property>
</bean>
 简化:
<bean id="userDao" class="XXX.userDaoImpl"/>
                                     `
<bean id="userService" class="XXX.userServiceImpl">
      <property name="userDao" ref="userDao"/>
</bean>

3.2,基于P命名空间简化

1)JDK类型注入

<bean id="XXX" class="XXX" p:name="张三"/>

2)自定义类型注入

<bean id="userDao" class="userDaoImpl"/>
<bean id="userService" class="userServiceImpl"  p:userDao-ref="userDao"/>

注意:这里只能简化八种基本类型和用户自定义类型

4,有参构造注入属性

<bean id="user" class="com.company.Spring.User">
        <constructor-arg name="name" value="小光"></constructor-arg>
        <constructor-arg name="age" value="12"></constructor-arg>
</bean>

另一种写法:

<bean id="user" class="com.company.Spring.User">
        <constructor-arg index="0" value="小光"></constructor-arg>
        <constructor-arg index="1" value="12"></constructor-arg>
</bean>

5,注入空值和特殊符号

  • 注入空值
<property name="property">
       <null/>
</property>
  • 特殊符号
    • 把特殊符号进行转义, 例如:&lt; &gt;
    • 把带特殊符号内容写到CDTAT
<property name="property"> 
     <value><![CDATA[含特殊符号的内容]]></value>
</property>

6,注入外部bean

(1)创建两个Service类和dao类
(2)在service调用dao里面的方法
(3)在spring配置文件中进行配置

在这里插入图片描述

bean1.xml文件中

<bean id="userService" class="com.company.UserService">
    <property name="userDao" ref="userDaoImpl">
    </property>
</bean>
<bean id="userDaoImpl" class="com.company.UserDaoImpl"></bean>

6,注入内部bean和级联赋值

  • 注入内部bean
    (以员工和部门为例子)
    (1)一对多关系,部门和员工
    (2)在实体类之间表示一对多关系

部门类

package com.company.test;

public class Dept {
    private String dname;
    public void setDname(String dname){
        this.dname = dname;
    }
    public String getDname() {
        return dname;
    }
}

员工类

package com.company.test;

public class Emp {
    private String ename;
    private String gender;
    private Dept dept;

    public void setDept(Dept dept) {
        this.dept = dept;
    }

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

    public void setEname(String ename) {
        this.ename = ename;
    }

      public Dept getDept() {
        return dept;
    }

    public String getEname() {
        return ename;
    }

    public String getGender() {
        return gender;
    }
}

bean.xml文件

<bean id="emp" class="com.company.test.Emp">
        <property name="ename" value="张三"></property>
        <property name="gender" value=""></property>
        <property name="dept">
            <bean id="dept" class="com.company.test.Dept">
                <property name="dname" value="保安部"></property>
            </bean>
        </property>
    </bean>
  • 级联赋值

(只需更改bean.xml文件)

<bean id="emp" class="com.company.test.Emp">
        <property name="ename" value="张三"></property>
        <property name="gender" value=""></property>
        <property name="dept" ref="dept"/>
 </bean>
 <bean id="dept" class="com.company.test.Dept">
          <property name="dname" value="保安部"></property>
 </bean>

7,工厂bean

  • Spring有两种类型bean, 一种普通bean,另为一种工厂bean(FactoryBean)
  • 普通bean:在配置文件中定义bean类型就是返回类型
  • 工厂bean: 在配置文件中定义bean类型可以与返回值类型不一样
    • 第一步创建类,让这个类作为工厂bean,实现接口FactoryBean
    • 第二步实现接口里面的方法,在实现的方法中定义返回的bean类型

8, bean的作用域

  • 在Spring里面,设置创建bean实例是默认单实例对象
  • 设置多实例对象的方法:
    • 在Spring配置文件bean标签里面有属性(scope) 用于设置单实例还是多实例
    • scope属性值 :第一个值为singleton, 表示单实例对象,第二个值为prototype,表示多实例对象
  • singleton和prototype区别
    • singleton 单实例,prototype多实例
    • 设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象
    • 设置scope值是prototype时候,不是在加载spring配置文件时候创建对象,在调用getBean方法时候创建多实例对象

9,bean的生命周期

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

1) 配置初始化方法

Student类中添加

public void initmethod(){
        System.out.println("初始化");
}

XML文件中设置init-method属性

<bean id="student" class="com.company.test.Student" init-method="initmethod"/>

2)配置销毁方法

Student类中添加

public void destorymethod(){
        System.out.println("销毁对象");
}

XML文件中设置init-method属性

<bean id="student" class="com.company.test.Student" destroy-method="destroyMethod"/>

测试

    @Test
    public void test(){
          ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("bean1.xml");
          Object obj = ctx.getBean("student", Student.class);
          System.out.println(obj.toString());

          ctx.close();
          System.out.println("对象已销毁");
   }

3)实现后置处理器
在这里插入图片描述
XML
在这里插入图片描述

10,XML实现自动装配

(该方法不常用)

配置XML文件

<!--实现自动装配
       bean标签属性autowire, 配置自动装配
       autowire属性常用两个值:
            byName根据属性名字注入,注入值bean的id值和类属性名称一样
            byType根据属性类型注入
    -->
 <bean id="emp" class="com.company.autoWrie.Emp" autowire="byName">
          <!--<property name="dept" ref="dept"></property>-->
 </bean>

Java文件

package com.company.autoWrie;

public class Emp {
    private Dept dept;

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "dept=" + dept +
                '}';
    }

    public void test(){
        System.out.println(dept);
    }
}

11,外部文件属性

  • 直接配置数据库信息
    • 配置德鲁伊连接池
    • 引入德鲁伊连接池依赖或jar包
      如图:在这里插入图片描述
      配置XML文件
 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
          <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
          <property name="url" value="jdbc:mysql://localhost:3306/StudentSystem"></property>
          <property name="username" value="root"></property>
          <property name="password" value="123456"></property>
     </bean>
  • 引入外部属性文件配置数据库连接池
    • 配置properties文件
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/StudentSystem
prop.userName=root
prop.password=123456
  • 把外部properties属性文件引入到spring配置文件中
<!--          引入外部属性文件-->
     <context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置连接池-->
          <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
               <property name="driverClassName" value="${prop.driverClass}"></property>
               <property name="url" value="${prop.url}"></property>
               <property name="username" value="${prop.userName}"></property>
               <property name="password" value="${prop.password}"></property>

          </bean>

12,基于注解方式创建对象

  • 什么是注解?

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

    • @Component
    • @Service
    • @Controller
    • @Repository
      注:上面四个注解功能是一样的,都可以用来创建bean实例,相当于<bean id="" class=""/>
  • 基于注解方式实现对象创建

    • 引入依赖
      在这里插入图片描述
    • 开启组件扫描(指定扫描的位置)
<context:component-scan base-package="com.company.autoWrie, com.company.test"></context:component-scan>

13,精准扫描位置

<!--表示在service包中扫描带Controller注解的内容-->
   <context:component-scan base-package="com.company.service" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
   </context:component-scan>
<!--表示不扫描带Controller注解的内容-->
   <context:component-scan base-package="com.company.service">
      <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
   </context:component-scan>

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

(1)@Autowired:根据属性类型进行自动装配
(2)@Qualifier:根据属性名称进行注入
(3)@Resource:既可以根据类型注入,也可以根据名称注入
(4)@Value:注入普通类型属性

  • @Autowired的使用
    通过属性名去查找对应接口,实例化该接口的实现类。
    (以web三层架构为例)

在dao类中

package com.company.dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements IUserDao{

    @Override
    public void add() {
     System.out.println("dao add...");
    }
}

在service中

package com.company.service;

import com.company.dao.IUserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    //定义dao类型属性
    //不需要添加set方法
    //添加注入属性注解

    @Autowired
    private IUserDao iUserDao;

    public void add(){
            System.out.println("service add...");
            iUserDao.add();
    }
}
  • @Qualifier的使用
    因为在接口IUserDao中可能有多个实现类UserDaoImpl,因此需要指明某一个实现类,它常常与Autowired连用。

在dao类中

package com.company.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDaoImpl")
public class UserDaoImpl implements IUserDao{

    @Override
    public void add() {
     System.out.println("dao add...");
    }
}

在service类中

package com.company.service;

import com.company.dao.IUserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserService {
    //定义dao类型属性
    //不需要添加set方法
    //添加注入属性注解

    @Autowired
    @Qualifier(value = "userDaoImpl")
    private IUserDao iUserDao;

    public void add(){
            System.out.println("service add...");
            iUserDao.add();
    }
}
  • @Resource的使用

在dao类中

package com.company.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userDaoImpl")
public class UserDaoImpl implements IUserDao{

    @Override
    public void add() {
     System.out.println("dao add...");
    }
}

在service类中
方法一:根据类型进行注入

package com.company.service;

import com.company.dao.IUserDao;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserService {
    //定义dao类型属性
    //不需要添加set方法
    //添加注入属性注解

    @Resource  //根据类型进行注入
    private IUserDao iUserDao;

    public void add(){
            System.out.println("service add...");
            iUserDao.add();
    }
}

方法二:根据名称进行注入

package com.company.service;

import com.company.dao.IUserDao;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserService {
    //定义dao类型属性
    //不需要添加set方法
    //添加注入属性注解

    @Resource(name = "userDaoImpl")  //根据名称进行注入
    private IUserDao iUserDao;

    public void add(){
            System.out.println("service add...");
            iUserDao.add();
    }
}

注意:因为Resource注解是在javax拓展包中提供的,因此不建议使用。

  • @Value的使用
package com.company.service;

import com.company.dao.IUserDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserService {

    @Value(value = "abc")
    private String name;

    //定义dao类型属性
    //不需要添加set方法
    //添加注入属性注解

    public void add(){
            System.out.println("service add...");
            System.out.println(name);//name为"abc"
    }
}

15,完全注解开发

(1)创建配置类,替代XML配置文件

@Configuration //使该类作为配置文件
@ComponentScan(basePackages = {"com.company.service"})//扫描文件
public class SpringConfig {        
}

(2)编写测试类

 @Test
 public void test2(){
        //加载配置类
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService ser = ctx.getBean("userService", UserService.class);

        System.out.println(ser);
        ser.add();
    }

注:在实际开发中,一般都是基于springboot进行注解开发。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值