IOC容器(一)

IOC底层原理

  控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理。使用IOC目的:降低耦合度
底层原理:
xml解析工厂模式反射
我们先来看看关联两个类最直接的实现方式是怎样的:

public class UserService {
     
    public void execute(){
     
        UserDao userDao = new UserDao();
        userDao.add();
    }
}
class UserDao{
     
    public  void add(){
     
        //这里是方法体部分
    }
}

说明:通过在UserService 类当中new一个关于UserDao的对象,并且调用其方法,很明显这种方式是可以实现关联的,但是这两个类之间的耦合度太高,当UserDao内部代码修改之后,UserService相应的调用也需要修改。
接下来使用工厂模式进行解耦操作:

public class UserService {
     
    public void execute(){
     
       //UserDao userDao = new UserDao();
       //userDao.add();
       UserDao userDao = UserFactory.getDao();
       userDao.add();
    }
}
class UserDao{
     
    public  void add(){
     
        //这里是方法体部分
    }
}
class UserFactory{
     
    public static UserDao getDao(){
     
        return  new UserDao();
    }
}

说明:对于工厂设计模式来说,对象的new操作不需要自己直接来进行,只需要跟第三方的Fantory进行交涉就行了。工厂设计模式确实是降低耦合度的一种方式,但并不是最好的一种方式,那么下面就需要介绍IOC解耦过程了。
IOC解耦过程:
第一步:xml配置文件,配置创建的对象

<bean id="user" class="com.spring.User"></bean>
//这个class字段内容是你的项目种User类的路径(包名.类名)

第二步:有UserService类和UserDao类,同样创建一个工厂类

class UserFactory{
     
    public static UserDao getDao(){
     
        //1.xml解析
        //String classValue = class属性值;
        //2.通过反射创建对象(得到相应类的字节码文件)
        //Class clazz = Class.forName(classValue);
        //return (UserDao)clazz.newInstance();
    }
}

说明:IOC可以进一步降低代码间的耦合度,将对象的创建以及对象之间的调用都交给Spring来管理。

IOC接口

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

IOC操作Bean管理(基于XML)

什么是Bean管理?
Bean管理指的是两个操作,1.Spring创建对象2.Spring注入属性
基于xml方式实现过程:
  1.在Spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建。

<bean id="user" class="com.spring.User"></bean>

bean标签里面有很多属性:
id:类的唯一标识
class:类全路径(包+类路径)
name:和id属性类似,可以加特殊符号(几乎不使用这个属性)
注意:bean标签在创建对象的时候,默认也是执行无参构造方法。

  2.基于xml方式注入属性

  • 使用set()方法来实现属性注入:
public class UserService {
     
    private  String name;
    public void setName(String name) {
     
        this.name = name;
    }
    public static void main(String[] args) {
     
        UserService userService = new UserService();
        userService.setName("张三");
    }
}

上面的过程可以使用xml配置文件的形式来实现:

 <!--对象创建-->
    <bean id="user" class="com.spring.User">
        <!-- 设置字段属性值-->
        <property name="userName" value="张三"></property>
    </bean>
  • 使用有参构造方法注入:
public class UserService {
     
    private  String name;
    public UserService(String name) {
     
        this.name = name;
    }
    public static void main(String[] args) {
     
        UserService userService = new UserService("张三");
    }
}

上面的过程可以使用xml配置文件的形式来实现:

 <bean id="user" class="com.spring.User">
       <constructor-arg name="userName" value="张三"></constructor-arg>
    </bean>

XML注入其它类型属性

  • 设置空值null
 <!--对象创建-->
    <bean id="user" class="com.spring.User">
    <!-- 设置字段属性值-->
        <property name="userName">
            <null></null>
        </property>
    </bean>
  • 设置的属性值包含特殊符号
<!-- 设置字段属性值-->
        <property name="userName">
            <value><![CDATA[<<张三>>]]></value>
        </property>
  • 注入属性-外部bean
    1.创建两个类service类和dao类
    2.在service里面调用dao里面的方法
import dao.UserDao;
public class UserService {
     
    //1.创建UserDao类型属性,生成set方法
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
     
        this.userDao = userDao;
    }

    public  void add(){
     
        System.out.println("添加方法");
        userDao.updata();
        //原始方式:new对象+调用方法
        /*UserDao userDao = new UserDaoImpl();
        userDao.updata();*/
    }
}
public class UserDaoImpl implements UserDao{
     
    @Override
    public void updata() {
     
        System.out.println("dao updata");
    }
}
<!-- 1.service和dao对象创建-->
    <bean id="userService" class="service.UserService">
        <!--注入UserDao对象
        name属性:类里面的属性名称
        ref属性:创建UserDao对象bean标签id值
        -->
        <property name="userDao" ref="userDaoImpl"></property>
    </bean>
    <bean id="userDaoImpl" class="dao.UserDaoImpl"></bean>
  • 注入属性-内部bean和级联赋值
    举例一对多的关系:学校和学生
public class School {
     
    private String sch_name;

    public void setSch_name(String sch_name) {
     
        this.sch_name = sch_name;
    }
    //重写toString()方法
    public String toString(){
     
        return sch_name;
    }
}
public class Student {
     
    //设置学生属性
    private String stu_name;
    private String stu_gender;
    private School stu_school;
    //生成每个属性对应的set方法
    public void setStu_name(String stu_name) {
     
        this.stu_name = stu_name;
    }

    public void setStu_gender(String stu_gender) {
     
        this.stu_gender = stu_gender;
    }

    public void setStu_school(School stu_school) {
     
        this.stu_school = stu_school;
    }
    //设置一个方法
    public void print(){
     
        System.out.println(stu_name+" "+stu_gender+" "+stu_school.toString());
    }
}
 <!--1.创建对象-->
    <bean id="student" class="bean.Student">
        <!-- 2.给该对象设置其属性-->
        <property name="stu_name" value="张三"></property>
        <property name="stu_gender" value="男"></property>
        <property name="stu_school">
            <bean id="school" class="bean.School">
                <property name="sch_name" value="某大学"></property>
            </bean>
        </property>
    </bean>

上面的xml配置文件也可以使用级联赋值方式:
(1)第一种方式:也即是外部bean方法

<!--1.创建对象-->
    <bean id="student" class="bean.Student">
        <!-- 2.给该对象设置其属性-->
        <property name="stu_name" value="张三"></property>
        <property name="stu_gender" value="男"></property>
        <property name="stu_school" ref="school"></property>
    </bean>
    <bean id="school" class="bean.School">
        <property name="sch_name" value="某大学"></property>
    </bean>

(2)第二种方式:

 <!--1.创建对象-->
    <bean id="student" class="bean.Student">
        <!-- 2.给该对象设置其属性-->
        <property name="stu_name" value="张三"></property>
        <property name="stu_gender" value="男"></property>
        <property name="stu_school" ref="school"></property>
        <property name="stu_school.sch_name" value="某小学"></property>
    </bean>
    <bean id="school" class="bean.School">
        <!--<property name="sch_name" value="某大学"></property>-->
    </bean>

Tips:这个似乎是有优先级内味儿了,某大学那一栏的属性值可以去掉,只需要创建school对象即可。注意哈,需要生成Student类当中属性stu_school的get方法。

  • 注入集合属性
    (1)属性为数组
    (2)属性为List集合
    (3)属性为Map集合
    (4)属性为Set集合
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Student {
     
    private  String[] names;
    private List<String> list;
    private Map<String,String> map;
    private Set<String> set;
    public void setNames(String[] names) {
     
        this.names = names;
    }
    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 print(){
     
        System.out.println(Arrays.toString(names));
        System.out.println(list);
        System.out.println(map);
        System.out.println(set);
    }
}
 <!--1.创建对象-->
    <bean id="student" class="collectiontype.Student">
        <!--2.设置属性-->
        <property name="names">
            <array>
                <value>张三</value>
                <value>李四</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>张三</value>
                <value>李四</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="张三" value="张三"></entry>
                <entry key="李四" value="李四"></entry>
            </map>
        </property>
        <property name="set">
            <set>
                <value>张三</value>
                <value>李四</value>
            </set>
        </property>
    </bean>
</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: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">
   <!-- 1.提取list集合类型属性注入-->
    <util:list id="studentList">
        <value>张三</value>
        <value>李四</value>
    </util:list>
   <!-- 2.提取list集合类型属性注入使用-->
    <bean id="student" class="collectiontype.Student">
        <property name="list" ref="studentList"></property>
    </bean>
</beans>

  Spring有两种类型的bean,一种普通bean,另外一种是工厂bean (FactoryBean)
(1)普通bean:在配置文件中定义的bean类型就是返回类型
(2)工厂bean:在配置文件中定义的bean类型可以和返回类型不一样

public class MyBean implements FactoryBean<Course> {
     
    @Override
    public Course getObject() throws Exception {
     
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean3.xml");
        Course course = context.getBean("course",Course.class);
        return  course;
    }
    @Override
    public Class<?> getObjectType() {
     
        return null;
    }
}
 <!-- 1.创建对象-->
    <bean id="mybean" class="bean.MyBean"></bean>
    <bean id="course" class="collectiontype.Course">
        <property name="course_name" value="语文"></property>
    </bean>

有关bean作用域问题:
1.在Spring框架当中,需要明确设置创建的bean实例是单实例还是多实例。默认情况下,bean是单实例对象。
2.如何设置单实例还是多实例?
  在Spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例。
scope属性值:
  默认值singleton:表示是单实例对象
  prototype:表示是多实例对象
两者的区别是啥呢:
  scope的属性值是singleton的时候,加载Spring配置文件的时候就会创建单实例对象;当scope的属性值是prototype的时候,不是在加载Spring配置文件的时候创建对象,在调用getBean方法的时候创建多实例对象。

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

xml自动装配问题
  上面讨论的有关使用value设置属性值等等的xml文件配置问题都是基于手动配置的,接下来我要讲的就是xml自动装配问题。
根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入。
bean标签属性autowire用来自动装配,autowire属性常用的两个值:
(1)byName:根据属性名称注入,要求是注入值bean的id值和类属性名称一样。
(2)byType:根据属性类型注入。

 <bean id="student" class="autowire.Student" autowire="byName">
       <!-- <property name="school_name" ref="school"></property>-->
    </bean>
    <bean id="school_name" class="autowire.School"></bean>
 <bean id="student" class="autowire.Student" autowire="byType">
       <!-- <property name="school_name" ref="school"></property>-->
    </bean>
    <bean id="school_name" class="autowire.School"></bean>

引入外部属性文件
(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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--直接配置连接池-->
    <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/userDb"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>
</beans>

(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: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"/>
    <!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driverClassName}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${username}"></property>
        <property name="password" value="${password}"></property>
    </bean>
</beans>

Tips:需要使用名称空间context


下期博客接着讲解IOC操作Bean管理(基于注解)

你可能感兴趣的:(Spring相关,spring,ioc,xml)